Re: [PATCH v5 13/17] read-tree: show progress by default

2019-10-21 Thread Phillip Wood

Hi Stolee

On 21/10/2019 14:56, Derrick Stolee via GitGitGadget wrote:

From: Derrick Stolee 

The read-tree builtin has a --verbose option that signals to show
progress and other data while updating the index. Update this to
be on by default when stderr is a terminal window.

This will help tools like 'git sparse-checkout' to automatically
benefit from progress indicators when a user runs these commands.

Signed-off-by: Derrick Stolee 
---
  builtin/read-tree.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index ca5e655d2f..69963d83dc 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -162,6 +162,7 @@ int cmd_read_tree(int argc, const char **argv, const char 
*cmd_prefix)
opts.head_idx = -1;
opts.src_index = &the_index;
opts.dst_index = &the_index;
+   opts.verbose_update = isatty(2);


I'm slightly wary of changing the output of plumbing commands like this. 
If a script wants progress output it can already get it by passing 
--verbose. With this change a script that does not want that output now 
has to pass --no-verbose. If 'git sparse-checkout' wants progress 
indicators why not put the isatty() check there and pass the appropriate 
option to read-tree?


Best Wishes

Phillip


git_config(git_read_tree_config, NULL);
  



Re: [RFC PATCH 7/7] merge: teach --autostash option

2019-10-18 Thread Phillip Wood

Hi Denton

On 16/10/2019 18:26, Denton Liu wrote:

In rebase, one can pass the `--autostash` option to cause the worktree
to be automatically stashed before continuing with the rebase. This
option is missing in merge, however.


It might be helpful to say why this option is useful. I can see one 
might want to stash before doing `git pull` in the same way as one might 
before a rebase but what's the motivation for doing it before a normal 
merge?




Implement the `--autostash` option and corresponding `merge.autoStash`
option in merge which stashes before merging and then pops after.

Reported-by: Alban Gruin 
Signed-off-by: Denton Liu 
---
  builtin/merge.c | 13 +
  builtin/pull.c  |  9 +
  t/t5520-pull.sh |  8 
  3 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 062e911441..d1a5eaad0d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -40,6 +40,7 @@
  #include "branch.h"
  #include "commit-reach.h"
  #include "wt-status.h"
+#include "autostash.h"
  
  #define DEFAULT_TWOHEAD (1<<0)

  #define DEFAULT_OCTOPUS (1<<1)
@@ -58,6 +59,8 @@ static const char * const builtin_merge_usage[] = {
NULL
  };
  
+static GIT_PATH_FUNC(merge_autostash, "MERGE_AUTOSTASH")

+
  static int show_diffstat = 1, shortlog_len = -1, squash;
  static int option_commit = -1;
  static int option_edit = -1;
@@ -81,6 +84,7 @@ static int show_progress = -1;
  static int default_to_upstream = 1;
  static int signoff;
  static const char *sign_commit;
+static int autostash;
  static int no_verify;
  
  static struct strategy all_strategy[] = {

@@ -285,6 +289,8 @@ static struct option builtin_merge_options[] = {
OPT_SET_INT(0, "progress", &show_progress, N_("force progress 
reporting"), 1),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+   OPT_BOOL(0, "autostash", &autostash,
+ N_("automatically stash/stash pop before and after")),
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files 
(default)")),
OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and 
commit-msg hooks")),
@@ -440,6 +446,7 @@ static void finish(struct commit *head_commit,
strbuf_addf(&reflog_message, "%s: %s",
getenv("GIT_REFLOG_ACTION"), msg);
}
+   apply_autostash(merge_autostash());
if (squash) {
squash_message(head_commit, remoteheads);
} else {
@@ -631,6 +638,9 @@ static int git_merge_config(const char *k, const char *v, 
void *cb)
} else if (!strcmp(k, "commit.gpgsign")) {
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
+   } else if (!strcmp(k, "merge.autostash")) {
+   autostash = git_config_bool(k, v);
+   return 0;
}
  
  	status = fmt_merge_msg_config(k, v, cb);

@@ -724,6 +734,8 @@ static int try_merge_strategy(const char *strategy, struct 
commit_list *common,
for (j = common; j; j = j->next)
commit_list_insert(j->item, &reversed);
  
+		if (autostash)

+   perform_autostash(merge_autostash());
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
clean = merge_recursive(&o, head,
remoteheads->item, reversed, &result);
@@ -1288,6 +1300,7 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
  
  		/* Invoke 'git reset --merge' */

ret = cmd_reset(nargc, nargv, prefix);
+   apply_autostash(merge_autostash());
goto done;
}
  
diff --git a/builtin/pull.c b/builtin/pull.c

index d25ff13a60..ee186781ae 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -183,7 +183,7 @@ static struct option pull_options[] = {
N_("verify that the named commit has a valid GPG signature"),
PARSE_OPT_NOARG),
OPT_BOOL(0, "autostash", &opt_autostash,
-   N_("automatically stash/stash pop before and after rebase")),
+   N_("automatically stash/stash pop before and after")),


I've not looked closely at the code in this patch but noticed this. I 
think it would read better if it said


automatically stash/stash pop before and after pulling

Best Wishes

Phillip


OPT_PASSTHRU_ARGV('s', "strategy", &opt_strategies, N_("strategy&quo

Re: [RFC PATCH 6/7] autostash.c: undefine USE_THE_INDEX_COMPATIBILITY_MACROS

2019-10-18 Thread Phillip Wood

Hi Denton

On 16/10/2019 18:26, Denton Liu wrote:

Since autostash.c was recently introduced, we should avoid
USE_THE_INDEX_COMPATIBILITY_MACROS since we are trying to move away from
this in the rest of the codebase. Rewrite the autostash code to not need
it and remove its definition.

Signed-off-by: Denton Liu 
---
  autostash.c | 8 +++-
  1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/autostash.c b/autostash.c
index 722cf78b12..0a1f00d2e5 100644
--- a/autostash.c
+++ b/autostash.c
@@ -1,5 +1,3 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-
  #include "git-compat-util.h"
  #include "autostash.h"
  #include "cache-tree.h"
@@ -46,7 +44,7 @@ int reset_head(struct object_id *oid, const char *action,
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
  
-	if (!refs_only && hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {

+   if (!refs_only && repo_hold_locked_index(the_repository, &lock, 
LOCK_REPORT_ON_ERROR) < 0) {


As I understand it the reason for moving away from hold_locked_index() 
is that it relies on a global variable. While replacing it with an 
explicit reference the the_repository removes the implicit dependency on 
global state, it does not move us away from depending on a global 
variable. I think it would be nicer to change these functions to take a 
`struct repository*` before moving them.


Best Wishes

Phillip

ret = -1;
goto leave_reset_head;
}
@@ -157,8 +155,8 @@ void perform_autostash(const char *path)
struct lock_file lock_file = LOCK_INIT;
int fd;
  
-	fd = hold_locked_index(&lock_file, 0);

-   refresh_cache(REFRESH_QUIET);
+   fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+   refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
repo_update_index_if_able(the_repository, &lock_file);
rollback_lock_file(&lock_file);



Re: [RFC PATCH 4/7] autostash: extract reset_head() from rebase

2019-10-18 Thread Phillip Wood

Hi Denton

It's great to see this being libified, I've had it in mind to do this so 
we can avoid forking 'git checkout' in sequencer.c


On 16/10/2019 18:26, Denton Liu wrote:

Begin the process of lib-ifying the autostash code. In a future commit,

This patch is best viewed with `--color-moved` and
`--color-moved-ws=allow-indentation-change`.
this will be used to implement `--autostash` in other builtins.

Signed-off-by: Denton Liu 
---
  autostash.c  | 137 +++
  autostash.h  |  12 +
  builtin/rebase.c | 137 ---
  3 files changed, 149 insertions(+), 137 deletions(-)

diff --git a/autostash.c b/autostash.c
index 62ec7a7c80..eb58e0c8a4 100644
--- a/autostash.c
+++ b/autostash.c
@@ -1,9 +1,17 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS


It might be nicer to have a preparatory step that fixes this by adding a 
'struct repository *r' argument to the function in builtin/rebase.c 
before moving the function. You could also do the same for next patch 
and then move both functions together.


Best Wishes

Phillip


+
  #include "git-compat-util.h"
  #include "autostash.h"
+#include "cache-tree.h"
  #include "dir.h"
  #include "gettext.h"
+#include "lockfile.h"
+#include "refs.h"
  #include "run-command.h"
  #include "strbuf.h"
+#include "tree-walk.h"
+#include "tree.h"
+#include "unpack-trees.h"
  
  int read_one(const char *path, struct strbuf *buf)

  {
@@ -13,6 +21,135 @@ int read_one(const char *path, struct strbuf *buf)
return 0;
  }
  
+int reset_head(struct object_id *oid, const char *action,

+  const char *switch_to_branch, unsigned flags,
+  const char *reflog_orig_head, const char *reflog_head)
+{
+   unsigned detach_head = flags & RESET_HEAD_DETACH;
+   unsigned reset_hard = flags & RESET_HEAD_HARD;
+   unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+   unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
+   unsigned update_orig_head = flags & RESET_ORIG_HEAD;
+   struct object_id head_oid;
+   struct tree_desc desc[2] = { { NULL }, { NULL } };
+   struct lock_file lock = LOCK_INIT;
+   struct unpack_trees_options unpack_tree_opts;
+   struct tree *tree;
+   const char *reflog_action;
+   struct strbuf msg = STRBUF_INIT;
+   size_t prefix_len;
+   struct object_id *orig = NULL, oid_orig,
+   *old_orig = NULL, oid_old_orig;
+   int ret = 0, nr = 0;
+
+   if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
+   BUG("Not a fully qualified branch: '%s'", switch_to_branch);
+
+   if (!refs_only && hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
+   ret = -1;
+   goto leave_reset_head;
+   }
+
+   if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
+   ret = error(_("could not determine HEAD revision"));
+   goto leave_reset_head;
+   }
+
+   if (!oid)
+   oid = &head_oid;
+
+   if (refs_only)
+   goto reset_head_refs;
+
+   memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
+   setup_unpack_trees_porcelain(&unpack_tree_opts, action);
+   unpack_tree_opts.head_idx = 1;
+   unpack_tree_opts.src_index = the_repository->index;
+   unpack_tree_opts.dst_index = the_repository->index;
+   unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
+   unpack_tree_opts.update = 1;
+   unpack_tree_opts.merge = 1;
+   if (!detach_head)
+   unpack_tree_opts.reset = 1;
+
+   if (repo_read_index_unmerged(the_repository) < 0) {
+   ret = error(_("could not read index"));
+   goto leave_reset_head;
+   }
+
+   if (!reset_hard && !fill_tree_descriptor(the_repository, &desc[nr++], 
&head_oid)) {
+   ret = error(_("failed to find tree of %s"),
+   oid_to_hex(&head_oid));
+   goto leave_reset_head;
+   }
+
+   if (!fill_tree_descriptor(the_repository, &desc[nr++], oid)) {
+   ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
+   goto leave_reset_head;
+   }
+
+   if (unpack_trees(nr, desc, &unpack_tree_opts)) {
+   ret = -1;
+   goto leave_reset_head;
+   }
+
+   tree = parse_tree_indirect(oid);
+   prime_cache_tree(the_repository, the_repository->index, tree);
+
+   if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
+   ret = error(_("co

Re: [RFC PATCH 2/7] autostash: extract read_one() from rebase

2019-10-18 Thread Phillip Wood

Hi Denton

On 16/10/2019 18:26, Denton Liu wrote:

Begin the process of lib-ifying the autostash code. In a future commit,
this will be used to implement `--autostash` in other builtins.

This patch is best viewed with `--color-moved` and
`--color-moved-ws=allow-indentation-change`.

Signed-off-by: Denton Liu 
---
  autostash.c  | 12 
  autostash.h  |  9 +
  builtin/rebase.c | 10 +-
  3 files changed, 22 insertions(+), 9 deletions(-)
  create mode 100644 autostash.c
  create mode 100644 autostash.h

diff --git a/autostash.c b/autostash.c
new file mode 100644
index 00..a6898e0fda
--- /dev/null
+++ b/autostash.c
@@ -0,0 +1,12 @@
+#include "git-compat-util.h"
+#include "autostash.h"
+#include "gettext.h"
+#include "strbuf.h"
+
+int read_one(const char *path, struct strbuf *buf)
+{
+   if (strbuf_read_file(buf, path, 0) < 0)
+   return error_errno(_("could not read '%s'"), path);
+   strbuf_trim_trailing_newline(buf);
+   return 0;
+}


This looks like it's doing a similar job to read_oneliner() in 
sequencer.c, is it possible to make that public and use it instead? 
(There may be a difference if the file is missing but that function 
already takes a flag so it could probably be modified easily enough.)


Best Wishes

Phillip



diff --git a/autostash.h b/autostash.h
new file mode 100644
index 00..4a8f504f12
--- /dev/null
+++ b/autostash.h
@@ -0,0 +1,9 @@
+#ifndef AUTOSTASH_H
+#define AUTOSTASH_H
+
+#include "strbuf.h"
+
+/* Read one file, then strip line endings */
+int read_one(const char *path, struct strbuf *buf);
+
+#endif
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 4a20582e72..9fd7de6b2f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -27,6 +27,7 @@
  #include "branch.h"
  #include "sequencer.h"
  #include "rebase-interactive.h"
+#include "autostash.h"
  
  static char const * const builtin_rebase_usage[] = {

N_("git rebase [-i] [options] [--exec ] "
@@ -561,15 +562,6 @@ static const char *state_dir_path(const char *filename, 
struct rebase_options *o
return path.buf;
  }
  
-/* Read one file, then strip line endings */

-static int read_one(const char *path, struct strbuf *buf)
-{
-   if (strbuf_read_file(buf, path, 0) < 0)
-   return error_errno(_("could not read '%s'"), path);
-   strbuf_trim_trailing_newline(buf);
-   return 0;
-}
-
  /* Initialize the rebase options from the state directory. */
  static int read_basic_state(struct rebase_options *opts)
  {



[PATCH v2 5/6] move run_commit_hook() to libgit and use it there

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

This function was declared in commit.h but was implemented in
builtin/commit.c so was not part of libgit. Move it to libgit so we can
use it in the sequencer. This simplifies the implementation of
run_prepare_commit_msg_hook() and will be used in the next commit.

Signed-off-by: Phillip Wood 
---
 builtin/commit.c | 22 --
 commit.c | 24 
 sequencer.c  | 23 ++-
 3 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1921401117..d898a57f5d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1443,28 +1443,6 @@ static int git_commit_config(const char *k, const char 
*v, void *cb)
return git_status_config(k, v, s);
 }
 
-int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...)
-{
-   struct argv_array hook_env = ARGV_ARRAY_INIT;
-   va_list args;
-   int ret;
-
-   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
-
-   /*
-* Let the hook know that no editor will be launched.
-*/
-   if (!editor_is_used)
-   argv_array_push(&hook_env, "GIT_EDITOR=:");
-
-   va_start(args, name);
-   ret = run_hook_ve(hook_env.argv,name, args);
-   va_end(args);
-   argv_array_clear(&hook_env);
-
-   return ret;
-}
-
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
const char *argv_gc_auto[] = {"gc", "--auto", NULL};
diff --git a/commit.c b/commit.c
index 26ce0770f6..7ca8d12174 100644
--- a/commit.c
+++ b/commit.c
@@ -19,6 +19,7 @@
 #include "advice.h"
 #include "refs.h"
 #include "commit-reach.h"
+#include "run-command.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char 
*buf, size_t len, const char **);
 
@@ -1581,3 +1582,26 @@ size_t ignore_non_trailer(const char *buf, size_t len)
}
return boc ? len - boc : len - cutoff;
 }
+
+int run_commit_hook(int editor_is_used, const char *index_file,
+   const char *name, ...)
+{
+   struct argv_array hook_env = ARGV_ARRAY_INIT;
+   va_list args;
+   int ret;
+
+   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+
+   /*
+* Let the hook know that no editor will be launched.
+*/
+   if (!editor_is_used)
+   argv_array_push(&hook_env, "GIT_EDITOR=:");
+
+   va_start(args, name);
+   ret = run_hook_ve(hook_env.argv,name, args);
+   va_end(args);
+   argv_array_clear(&hook_env);
+
+   return ret;
+}
diff --git a/sequencer.c b/sequencer.c
index 2adcf5a639..cdc0d1dfba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1127,25 +1127,22 @@ static int run_prepare_commit_msg_hook(struct 
repository *r,
   struct strbuf *msg,
   const char *commit)
 {
-   struct argv_array hook_env = ARGV_ARRAY_INIT;
-   int ret;
-   const char *name;
+   int ret = 0;
+   const char *name, *arg1 = NULL, *arg2 = NULL;
 
name = git_path_commit_editmsg();
if (write_message(msg->buf, msg->len, name, 0))
return -1;
 
-   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file);
-   argv_array_push(&hook_env, "GIT_EDITOR=:");
-   if (commit)
-   ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
- "commit", commit, NULL);
-   else
-   ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
- "message", NULL);
-   if (ret)
+   if (commit) {
+   arg1 = "commit";
+   arg2 = commit;
+   } else {
+   arg1 = "message";
+   }
+   if (run_commit_hook(0, r->index_file, "prepare-commit-msg", name,
+   arg1, arg2, NULL))
ret = error(_("'prepare-commit-msg' hook failed"));
-   argv_array_clear(&hook_env);
 
return ret;
 }
-- 
gitgitgadget



[PATCH v2 4/6] sequencer.h fix placement of #endif

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Commit 65850686cf ("rebase -i: rewrite write_basic_state() in C",
2018-08-28) accidentially added new function declarations after
the #endif at the end of the include guard.

Signed-off-by: Phillip Wood 
---
 sequencer.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..ac66892d71 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -195,11 +195,10 @@ void print_commit_summary(struct repository *repo,
 
 int read_author_script(const char *path, char **name, char **email, char 
**date,
   int allow_missing);
-#endif
-
 void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
 int write_basic_state(struct replay_opts *opts, const char *head_name,
  struct commit *onto, const char *orig_head);
 void sequencer_post_commit_cleanup(struct repository *r);
 int sequencer_get_last_command(struct repository* r,
   enum replay_action *action);
+#endif /* SEQUENCER_H */
-- 
gitgitgadget



[PATCH v2 2/6] t3404: set $EDITOR in subshell

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

As $EDITOR is exported setting it in one test affects all subsequent
tests. Avoid this by always setting it in a subshell. This commit leaves
20 calls to set_fake_editor that are not in subshells as they can
safely be removed in the next commit once all the other editor setting
is done inside subshells.

I have moved the call to set_fake_editor in some tests so it comes
immediately before the call to 'git rebase' to avoid moving unrelated
commands into the subshell. In one case ('rebase -ix with
--autosquash') the call to set_fake_editor is moved past an invocation
of 'git rebase'. This is safe as that invocation of 'git rebase'
requires EDITOR=: or EDITOR=fake-editor.sh without FAKE_LINES being
set which will be the case as the preceding tests either set their
editor in a subshell or call set_fake_editor without setting FAKE_LINES.

In a one test ('auto-amend only edited commits after "edit"') a call
to test_tick are now in a subshell. I think this is OK as it is there
to set the date for the next commit which is executed in the same
subshell rather than updating GIT_COMMITTER_DATE for later tests (the
next test calls test_tick before doing anything else).

Signed-off-by: Phillip Wood 
---
 t/t3404-rebase-interactive.sh | 546 +-
 1 file changed, 342 insertions(+), 204 deletions(-)

diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index c26b3362ef..cb9b21 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -79,8 +79,11 @@ test_expect_success 'rebase -i with empty HEAD' '
cat >expect <<-\EOF &&
error: nothing to do
EOF
-   set_fake_editor &&
-   test_must_fail env FAKE_LINES="1 exec_true" git rebase -i HEAD^ >actual 
2>&1 &&
+   (
+   set_fake_editor &&
+   test_must_fail env FAKE_LINES="1 exec_true" \
+   git rebase -i HEAD^ >actual 2>&1
+   ) &&
test_i18ncmp expect actual
 '
 
@@ -139,8 +142,11 @@ test_expect_success 'rebase -i sets work tree properly' '
 
 test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git checkout master &&
-   set_fake_editor &&
-   test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" git rebase -i 
HEAD^ &&
+   (
+   set_fake_editor &&
+   test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" \
+   git rebase -i HEAD^
+   ) &&
test_cmp_rev master^ HEAD &&
git reset --hard &&
git rebase --continue
@@ -168,9 +174,11 @@ test_expect_success 'rebase -x with newline in command 
fails' '
 test_expect_success 'rebase -i with exec of inexistent command' '
git checkout master &&
test_when_finished "git rebase --abort" &&
-   set_fake_editor &&
-   test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 1" \
-   git rebase -i HEAD^ >actual 2>&1 &&
+   (
+   set_fake_editor &&
+   test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 
1" \
+   git rebase -i HEAD^ >actual 2>&1
+   ) &&
! grep "Maybe git-rebase is broken" actual
 '
 
@@ -230,8 +238,10 @@ test_expect_success 'reflog for the branch shows correct 
finish message' '
 '
 
 test_expect_success 'exchange two commits' '
-   set_fake_editor &&
-   FAKE_LINES="2 1" git rebase -i HEAD~2 &&
+   (
+   set_fake_editor &&
+   FAKE_LINES="2 1" git rebase -i HEAD~2
+   ) &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
 '
@@ -332,9 +342,11 @@ test_expect_success 'squash' '
test_tick &&
GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
echo "**" &&
-   set_fake_editor &&
-   FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
-   git rebase -i --onto master HEAD~2 &&
+   (
+   set_fake_editor &&
+   FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
+   git rebase -i --onto master HEAD~2
+   ) &&
test B = $(cat file7) &&
test $(git rev-parse HEAD^) = $(git rev-parse master)
 '
@@ -355,8 +367,10 @@ test_expect_success REBA

[PATCH v2 0/6] sequencer: start running post-commit hook again

2019-10-15 Thread Phillip Wood via GitGitGadget
When I converted the sequencer to avoid forking git commit i forgot about
the post-commit hook. These patches are based on
pw/rebase-i-show-HEAD-to-reword, otherwise the new test fails as that branch
changes the number of commits we make.

Thanks to Dscho & Junio for their comments on V1. I've made the following
changes:

Patches 1-3 These are new patches in response to Dscho's request to set
$EDITOR in a subshell. There were ~80 other tests that weren't doing that
and they are fixed in these patches. Patch 2 contains the main action,
unfortunately due to a combination of having to remove the trailing ' &&'
from the last line moved into the subshell and re-wrapping some lines due to
the increased indentation --color-moved and --color-moved-ws are of limited
use when viewing this patch.

Patch 4 (was 1) Unchanged

Patch 5 (was 2) I've moved the function definition to commit.c rather than
sequencer.c as suggested. I've also removed an unused struct argv_array from
run_prepare_commit_msg_hook() (There wasn't a compiler warning as it was
still calling argv_array_clear() at the end of the function) and reworded
the commit message.

Patch 6 (was 3) I've tided up the test and removed the wrapper function for
running the post-commit hook as suggested.

Phillip Wood (6):
  t3404: remove unnecessary subshell
  t3404: set $EDITOR in subshell
  t3404: remove uneeded calls to set_fake_editor
  sequencer.h fix placement of #endif
  move run_commit_hook() to libgit and use it there
  sequencer: run post-commit hook

 builtin/commit.c  |  22 --
 commit.c  |  24 ++
 sequencer.c   |  24 +-
 sequencer.h   |   3 +-
 t/lib-rebase.sh   |  28 ++
 t/t3404-rebase-interactive.sh | 596 +-
 6 files changed, 432 insertions(+), 265 deletions(-)


base-commit: b0a3186140dbc7bd64cbc6ef733386a0f1eb6a4d
Published-As: 
https://github.com/gitgitgadget/git/releases/tag/pr-388%2Fphillipwood%2Fwip%2Frebase-commit-hooks-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git 
pr-388/phillipwood/wip/rebase-commit-hooks-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/388

Range-diff vs v1:

 -:  -- > 1:  b9689e85e5 t3404: remove unnecessary subshell
 -:  -- > 2:  96432cd0f0 t3404: set $EDITOR in subshell
 -:  -- > 3:  09857dee78 t3404: remove uneeded calls to set_fake_editor
 1:  7305f8d8e8 = 4:  0eac3ede02 sequencer.h fix placement of #endif
 2:  420ecf442c ! 5:  f394a0e163 sequencer: use run_commit_hook()
 @@ -1,9 +1,11 @@
  Author: Phillip Wood 
  
 -sequencer: use run_commit_hook()
 +move run_commit_hook() to libgit and use it there
  
 -This simplifies the implementation of run_prepare_commit_msg_hook() 
and
 -will be used in the next commit.
 +This function was declared in commit.h but was implemented in
 +builtin/commit.c so was not part of libgit. Move it to libgit so we 
can
 +use it in the sequencer. This simplifies the implementation of
 +run_prepare_commit_msg_hook() and will be used in the next commit.
  
  Signed-off-by: Phillip Wood 
  
 @@ -40,25 +42,22 @@
   {
const char *argv_gc_auto[] = {"gc", "--auto", NULL};
  
 - diff --git a/commit.h b/commit.h
 - --- a/commit.h
 - +++ b/commit.h
 + diff --git a/commit.c b/commit.c
 + --- a/commit.c
 + +++ b/commit.c
  @@
 - int compare_commits_by_commit_date(const void *a_, const void *b_, void 
*unused);
 - int compare_commits_by_gen_then_commit_date(const void *a_, const void 
*b_, void *unused);
 + #include "advice.h"
 + #include "refs.h"
 + #include "commit-reach.h"
 ++#include "run-command.h"
 + 
 + static struct commit_extra_header *read_commit_extra_header_lines(const 
char *buf, size_t len, const char **);
   
 --LAST_ARG_MUST_BE_NULL
 --int run_commit_hook(int editor_is_used, const char *index_file, const 
char *name, ...);
 --
 - #endif /* COMMIT_H */
 -
 - diff --git a/sequencer.c b/sequencer.c
 - --- a/sequencer.c
 - +++ b/sequencer.c
  @@
 -  run_rewrite_hook(&old_head->object.oid, new_head);
 +  }
 +  return boc ? len - boc : len - cutoff;
   }
 - 
 ++
  +int run_commit_hook(int editor_is_used, const char *index_file,
  + const char *name, ...)
  +{
 @@ -81,12 +80,15 @@
  +
  + return ret;
  +}
 -+
 - static int run_prepare_commit_msg_hook(struct repository *r,
 +
 + diff --git a/sequencer.c b/sequencer.c
 + --- a/sequencer.c
 + +++ b/sequencer.c
 +@@
   struct strbuf *msg,
   const char *commit)
   {
 -  struct a

[PATCH v2 1/6] t3404: remove unnecessary subshell

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Neither of the commands executed in the subshell change any shell
variables or the current directory so there is no need for them to be
executed in a subshell.

Signed-off-by: Phillip Wood 
---
 t/t3404-rebase-interactive.sh | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index d2f1d5bd23..c26b3362ef 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -945,10 +945,8 @@ test_expect_success C_LOCALE_OUTPUT 'rebase -ix with 
--autosquash' '
git add bis.txt &&
git commit -m "fixup! two_exec" &&
set_fake_editor &&
-   (
-   git checkout -b autosquash_actual &&
-   git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
-   ) &&
+   git checkout -b autosquash_actual &&
+   git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual &&
git checkout autosquash &&
(
git checkout -b autosquash_expected &&
-- 
gitgitgadget



[PATCH v2 6/6] sequencer: run post-commit hook

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Prior to commit 356ee4659b ("sequencer: try to commit without forking
'git commit'", 2017-11-24) the sequencer would always run the
post-commit hook after each pick or revert as it forked `git commit` to
create the commit. The conversion to committing without forking `git
commit` omitted to call the post-commit hook after creating the commit.

Signed-off-by: Phillip Wood 
---
 sequencer.c   |  1 +
 t/t3404-rebase-interactive.sh | 19 +++
 2 files changed, 20 insertions(+)

diff --git a/sequencer.c b/sequencer.c
index cdc0d1dfba..da2decbd3a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1401,6 +1401,7 @@ static int try_to_commit(struct repository *r,
goto out;
}
 
+   run_commit_hook(0, r->index_file, "post-commit", NULL);
if (flags & AMEND_MSG)
commit_post_rewrite(r, current_head, oid);
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index c5d0326825..c573c99069 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1583,6 +1583,25 @@ test_expect_success 'valid author header when author 
contains single quote' '
test_cmp expected actual
 '
 
+test_expect_success 'post-commit hook is called' '
+   test_when_finished "rm -f .git/hooks/post-commit" &&
+   >actual &&
+   mkdir -p .git/hooks &&
+   write_script .git/hooks/post-commit <<-\EOS &&
+   git rev-parse HEAD >>actual
+   EOS
+   (
+   set_fake_editor &&
+   FAKE_LINES="edit 4 1 reword 2 fixup 3" git rebase -i A E &&
+   echo x>file3 &&
+   git add file3 &&
+   FAKE_COMMIT_MESSAGE=edited git rebase --continue
+   ) &&
+   git rev-parse HEAD@{5} HEAD@{4} HEAD@{3} HEAD@{2} HEAD@{1} HEAD \
+   >expect &&
+   test_cmp expect actual
+'
+
 # This must be the last test in this file
 test_expect_success '$EDITOR and friends are unchanged' '
test_editor_unchanged
-- 
gitgitgadget


[PATCH v2 3/6] t3404: remove uneeded calls to set_fake_editor

2019-10-15 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Some tests were calling set_fake_editor to ensure they had a sane no-op
editor set. Now that all the editor setting is done in subshells these
tests can rely on EDITOR=: and so do not need to call set_fake_editor.

Also add a test at the end to detect any future additions messing with
the exported value of $EDITOR.

Signed-off-by: Phillip Wood 
---
 t/lib-rebase.sh   | 28 
 t/t3404-rebase-interactive.sh | 25 +
 2 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 7ea30e5006..e4554db85e 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -118,3 +118,31 @@ make_empty () {
git commit --allow-empty -m "$1" &&
git tag "$1"
 }
+
+# Call this (inside test_expect_success) at the end of a test file to
+# check that no tests have changed editor related environment
+# variables or config settings
+test_editor_unchanged () {
+   # We're only interested in exported variables hence 'sh -c'
+   sh -c 'cat >actual <<-EOF
+   EDITOR=$EDITOR
+   FAKE_COMMIT_AMEND=$FAKE_COMMIT_AMEND
+   FAKE_COMMIT_MESSAGE=$FAKE_COMMIT_MESSAGE
+   FAKE_LINES=$FAKE_LINES
+   GIT_EDITOR=$GIT_EDITOR
+   GIT_SEQUENCE_EDITOR=$GIT_SEQUENCE_EDITOR
+   core.editor=$(git config core.editor)
+   sequence.editor=$(git config sequence.editor)
+   EOF'
+   cat >expect <<-\EOF
+   EDITOR=:
+   FAKE_COMMIT_AMEND=
+   FAKE_COMMIT_MESSAGE=
+   FAKE_LINES=
+   GIT_EDITOR=
+   GIT_SEQUENCE_EDITOR=
+   core.editor=
+   sequence.editor=
+   EOF
+   test_cmp expect actual
+}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index cb9b21..c5d0326825 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -189,7 +189,6 @@ test_expect_success 'implicit interactive rebase does not 
invoke sequence editor
 
 test_expect_success 'no changes are a nop' '
git checkout branch2 &&
-   set_fake_editor &&
git rebase -i F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse HEAD)
@@ -199,7 +198,6 @@ test_expect_success 'test the [branch] option' '
git checkout -b dead-end &&
git rm file6 &&
git commit -m "stop here" &&
-   set_fake_editor &&
git rebase -i F branch2 &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse branch2) &&
@@ -208,7 +206,6 @@ test_expect_success 'test the [branch] option' '
 
 test_expect_success 'test --onto ' '
git checkout -b test-onto branch2 &&
-   set_fake_editor &&
git rebase -i --onto branch1 F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
@@ -218,7 +215,6 @@ test_expect_success 'test --onto ' '
 test_expect_success 'rebase on top of a non-conflicting commit' '
git checkout branch1 &&
git tag original-branch1 &&
-   set_fake_editor &&
git rebase -i branch2 &&
test file6 = $(git diff --name-only original-branch1) &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
@@ -264,7 +260,6 @@ test_expect_success 'stop on conflicting pick' '
>>>>>>> 5d18e54... G
EOF
git tag new-branch1 &&
-   set_fake_editor &&
test_must_fail git rebase -i master &&
test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
test_cmp expect .git/rebase-merge/patch &&
@@ -293,7 +288,6 @@ test_expect_success 'abort' '
 test_expect_success 'abort with error when new base cannot be checked out' '
git rm --cached file1 &&
git commit -m "remove file in base" &&
-   set_fake_editor &&
test_must_fail git rebase -i master > output 2>&1 &&
test_i18ngrep "The following untracked working tree files would be 
overwritten by checkout:" \
output &&
@@ -308,7 +302,6 @@ test_expect_success 'retain authorship' '
test_tick &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
git tag twerp &&
-   set_fake_editor &&

Re: [PATCH 2/3] sequencer: use run_commit_hook()

2019-10-14 Thread Phillip Wood
Hi Dscho & Junio

On 11/10/2019 05:24, Junio C Hamano wrote:
> Johannes Schindelin  writes:
> 
>>>  builtin/commit.c | 22 --
>>>  commit.h |  3 ---
>>>  sequencer.c  | 45 ++---
>>>  sequencer.h  |  2 ++
>>>  4 files changed, 36 insertions(+), 36 deletions(-)
>>
>> Hmm. I would have thought that `commit.c` would be a more logical home
>> for that function (and that the declaration could remain in `commit.h`)?
> 
> Good correction.

There are some other public commit related functions in sequencer.c -
print_commit_summary(), commit_post_rewrite(), rest_is_empty(),
cleanup_message(), message_is_empty(), template_untouched(),
update_head_with_reflog() . Would you like to see them moved to commit.c
(probably as a separate series)?

Best Wishes

Phillip

> 
> Thanks.
> 



Re: [PATCH 3/3] sequencer: run post-commit hook

2019-10-11 Thread Phillip Wood

Hi Dscho

On 10/10/2019 22:31, Johannes Schindelin wrote:

Hi Phillip,

On Thu, 10 Oct 2019, Phillip Wood via GitGitGadget wrote:


From: Phillip Wood 

Prior to commit 356ee4659b ("sequencer: try to commit without forking
'git commit'", 2017-11-24) the sequencer would always run the
post-commit hook after each pick or revert as it forked `git commit` to
create the commit. The conversion to committing without forking `git
commit` omitted to call the post-commit hook after creating the commit.

Signed-off-by: Phillip Wood 


Makes sense.


---
  builtin/commit.c  |  2 +-
  sequencer.c   |  5 +
  sequencer.h   |  1 +
  t/t3404-rebase-interactive.sh | 17 +
  4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index d898a57f5d..adb8c89c60 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1653,7 +1653,7 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)

repo_rerere(the_repository, 0);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
-   run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
+   run_post_commit_hook(use_editor, get_index_file());


Does it really make sense to abstract the hook name away? It adds a lot
of churn for just two callers...


I'll drop the new function in the reroll


if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
}
diff --git a/sequencer.c b/sequencer.c
index 3ce578c40b..b4947f6969 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1173,6 +1173,10 @@ static int run_prepare_commit_msg_hook(struct repository 
*r,
return ret;
  }

+void run_post_commit_hook(int editor_is_used, const char *index_file) {
+   run_commit_hook(editor_is_used, index_file, "post-commit", NULL);
+}
+


If we must have a separate `run_post_commit_hook()`, then it should be
an `inline` function, defined in the header. Or even a macro to begin
with.


  static const char implicit_ident_advice_noconfig[] =
  N_("Your name and email address were configured automatically based\n"
  "on your username and hostname. Please check that they are accurate.\n"
@@ -1427,6 +1431,7 @@ static int try_to_commit(struct repository *r,
goto out;
}

+   run_post_commit_hook(0, r->index_file);


So this is the _actual_ change of this patch.


if (flags & AMEND_MSG)
commit_post_rewrite(r, current_head, oid);

diff --git a/sequencer.h b/sequencer.h
index b0419d6ddb..e3e73c5635 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -203,4 +203,5 @@ int sequencer_get_last_command(struct repository* r,
   enum replay_action *action);
  LAST_ARG_MUST_BE_NULL
  int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...);
+void run_post_commit_hook(int editor_is_used, const char *index_file);
  #endif /* SEQUENCER_H */
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index d2f1d5bd23..d9217235b6 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1467,4 +1467,21 @@ test_expect_success 'valid author header when author 
contains single quote' '
test_cmp expected actual
  '

+test_expect_success 'post-commit hook is called' '
+   test_when_finished "rm -f .git/hooks/post-commit commits" &&
+   mkdir -p .git/hooks &&
+   write_script .git/hooks/post-commit <<-\EOS &&
+   git rev-parse HEAD >>commits


Should `commits` be initialized before this script is written, e.g.
using

>commits &&


Good point, especially if it is renamed to actual as Junio suggests


+   EOS
+   set_fake_editor &&


The `set_fake_editor` function sets a global environment variable, and
therefore needs to be run in a subshell. Therefore, this line (as well
as the next one) need to be enclosed in `( ... )`.


There are ~80 instances of 
set_fake_editor/test_set_editor/set_cat_todo_editor in that file that 
are not in subshells. I've converted them in a preparatory patch (that 
was fun), removing about 20 that can now safely rely on EDITOR=: 
(hopefully that will ameliorate the performance hit of ~60 extra 
subshells a little)



+   FAKE_LINES="edit 4 1 reword 2 fixup 3" git rebase -i A E &&
+   echo x>file3 &&


We usually leave no space after the `>`, but we _do_ leave a space
_before_ the `>`.


+   git add file3 &&
+   FAKE_COMMIT_MESSAGE=edited git rebase --continue &&
+   # rev-list does not support -g --reverse
+   git rev-list --no-walk=unsorted HEAD@{5} HEAD@{4} HEAD@{3} HEAD@{2} \
+   HEAD@{1} HEAD >expected &&


Wouldn't this be better

[PATCH 3/3] sequencer: run post-commit hook

2019-10-10 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Prior to commit 356ee4659b ("sequencer: try to commit without forking
'git commit'", 2017-11-24) the sequencer would always run the
post-commit hook after each pick or revert as it forked `git commit` to
create the commit. The conversion to committing without forking `git
commit` omitted to call the post-commit hook after creating the commit.

Signed-off-by: Phillip Wood 
---
 builtin/commit.c  |  2 +-
 sequencer.c   |  5 +
 sequencer.h   |  1 +
 t/t3404-rebase-interactive.sh | 17 +
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index d898a57f5d..adb8c89c60 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1653,7 +1653,7 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
 
repo_rerere(the_repository, 0);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
-   run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
+   run_post_commit_hook(use_editor, get_index_file());
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
}
diff --git a/sequencer.c b/sequencer.c
index 3ce578c40b..b4947f6969 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1173,6 +1173,10 @@ static int run_prepare_commit_msg_hook(struct repository 
*r,
return ret;
 }
 
+void run_post_commit_hook(int editor_is_used, const char *index_file) {
+   run_commit_hook(editor_is_used, index_file, "post-commit", NULL);
+}
+
 static const char implicit_ident_advice_noconfig[] =
 N_("Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -1427,6 +1431,7 @@ static int try_to_commit(struct repository *r,
goto out;
}
 
+   run_post_commit_hook(0, r->index_file);
if (flags & AMEND_MSG)
commit_post_rewrite(r, current_head, oid);
 
diff --git a/sequencer.h b/sequencer.h
index b0419d6ddb..e3e73c5635 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -203,4 +203,5 @@ int sequencer_get_last_command(struct repository* r,
   enum replay_action *action);
 LAST_ARG_MUST_BE_NULL
 int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...);
+void run_post_commit_hook(int editor_is_used, const char *index_file);
 #endif /* SEQUENCER_H */
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index d2f1d5bd23..d9217235b6 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1467,4 +1467,21 @@ test_expect_success 'valid author header when author 
contains single quote' '
test_cmp expected actual
 '
 
+test_expect_success 'post-commit hook is called' '
+   test_when_finished "rm -f .git/hooks/post-commit commits" &&
+   mkdir -p .git/hooks &&
+   write_script .git/hooks/post-commit <<-\EOS &&
+   git rev-parse HEAD >>commits
+   EOS
+   set_fake_editor &&
+   FAKE_LINES="edit 4 1 reword 2 fixup 3" git rebase -i A E &&
+   echo x>file3 &&
+   git add file3 &&
+   FAKE_COMMIT_MESSAGE=edited git rebase --continue &&
+   # rev-list does not support -g --reverse
+   git rev-list --no-walk=unsorted HEAD@{5} HEAD@{4} HEAD@{3} HEAD@{2} \
+   HEAD@{1} HEAD >expected &&
+   test_cmp expected commits
+'
+
 test_done
-- 
gitgitgadget


[PATCH 1/3] sequencer.h fix placement of #endif

2019-10-10 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Commit 65850686cf ("rebase -i: rewrite write_basic_state() in C",
2018-08-28) accidentially added new function declarations after
the #endif at the end of the include guard.

Signed-off-by: Phillip Wood 
---
 sequencer.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..ac66892d71 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -195,11 +195,10 @@ void print_commit_summary(struct repository *repo,
 
 int read_author_script(const char *path, char **name, char **email, char 
**date,
   int allow_missing);
-#endif
-
 void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
 int write_basic_state(struct replay_opts *opts, const char *head_name,
  struct commit *onto, const char *orig_head);
 void sequencer_post_commit_cleanup(struct repository *r);
 int sequencer_get_last_command(struct repository* r,
   enum replay_action *action);
+#endif /* SEQUENCER_H */
-- 
gitgitgadget



[PATCH 2/3] sequencer: use run_commit_hook()

2019-10-10 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

This simplifies the implementation of run_prepare_commit_msg_hook() and
will be used in the next commit.

Signed-off-by: Phillip Wood 
---
 builtin/commit.c | 22 --
 commit.h |  3 ---
 sequencer.c  | 45 ++---
 sequencer.h  |  2 ++
 4 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1921401117..d898a57f5d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1443,28 +1443,6 @@ static int git_commit_config(const char *k, const char 
*v, void *cb)
return git_status_config(k, v, s);
 }
 
-int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...)
-{
-   struct argv_array hook_env = ARGV_ARRAY_INIT;
-   va_list args;
-   int ret;
-
-   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
-
-   /*
-* Let the hook know that no editor will be launched.
-*/
-   if (!editor_is_used)
-   argv_array_push(&hook_env, "GIT_EDITOR=:");
-
-   va_start(args, name);
-   ret = run_hook_ve(hook_env.argv,name, args);
-   va_end(args);
-   argv_array_clear(&hook_env);
-
-   return ret;
-}
-
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
const char *argv_gc_auto[] = {"gc", "--auto", NULL};
diff --git a/commit.h b/commit.h
index f5295ca7f3..37684a35f0 100644
--- a/commit.h
+++ b/commit.h
@@ -389,7 +389,4 @@ void verify_merge_signature(struct commit *commit, int 
verbose);
 int compare_commits_by_commit_date(const void *a_, const void *b_, void 
*unused);
 int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, 
void *unused);
 
-LAST_ARG_MUST_BE_NULL
-int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...);
-
 #endif /* COMMIT_H */
diff --git a/sequencer.c b/sequencer.c
index 2adcf5a639..3ce578c40b 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1123,28 +1123,51 @@ void commit_post_rewrite(struct repository *r,
run_rewrite_hook(&old_head->object.oid, new_head);
 }
 
+int run_commit_hook(int editor_is_used, const char *index_file,
+   const char *name, ...)
+{
+   struct argv_array hook_env = ARGV_ARRAY_INIT;
+   va_list args;
+   int ret;
+
+   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+
+   /*
+* Let the hook know that no editor will be launched.
+*/
+   if (!editor_is_used)
+   argv_array_push(&hook_env, "GIT_EDITOR=:");
+
+   va_start(args, name);
+   ret = run_hook_ve(hook_env.argv,name, args);
+   va_end(args);
+   argv_array_clear(&hook_env);
+
+   return ret;
+}
+
 static int run_prepare_commit_msg_hook(struct repository *r,
   struct strbuf *msg,
   const char *commit)
 {
struct argv_array hook_env = ARGV_ARRAY_INIT;
-   int ret;
-   const char *name;
+   int ret = 0;
+   const char *name, *arg1 = NULL, *arg2 = NULL;
 
name = git_path_commit_editmsg();
if (write_message(msg->buf, msg->len, name, 0))
return -1;
 
-   argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file);
-   argv_array_push(&hook_env, "GIT_EDITOR=:");
-   if (commit)
-   ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
- "commit", commit, NULL);
-   else
-   ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
- "message", NULL);
-   if (ret)
+   if (commit) {
+   arg1 = "commit";
+   arg2 = commit;
+   } else {
+   arg1 = "message";
+   }
+   if (run_commit_hook(0, r->index_file, "prepare-commit-msg", name,
+   arg1, arg2, NULL))
ret = error(_("'prepare-commit-msg' hook failed"));
+
argv_array_clear(&hook_env);
 
return ret;
diff --git a/sequencer.h b/sequencer.h
index ac66892d71..b0419d6ddb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -201,4 +201,6 @@ int write_basic_state(struct replay_opts *opts, const char 
*head_name,
 void sequencer_post_commit_cleanup(struct repository *r);
 int sequencer_get_last_command(struct repository* r,
   enum replay_action *action);
+LAST_ARG_MUST_BE_NULL
+int run_commit_hook(int editor_is_used, const char *index_file, const char 
*name, ...);
 #endif /* SEQUENCER_H */
-- 
gitgitgadget



[PATCH 0/3] sequencer: start running post-commit hook again

2019-10-10 Thread Phillip Wood via GitGitGadget
When I converted the sequencer to avoid forking git commit i forgot about
the post-commit hook. These patches are based on
pw/rebase-i-show-HEAD-to-reword, otherwise the new test fails as that branch
changes the number of commits we make.

Phillip Wood (3):
  sequencer.h fix placement of #endif
  sequencer: use run_commit_hook()
  sequencer: run post-commit hook

 builtin/commit.c  | 24 +
 commit.h  |  3 ---
 sequencer.c   | 50 +++
 sequencer.h   |  6 +++--
 t/t3404-rebase-interactive.sh | 17 
 5 files changed, 61 insertions(+), 39 deletions(-)


base-commit: b0a3186140dbc7bd64cbc6ef733386a0f1eb6a4d
Published-As: 
https://github.com/gitgitgadget/git/releases/tag/pr-388%2Fphillipwood%2Fwip%2Frebase-commit-hooks-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git 
pr-388/phillipwood/wip/rebase-commit-hooks-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/388
-- 
gitgitgadget


Re: Raise your hand to Ack jk/code-of-conduct if your Ack fell thru cracks

2019-10-09 Thread Phillip Wood

Hi Junio

On 09/10/2019 01:14, Junio C Hamano wrote:

Johannes Schindelin  writes:


In other words, the commit message can be augmented by this:

Acked-by: Johannes Schindelin 
Acked-by: Derrick Stolee 
Acked-by: Garima Singh 
Acked-by: Jonathan Tan 
Acked-by: Thomas Gummerer 
Acked-by: brian m. carlson 
Acked-by: Elijah Newren 

Junio, would you mind picking it up, please?


I trust you enough that I won't go back to the cited messages to
double check that these acks are real, but I'd still wait for a few
days for people who expressed their Acks but your scan missed, or
those who wanted to give their Acks but forgot to do so, to raise
their hands on this thread.


I forgot to add

Acked-by: Phillip Wood 

to my original reply in this thread, could you add it please

Thanks

Phillip

Thanks for starting the concluding move on this topic.

For reference, here is the CoC the patch wants to add (there is no
such topic yet locally, nor a single patch that can be made into
such a topic, so there isn't exactly something people can Ack on
yet. So here is a "preview" of what we would see once such a series
lands).

  CODE_OF_CONDUCT.md | 93 ++

# Git Code of Conduct

This code of conduct outlines our expectations for participants within
the Git community, as well as steps for reporting unacceptable behavior.
We are committed to providing a welcoming and inspiring community for
all and expect our code of conduct to be honored. Anyone who violates
this code of conduct may be banned from the community.

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, sex characteristics, gender identity and
expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
   advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
   address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
   professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies within all project spaces, and it also applies
when an individual is representing the project or its community in public
spaces. Examples of representing a project or community include using an
official project e-mail address, posting via an official social media account,
or acting as an appointed representative at an online or offline event.
Representation of a project may be further defined and clarified by project
maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at g...@sfconservancy.org. All
complaints will be reviewed and investigated and will result in a response
that is deemed necessary and appropriate to the circumstances. The project
team is obligated to maintain confidentiality with regard to the reporter of
an incident. Further details of specific enforcement policies may be posted
separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

The project leadership team can be contacted by email as a whole at
g...@sfconservancy.org, or individually:

   - Ævar Arnfjörð Bjarmason 
   - Christian Couder 
   - Jeff King 
   - Junio C Hamano 

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at 
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html


Re: [PATCH 1/1] commit: add support to provide --coauthor

2019-10-08 Thread Phillip Wood
On 08/10/2019 11:11, Phillip Wood wrote:
> Hi Toon & Zeger-Jan
> 
> On 08/10/2019 08:49, Toon Claes wrote:
>> Add support to provide the Co-author when committing. For each
>> co-author provided with --coauthor=, a line is added at the
>> bottom of the commit message, like this:
>>
>>  Co-authored-by: 
>>
>> It's a common practice use when pairing up with other people and both
>> authors want to in the commit message.
> 
> Thanks for the patch, it's looking good. I can see this being useful to
> some people - I like the way the patch itself is co-authored.
> [...]
>> @@ -803,6 +805,10 @@ static int prepare_to_commit(const char
>> *index_file, const char *prefix,
>>   if (clean_message_contents)
>>   strbuf_stripspace(&sb, 0);
>>
>> +    for (i = 0; i < coauthors.nr; i++) {
>> +    append_coauthor(&sb, coauthors.items[i].string);
> 
> If you look at the existing code that's calling append_signoff() it does
>   append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0)
> The purpose of ignore_non_trailer is to ignore comment and conflicts
> messages at the end of the commit message (there's more detail in a
> comment above it's definition in builtin/commit.c). I think we need to
> pass this offset when adding co-authors as well.
> 
> One question - what is the desired de-duplication behavior of
> Co-authored-by:? What happens if there is already a matching
> Co-authored-by: footer? (It is also possible for the trailers code to
> only ignore an existing footer if it's the last one.) What happens if
> the same Co-authored-by: is duplicated on the command line? It would be
> nice to have this defined and tests to check it's enforced.

I should give a bit more detail here. git-interpret-trailers gives more
control over handling of duplicates that is configurable via 'git
config' than 'commit --signoff' does. The reason for this is that
'commit --signoff' predates the interpret-trailers stuff. As we're
adding a new footer command we should decide if we want it to act like
--signoff or give the user the ability to configure the de-duplication
behavior by using the interpret-trailers code path instead. (I think
format-patch --signoff respects the interpret-trailers config variables
but 'am --signoff' and 'cherry-pick --signoff' do not.

> 
> Another useful addition would be to check that the footer value looks
> sane but that could come later

Looking at the way commit handles --author (grep for force_author in
builtin/commit.c) it should be simple to add these checks - just call
split_ident() and check it returns zero. --author also checks if the
string contains '<' and if it doesn't it uses the string given on the
command line to lookup a matching author in the commit log - that could
be a nice feature to use here too (see the code that calls
find_author_by_nickname()).

Best Wishes

Phillip

 - I don't think we do that for any other
> footers at the moment (though I haven't checked to see if that's really
> true)
> 
>> +    }
>> +
>>   if (signoff)
>>   append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
>>
>> @@ -1504,6 +1510,7 @@ int cmd_commit(int argc, const char **argv,
>> const char *prefix)
>>   OPT_STRING(0, "squash", &squash_message, N_("commit"),
>> N_("use autosquash formatted message to squash specified commit")),
>>   OPT_BOOL(0, "reset-author", &renew_authorship, N_("the
>> commit is authored by me now (used with -C/-c/--amend)")),
>>   OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
>> +    OPT_STRING_LIST(0, "coauthor", &coauthors, N_("co-author"),
>> N_("add Co-authored-by:")),
>>   OPT_FILENAME('t', "template", &template_file, N_("use
>> specified template file")),
>>   OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
>>   OPT_CLEANUP(&cleanup_arg),
>> diff --git a/sequencer.c b/sequencer.c
>> index d648aaf416..8958a22470 100644
>> --- a/sequencer.c
>> +++ b/sequencer.c
>> @@ -36,6 +36,7 @@
>>   #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
>>
>>   static const char sign_off_header[] = "Signed-off-by: ";
>> +static const char coauthor_header[] = "Co-authored-by: ";
>>   static const char cherry_picked_prefix[] = "(cherry picked from
>&g

Re: [PATCH 1/1] commit: add support to provide --coauthor

2019-10-08 Thread Phillip Wood
ader[] = "Signed-off-by: ";
+static const char coauthor_header[] = "Co-authored-by: ";
  static const char cherry_picked_prefix[] = "(cherry picked from commit ";

  GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
@@ -4385,15 +4386,9 @@ int sequencer_pick_revisions(struct repository *r,
return res;
  }

-void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
+static void append_footer(struct strbuf *msgbuf, struct strbuf* sob, size_t 
ignore_footer, size_t no_dup_sob)
  {
-   unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
-   struct strbuf sob = STRBUF_INIT;
-   int has_footer;
-
-   strbuf_addstr(&sob, sign_off_header);
-   strbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));
-   strbuf_addch(&sob, '\n');
+   size_t has_footer;

if (!ignore_footer)
strbuf_complete_line(msgbuf);
@@ -4402,11 +4397,11 @@ void append_signoff(struct strbuf *msgbuf, size_t 
ignore_footer, unsigned flag)
 * If the whole message buffer is equal to the sob, pretend that we
 * found a conforming footer with a matching sob
 */
-   if (msgbuf->len - ignore_footer == sob.len &&
-   !strncmp(msgbuf->buf, sob.buf, sob.len))
+   if (msgbuf->len - ignore_footer == sob->len &&
+   !strncmp(msgbuf->buf, sob->buf, sob->len))
has_footer = 3;
else
-   has_footer = has_conforming_footer(msgbuf, &sob, ignore_footer);
+   has_footer = has_conforming_footer(msgbuf, sob, ignore_footer);

if (!has_footer) {
const char *append_newlines = NULL;
@@ -4440,7 +4435,32 @@ void append_signoff(struct strbuf *msgbuf, size_t 
ignore_footer, unsigned flag)

if (has_footer != 3 && (!no_dup_sob || has_footer != 2))
strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0,
-   sob.buf, sob.len);
+   sob->buf, sob->len);
+}
+
+void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
+{
+   unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
+   struct strbuf sob = STRBUF_INIT;
+
+   strbuf_addstr(&sob, sign_off_header);
+   strbuf_addstr(&sob, fmt_name(WANT_COMMITTER_IDENT));
+   strbuf_addch(&sob, '\n');
+
+   append_footer(msgbuf, &sob, ignore_footer, no_dup_sob);
+
+   strbuf_release(&sob);
+}
+
+void append_coauthor(struct strbuf *msgbuf, const char *coauthor)
+{
+   struct strbuf sob = STRBUF_INIT;
+
+   strbuf_addstr(&sob, coauthor_header);
+   strbuf_addstr(&sob, coauthor);
+   strbuf_addch(&sob, '\n');
+
+   append_footer(msgbuf, &sob, 0, 1);


As we have a constant for APPEND_SIGNOFF_DEDUP can we use it here please 
rather than '1' which does not covey the same meaning to the author. 
Also as I said above I think you want to pass in a real value for 
ignore_footer not zero




strbuf_release(&sob);
  }
diff --git a/sequencer.h b/sequencer.h
index 574260f621..e36489fce7 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -170,6 +170,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list);
   */
  void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned 
flag);

+void append_coauthor(struct strbuf *msgbuf, const char* co_author);
+
  void append_conflicts_hint(struct index_state *istate,
struct strbuf *msgbuf, enum commit_msg_cleanup_mode 
cleanup_mode);
  enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh
index 14c92e4c25..5ed6735cf4 100755
--- a/t/t7502-commit-porcelain.sh
+++ b/t/t7502-commit-porcelain.sh
@@ -138,6 +138,17 @@ test_expect_success 'partial removal' '

  '

+test_expect_success 'co-author' '
+
+   >coauthor &&
+   git add coauthor &&
+   git commit -m "thank you" --co-author="Author " &&
+   git cat-file commit HEAD >commit.msg &&
+   sed -ne "s/Co-authored-by: //p" commit.msg >actual &&
+   echo "Author " >expected &&
+   test_cmp expected actual
+'


This is fine as far as it goes but it would be nice to test the 
de-duplication behavior once that's defined


Best Wishes

Phillip


  test_expect_success 'sign off' '

>positive &&
--
2.22.0.rc3



Re: What's cooking in git.git (Oct 2019, #01; Thu, 3)

2019-10-05 Thread Phillip Wood

Hi Elijah

On 05/10/2019 01:40, Elijah Newren wrote:

On Fri, Oct 4, 2019 at 4:49 AM Phillip Wood  wrote:


Hi Junio

On 03/10/2019 06:04, Junio C Hamano wrote:

Here are the topics that have been cooking.  Commits prefixed with
'-' are only in 'pu' (proposed updates) while commits prefixed with
'+' are in 'next'.  The ones marked with '.' do not appear in any of
the integration branches, but I am still holding onto them.
[...]


* pw/rebase-i-show-HEAD-to-reword (2019-08-19) 3 commits
   - sequencer: simplify root commit creation
   - rebase -i: check for updated todo after squash and reword
   - rebase -i: always update HEAD before rewording
   (this branch is used by ra/rebase-i-more-options.)

   "git rebase -i" showed a wrong HEAD while "reword" open the editor.

   Will merge to 'next'.


That's great, thanks



* ra/rebase-i-more-options (2019-09-09) 6 commits
   - rebase: add --reset-author-date
   - rebase -i: support --ignore-date
   - sequencer: rename amend_author to author_to_rename
   - rebase -i: support --committer-date-is-author-date
   - sequencer: allow callers of read_author_script() to ignore fields
   - rebase -i: add --ignore-whitespace flag
   (this branch uses pw/rebase-i-show-HEAD-to-reword.)

   "git rebase -i" learned a few options that are known by "git
   rebase" proper.

   Is this ready for 'next'.


Nearly, but not quite I think cf [1]. Also I'm still not convinced that
having different behaviors for --ignore-whitespace depending on the
backend is going to be helpful but maybe they are close enough not to
matter too much in practice [2].


Sorry I should have chimed in sooner; I can speak to the second point.
I would say that in practice it doesn't matter a lot; in most cases
the two overlap.  Both am's --ignore-whitespace and merge's
-Xignore-space-change are buggy (in different ways) and should be
fixed, but I'd consider them both to be buggy in edge cases.  I
recommended earlier this summer that Rohit submit the patches without
first attempting to fix apply or xdiff, and kept in my TODO list
that'd I'd go in and fix xdiff later if Rohit didn't have extra time
for it.  I did a little digging back then to find out the differences
and suggested some text to use to explain them and to argue that they
shouldn't block this feature:

"""
am's --ignore-space-change (an alias for am's --ignore-whitespace; see
git-apply's description of those two flags) not only share the same
name with diff's --ignore-space-change and merge's
-Xignore-space-change, but the similarity in naming appears to have
been intentional with am's --ignore-space-change and merge's
-Xignore-space-change being designed to have the same functionality
(see e.g. the commit messages for f008cef4abb2 ("Merge branch
'jc/apply-ignore-whitespace'", 2014-06-03) and 4e5dd044c62f
("merge-recursive: options to ignore whitespace changes",
2010-08-26)).  For the most part, these options do provide the same
behavior.  However, there are some edge cases where both apply's
--ignore-space-change and merge's -Xignore-space-change fall short of
optimal behavior, and in different ways.  In particular,
--ignore-space-change for apply will handle whitespace changes in the
context region but not in the region the other side modified, and
-Xignore-space-change will delete whitespace changes even when the
other side had no changes (thus treating both sides as unmodified).
Fixing these differences in edge cases is left for future work; this
patch simply wires interactive rebase to also understand
--ignore-whitespace by translating it to -Xignore-space-change.
"""

I've got another email with even more detail if folks need it.


Thanks for clarifying that, it sounds like it shouldn't be a problem in 
practice then (especially if you're planning some improvements)


Best Wishes

Phillip


Re: What's cooking in git.git (Oct 2019, #01; Thu, 3)

2019-10-04 Thread Phillip Wood

Hi Junio

On 03/10/2019 06:04, Junio C Hamano wrote:

Here are the topics that have been cooking.  Commits prefixed with
'-' are only in 'pu' (proposed updates) while commits prefixed with
'+' are in 'next'.  The ones marked with '.' do not appear in any of
the integration branches, but I am still holding onto them.
[...]


* pw/rebase-i-show-HEAD-to-reword (2019-08-19) 3 commits
  - sequencer: simplify root commit creation
  - rebase -i: check for updated todo after squash and reword
  - rebase -i: always update HEAD before rewording
  (this branch is used by ra/rebase-i-more-options.)

  "git rebase -i" showed a wrong HEAD while "reword" open the editor.

  Will merge to 'next'.


That's great, thanks



* ra/rebase-i-more-options (2019-09-09) 6 commits
  - rebase: add --reset-author-date
  - rebase -i: support --ignore-date
  - sequencer: rename amend_author to author_to_rename
  - rebase -i: support --committer-date-is-author-date
  - sequencer: allow callers of read_author_script() to ignore fields
  - rebase -i: add --ignore-whitespace flag
  (this branch uses pw/rebase-i-show-HEAD-to-reword.)

  "git rebase -i" learned a few options that are known by "git
  rebase" proper.

  Is this ready for 'next'.


Nearly, but not quite I think cf [1]. Also I'm still not convinced that 
having different behaviors for --ignore-whitespace depending on the 
backend is going to be helpful but maybe they are close enough not to 
matter too much in practice [2].


[1] 
https://public-inbox.org/git/20190806173638.17510-1-rohit.ashiwal...@gmail.com/T/#m965ce1f09d1d1b8010c04db0eabd4b19ce99fe82


[2] 
https://public-inbox.org/git/20190806173638.17510-1-rohit.ashiwal...@gmail.com/T/#m94e059c18b7bbcc721d12b190bd4aaecc5e8d591


Re: [PATCH v4 3/6] rebase -i: support --committer-date-is-author-date

2019-10-04 Thread Phillip Wood
thor_date)

+   options.flags |= REBASE_FORCE;
+
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
-   if (!strcmp(option, "--committer-date-is-author-date") ||
-   !strcmp(option, "--ignore-date") ||
+   if (!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
diff --git a/sequencer.c b/sequencer.c
index adeff2561e..fd925f2d72 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, 
"rebase-merge/refs-to-delete")
   * command-line.
   */
  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
  static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
  static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
  static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -879,6 +880,17 @@ static char *get_author(const char *message)
return NULL;
  }
  
+/* Returns a "date" string that needs to be free()'d by the caller */

+static char *read_author_date_or_null(void)
+{
+   char *date;
+
+   if (read_author_script(rebase_path_author_script(),
+  NULL, NULL, &date, 0))
+   return NULL;
+   return date;
+}
+
  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -938,6 +950,24 @@ static int run_git_commit(struct repository *r,
  
  	cmd.git_cmd = 1;
  
+if (opts->committer_date_is_author_date) {

+   int res = -1;
+   struct strbuf datebuf = STRBUF_INIT;
+   char *date = read_author_date_or_null();
+
+   if (!date)
+   return -1;
+
+   strbuf_addf(&datebuf, "@%s", date);
+   res = setenv("GIT_COMMITTER_DATE", datebuf.buf, 1);
+
+   strbuf_release(&datebuf);
+   free(date);
+
+   if (res)
+   return -1;
+}
+
if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
const char *gpg_opt = gpg_sign_opt_quoted(opts);
  
@@ -1331,7 +1361,6 @@ static int try_to_commit(struct repository *r,
  
  	if (parse_head(r, ¤t_head))

return -1;
-
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
@@ -1359,6 +1388,26 @@ static int try_to_commit(struct repository *r,
commit_list_insert(current_head, &parents);
}
  
+	if (opts->committer_date_is_author_date) {

+   int len = strlen(author);
+   struct ident_split ident;
+   struct strbuf date = STRBUF_INIT;
+
+   if (split_ident_line(&ident, author, len) < 0)
+   return error(_("malformed ident line"));


Here (and just below) we return if there is an error but later on we 
`goto out` should we be doing that here to clean something up?


Best Wishes

Phillip


+   if (!ident.date_begin)
+   return error(_("corrupted author without date 
information"));
+
+   strbuf_addf(&date, "@%.*s %.*s",
+   (int)(ident.date_end - ident.date_begin), 
ident.date_begin,
+   (int)(ident.tz_end - ident.tz_begin), 
ident.tz_begin);
+   res = setenv("GIT_COMMITTER_DATE", date.buf, 1);
+   strbuf_release(&date);
+
+   if (res)
+   goto out;
+   }
+
if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
@@ -2473,6 +2522,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}
  
+		if (file_exists(rebase_path_cdate_is_adate())) {

+   opts->allow_ff = 0;
+   opts->committer_date_is_author_date = 1;
+   }
+
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
  
@@ -2555,6 +2609,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,

write_file

Re: [PATCH v4 1/6] rebase -i: add --ignore-whitespace flag

2019-10-04 Thread Phillip Wood
t")),
-   OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
- NULL, N_("passed to 'git am'"),
- PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
  &options.git_am_opts, NULL,
  N_("passed to 'git am'"), PARSE_OPT_NOARG),
@@ -1417,6 +1426,8 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
  N_("passed to 'git am'"), PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
  N_("passed to 'git apply'"), 0),
+   OPT_BOOL(0, "ignore-whitespace", &options.ignore_whitespace,
+N_("ignore changes in whitespace")),
OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
  N_("action"), N_("passed to 'git apply'"), 0),
OPT_BIT('f', "force-rebase", &options.flags,
@@ -1834,6 +1845,9 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
}
  
  	if (options.rebase_merges) {

+   if (options.ignore_whitespace)
+   die(_("cannot combine '--rebase-merges' with "
+ "'--ignore-whitespace'"));


--rebase-merges now supports --strategy_option so we should fix this.


if (strategy_options.nr)
die(_("cannot combine '--rebase-merges' with "
  "'--strategy-option'"));
diff --git a/t/t3422-rebase-incompatible-options.sh 
b/t/t3422-rebase-incompatible-options.sh
index a5868ea152..4342f79eea 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -61,7 +61,6 @@ test_rebase_am_only () {
  }
  
  test_rebase_am_only --whitespace=fix

-test_rebase_am_only --ignore-whitespace
  test_rebase_am_only --committer-date-is-author-date
  test_rebase_am_only -C4
  
diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh

new file mode 100755
index 00..2e16e00a9d
--- /dev/null
+++ b/t/t3433-rebase-options-compatibility.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Rohit Ashiwal
+#
+
+test_description='tests to ensure compatibility between am and interactive 
backends'
+
+. ./test-lib.sh
+
+# This is a special case in which both am and interactive backends
+# provide the same output. 


I'm still concerned that we have to construct a special test case to get 
both backends to generate the same output. If this series is about 
supporting the behavior of the am backend in the sequencer then I'm 
worried that having the same option name have two different behaviors 
will create more problems than it solves. Do you have a feeling for how 
often the two backends give different results?


Best Wishes

Phillip

It was done intentionally because

+# both the backends fall short of optimal behaviour.
+test_expect_success 'setup' '
+   git checkout -b topic &&
+   q_to_tab >file <<-\EOF &&
+   line 1
+   Qline 2
+   line 3
+   EOF
+   git add file &&
+   git commit -m "add file" &&
+   cat >file <<-\EOF &&
+   line 1
+   new line 2
+   line 3
+   EOF
+   git commit -am "update file" &&
+   git tag side &&
+
+   git checkout --orphan master &&
+   sed -e "s/^|//" >file <<-\EOF &&
+   |line 1
+   |line 2
+   |line 3
+   EOF
+   git add file &&
+   git commit -m "add file" &&
+   git tag main
+'
+
+test_expect_success '--ignore-whitespace works with am backend' '
+   cat >expect <<-\EOF &&
+   line 1
+   new line 2
+   line 3
+   EOF
+   test_must_fail git rebase main side &&
+   git rebase --abort &&
+   git rebase --ignore-whitespace main side &&
+   test_cmp expect file
+'
+
+test_expect_success '--ignore-whitespace works with interactive backend' '
+   cat >expect <<-\EOF &&
+   line 1
+   new line 2
+   line 3
+   EOF
+   test_must_fail git rebase --merge main side &&
+   git rebase --abort &&
+   git rebase --merge --ignore-whitespace main side &&
+   test_cmp expect file
+'
+
+test_done



Re: [PATCH v1 4/5] rebase: fill `squash_onto' in get_replay_opts()

2019-10-02 Thread Phillip Wood

Hi Dscho

On 02/10/2019 09:16, Johannes Schindelin wrote:

Hi,

On Fri, 27 Sep 2019, Phillip Wood wrote:


Hi Alban

On 25/09/2019 21:13, Alban Gruin wrote:

>>> [...]

   builtin/rebase.c | 5 +
   1 file changed, 5 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index e8319d5946..2097d41edc 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -117,6 +117,11 @@ static struct replay_opts get_replay_opts(const struct
rebase_options *opts)
if (opts->strategy_opts)
 parse_strategy_opts(&replay, opts->strategy_opts);
   +if (opts->squash_onto) {


I guess it does not matter much, but shouldn't this be guarded against
the case where `replay.squash_onto` was already initialized? Like, `if
(opts->squash_onto && !replay.have_squash_onto)`?


replay is uninitialized as this function takes a `struct rebase_opitons` 
and returns a new `struct replay_options` based on that.


Best Wishes

Phillip



Other than that, this patch makes sense to me.

Ciao,
Dscho


+   oidcpy(&replay.squash_onto, opts->squash_onto);
+   replay.have_squash_onto = 1;
+   }
+
return replay;
   }







Re: [PATCH v1 0/5] Use complete_action’s todo list to do the rebase

2019-09-27 Thread Phillip Wood

Hi Alban

On 25/09/2019 21:13, Alban Gruin wrote:

This can be seen as a continuation of ag/reduce-rewriting-todo.

Currently, complete_action() releases its todo list before calling
sequencer_continue(), which reloads the todo list from the disk.  This
series removes this useless round trip.

Patches 1, 2, and 3 originally come from a series meaning to improve
rebase.missingCommitsCheck[0].  In the original series, I wanted to
check for missing commits in read_populate_todo(), so a warning could be
issued after a `rebase --continue' or an `exec' commands.  But, in the
case of the initial edit, it is already checked in complete_action(),
and would be checked a second time in sequencer_continue() (a caller of
read_populate_todo()).  So I hacked up sequencer_continue() to accept a
pointer to a todo list, and if not null, would skip the call to
read_populate_todo().  (This was really ugly, tbh.)  Some issues arose
with git-prompt.sh[1], hence 1, 2 and 3.

Patch 5 is a new approach to what I did first.  Instead of bolting a new
parameter to sequencer_continue(), this makes complete_action() calling
directly pick_commits().


Thanks for working on this, these patches all look fine to me modulo the 
confusing wording in the commit message on patch 4


Best Wishes

Phillip



This is based on master (4c86140027, "Third batch").

The tip of this series is tagged as "reduce-todo-list-cont-v1" at
https://github.com/agrn/git.

[0] http://public-inbox.org/git/20190717143918.7406-1-alban.gr...@gmail.com/
[1] http://public-inbox.org/git/1732521.CJWHkCQAay@andromeda/

Alban Gruin (5):
   sequencer: update `total_nr' when adding an item to a todo list
   sequencer: update `done_nr' when skipping commands in a todo list
   sequencer: move the code writing total_nr on the disk to a new
 function
   rebase: fill `squash_onto' in get_replay_opts()
   sequencer: directly call pick_commits() from complete_action()

  builtin/rebase.c |  5 +
  sequencer.c  | 26 ++
  2 files changed, 23 insertions(+), 8 deletions(-)



Re: [PATCH v1 4/5] rebase: fill `squash_onto' in get_replay_opts()

2019-09-27 Thread Phillip Wood

Hi Alban

On 25/09/2019 21:13, Alban Gruin wrote:

get_replay_opts() did not fill `squash_onto' if possible, meaning that


I'm not sure what you mean by 'if possible' here, I think the sentance 
makes sense without that.



this field should be read from the disk by the sequencer through
read_populate_opts().  Without this, calling `pick_commits()' directly
will result in incorrect results with `rebase --root'.

Let’s change that.


Good catch

Best Wishes

Phillip


Signed-off-by: Alban Gruin 
---
  builtin/rebase.c | 5 +
  1 file changed, 5 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index e8319d5946..2097d41edc 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -117,6 +117,11 @@ static struct replay_opts get_replay_opts(const struct 
rebase_options *opts)
if (opts->strategy_opts)
parse_strategy_opts(&replay, opts->strategy_opts);
  
+	if (opts->squash_onto) {

+   oidcpy(&replay.squash_onto, opts->squash_onto);
+   replay.have_squash_onto = 1;
+   }
+
return replay;
  }
  



Re: [PATCH v1 5/5] sequencer: directly call pick_commits() from complete_action()

2019-09-27 Thread Phillip Wood

Hi Alban

Thanks for removing some more unnecessary work reloading the the todo list.

On 25/09/2019 21:13, Alban Gruin wrote:

Currently, complete_action() calls sequencer_continue() to do the
rebase.  Even though the former already has the todo list, the latter
loads it from the disk and parses it.  Calling directly pick_commits()
from complete_action() avoids this unnecessary round trip.
Signed-off-by: Alban Gruin 
---
  sequencer.c | 8 +---
  1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index ec7ea8d9e5..b395dd6e11 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -5140,15 +5140,17 @@ int complete_action(struct repository *r, struct 
replay_opts *opts, unsigned fla
return error_errno(_("could not write '%s'"), todo_file);
}
  
-	todo_list_release(&new_todo);

-
if (checkout_onto(r, opts, onto_name, &oid, orig_head))
return -1;
  
  	if (require_clean_work_tree(r, "rebase", "", 1, 1))

return -1;
  
-	return sequencer_continue(r, opts);


sequencer_continue does a number of things before calling pick_commits(). It
 - calls read_and_refresh_cache() - this is unnecessary here as we've 
just called require_clean_work_tree()
 - calls read_populate_opts() - this is unnecessary as we're staring a 
new rebase so opts is fully populated
 - loads the todo list - this is unnecessary as we've just populated 
the todo list
 - commits any staged changes - this is unnecessary as we're staring a 
new rebase so there are no staged changes
 - calls record_in_rewritten() - this is unnecessary as we're starting 
a new rebase


So I agree that this patch is correct.

Thanks

Phillip


+   todo_list_write_total_nr(&new_todo);
+   res = pick_commits(r, &new_todo, opts);
+   todo_list_release(&new_todo);
+
+   return res;
  }
  
  struct subject2item_entry {




Re: [PATCH v4 5/6] rebase -i: support --ignore-date

2019-09-27 Thread Phillip Wood
-signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
+   if (opts->ignore_date)
+   write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
 
@@ -3536,6 +3584,8 @@ static int do_merge(struct repository *r,

argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
+   if (opts->ignore_date)
+   push_dates(&cmd);
 
 		/* Add the tips to be merged */

for (j = to_merge; j; j = j->next)
@@ -3809,7 +3859,8 @@ static int pick_commits(struct repository *r,
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit ||
-   opts->committer_date_is_author_date));
+   opts->committer_date_is_author_date ||
+   opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;
 
diff --git a/sequencer.h b/sequencer.h

index e3881e9275..bf5a79afdb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -44,6 +44,7 @@ struct replay_opts {
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;
+   int ignore_date;
 
 	int mainline;
 
diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh

index 6c1fbab4d8..0ad7bfc6a0 100755
--- a/t/t3433-rebase-options-compatibility.sh
+++ b/t/t3433-rebase-options-compatibility.sh
@@ -99,4 +99,39 @@ test_expect_success '--committer-date-is-author-date works 
with rebase -r' '
done  
+# Checking for + in author time is enough since default

+# timezone is UTC, but the timezone used while committing
+# sets to +0530.
+test_expect_success '--ignore-date works with am backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   git show HEAD --pretty="format:%ci" >committertime &&
+   grep "+" authortime &&
+   grep "+" committertime
+'
+
+test_expect_success '--ignore-date works with interactive backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date -i HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   git show HEAD --pretty="format:%ci" >committertime &&
+   grep "+" authortime &&
+   grep "+" committertime
+'
+
+test_expect_success '--ignore-date works with rebase -r' '
+   git checkout side &&
+   git merge commit3 &&
+   git rebase -r --root --ignore-date &&
+   git rev-list HEAD >rev_list &&
+   while read HASH
+   do
+   git show $HASH --pretty="format:%ai" >authortime
+   git show $HASH --pretty="format:%ci" >committertime
+   grep "+" authortime
+   grep "+" committertime
+   done 

It's good to see the new test. Did you see Stolee's email [4] about the 
test coverage of the previous version of this series? You should check 
that this series tests all the untested non-error handling lines.


[4] 
https://public-inbox.org/git/1ed86989-9ba2-0cd7-b6f7-654d1943b...@gmail.com/


Best Wishes

Phillip


 test_done





Re: [PATCH v2 00/19] hashmap bug/safety/ease-of-use fixes

2019-09-26 Thread Phillip Wood

Hi Eric

On 24/09/2019 02:03, Eric Wong wrote:

Patches 1-11 are largely unchanged from the original series with the
exception of 2, which is new and posted at:

https://public-inbox.org/git/20190908074953.kux7zz4y7iolqko4@whir/

12-17 take further steps to get us away from hashmap_entry being
the first element, but they're also a bit ugly because __typeof__
isn't portable

18-19 finally brings me to the APIs I want to expose without
relying on __typeof :)


Looking at the overall diff for this series looks a lot nicer with the 
extra patches that eliminate most of the explicit calls to 
container_of(). Thanks for the improved api and the cocci-check patch as 
well.


I've only had time for a quick look through but the patches seem well 
ordered and easy to follow. I think there are some line folding issues 
where you have wrapped a line when you added the type parameter and then 
removed it in a later path without re-flowing the line. Apart from that 
the only thing I noticed is that hashmap.h still starts with


  * struct long2string {
  * struct hashmap_entry ent; // must be the first member!

Is that still the case now that hashmap_{get,put,remove}_entry() use 
container_of() and hashmap_init() takes a struct hashmap_entry? That 
comment is in a lot of our structure definitions as well.


Best Wishes

Phillip


Apologies for the delays, been busy with other stuff...

Previous discussion starts at:

https://public-inbox.org/git/20190826024332.3403-...@80x24.org/

The following changes since commit 745f6812895b31c02b29bdfe4ae8e5498f776c26:

   First batch after Git 2.23 (2019-08-22 12:41:04 -0700)

are available in the Git repository at:

   https://80x24.org/git-svn.git hashmap-wip-v2

for you to fetch changes up to 212a596edd99169b284912b7b70b6280e2fb90e6:

   hashmap: remove type arg from hashmap_{get,put,remove}_entry (2019-09-24 
00:42:22 +)


Eric Wong (19):
   diff: use hashmap_entry_init on moved_entry.ent
   coccicheck: detect hashmap_entry.hash assignment
   packfile: use hashmap_entry in delta_base_cache_entry
   hashmap_entry_init takes "struct hashmap_entry *"
   hashmap_get_next takes "const struct hashmap_entry *"
   hashmap_add takes "struct hashmap_entry *"
   hashmap_get takes "const struct hashmap_entry *"
   hashmap_remove takes "const struct hashmap_entry *"
   hashmap_put takes "struct hashmap_entry *"
   introduce container_of macro
   hashmap_get_next returns "struct hashmap_entry *"
   hashmap: use *_entry APIs to wrap container_of
   hashmap_get{,_from_hash} return "struct hashmap_entry *"
   hashmap_cmp_fn takes hashmap_entry params
   hashmap: use *_entry APIs for iteration
   hashmap: hashmap_{put,remove} return hashmap_entry *
   hashmap: introduce hashmap_free_entries
   OFFSETOF_VAR macro to simplify hashmap iterators
   hashmap: remove type arg from hashmap_{get,put,remove}_entry

  attr.c  |  22 ++---
  blame.c |  25 +++---
  builtin/describe.c  |  21 +++--
  builtin/difftool.c  |  56 ++--
  builtin/fast-export.c   |  15 ++--
  builtin/fetch.c |  30 ---
  config.c|  24 +++---
  contrib/coccinelle/hashmap.cocci|  16 
  diff.c  |  31 ---
  diffcore-rename.c   |  15 ++--
  git-compat-util.h   |  33 
  hashmap.c   |  58 -
  hashmap.h   | 164 +---
  merge-recursive.c   |  87 ++-
  name-hash.c |  57 +++--
  oidmap.c|  20 +++--
  oidmap.h|   6 +-
  packfile.c  |  22 +++--
  patch-ids.c |  18 ++--
  range-diff.c|  10 +--
  ref-filter.c|  31 ---
  refs.c  |  23 +++--
  remote.c|  21 +++--
  revision.c  |  28 +++---
  sequencer.c |  44 ++
  sub-process.c   |  20 +++--
  sub-process.h   |   4 +-
  submodule-config.c  |  52 +++-
  t/helper/test-hashmap.c |  49 ++-
  t/helper/test-lazy-init-name-hash.c |  12 +--
  30 files changed, 647 insertions(+), 367 deletions(-)
  create mode 100644 contrib/coccinelle/hashmap.cocci

Eric Wong (19):
   diff: use hashmap_entry_init on moved_entry.ent
   coccicheck: detect hashmap_entry.hash assignment
   packfile: use hashmap_entry in delta_base_cache_ent

Re: [PATCH] add a Code of Conduct document

2019-09-24 Thread Phillip Wood

Hi Gábor

On 24/09/2019 10:01, SZEDER Gábor wrote:

On Tue, Sep 24, 2019 at 02:44:54AM -0400, Jeff King wrote:

[...]

After some poking around at various CoC options, this one seemed like
the best fit to me. But I'm open to suggestions or more discussion. It
seems to me that the important piece is having _some_ CoC, and picking
something standard-ish seems a safe bet.


We are decent people, and know how to behave properly and treat each
other with respect.  It is my fundamental assumption that all future
contributors are decent and respectful human beings as well.


History suggests that almost all will be decent but there will be one or 
two who aren't and cause trouble.



A CoC
like this, which is "explicit about the behavior we want to model"
(quoting the original discussion starter) inherently insinuates that
we aren't decent, and can't behave without being told how to do so.
Frankly, I find this borderline insulting to me, to my parents, to all
fellow contributors, and to future contributors as well.


I don't find it insulting, to me it just sets out that the project 
welcomes contributors who behave decently.



There are locations, nationalities and cultures, where the avarage
wide-spread CoCs, like Contributor Covenant and its derivatives, are
perceived as (paraphrasing) too "American", politically overcorrect,
corporate BS, etc., which are forced upon open-source projects.
Consequently, such CoCs are often found rather discouraging, and
announcements about their adoption in open-source projects generally
get negative reaction.

Less is more.  Much-much more.  A concise CoC that treats its readers
as responsible, well-behaved human beings is met with much approval.


I was pleasantly surprised at how short the proposed CoC is, I don't 
think it's too long at all. It only takes a couple of minutes to read 
and is quite clear.


Best Wishes

Phillip



Take, for example, the TrueOS Rules of Conduct, which in just a few
short sentences covers everything that's worth covering:

   https://www.trueos.org/rulesofconduct/

If diversity and inclusion of other cultures is indeed a priority,
then we should carefully consider that some potential contributors
will rather choose not to contribute because of a CoC like this.



If people are on board with this direction, it might be fun to pick up a
bunch of "Acked-by" trailers from people in the community who agree with
it. It might give it more weight if many members have publicly endorsed
it.


Because of the above I'm leaning towards NACK.



Re: [PATCH] add a Code of Conduct document

2019-09-24 Thread Phillip Wood

Hi Peff

On 24/09/2019 07:44, Jeff King wrote:

We've never had a formally written Code of Conduct document. Though it
has been discussed off and on over the years, for the most part the
behavior on the mailing list has been good enough that nobody felt the
need to push one forward.

However, even if there aren't specific problems now, it's a good idea to
have a document:

   - it puts everybody on the same page with respect to expectations.
 This might avoid poor behavior, but also makes it easier to handle
 it if it does happen.

   - it publicly advertises that good conduct is important to us and will
 be enforced, which may make some people more comfortable with
 joining our community

   - it may be a good time to cement our expectations when things are
 quiet, since it gives everybody some distance rather than focusing
 on a current contentious issue


I think these are all good points, it is definitely better to discuss 
this when there isn't a pressing problem to resolve.



This patch adapts the Contributor Covenant Code of Conduct. As opposed
to writing our own from scratch, this uses common and well-accepted
language, and strikes a good balance between illustrating expectations
and avoiding a laundry list of behaviors. It's also the same document
used by the Git for Windows project.

The text is taken mostly verbatim from:

   https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

I also stole a very nice introductory paragraph from the Git for Windows
version of the file.


Using an existing text makes sense, even more so if it is being 
successfully used by git for windows




There are a few subtle points, though:

   - the document refers to "the project maintainers". For the code, we
 generally only consider there to be one maintainer: Junio C Hamano.
 But for dealing with community issues, it makes sense to involve
 more people to spread the responsibility. I've listed the project
 committee address of g...@sfconservancy.org as the contact point.

   - the document mentions banning from the community, both in the intro
 paragraph and in "Our Responsibilities". The exact mechanism here is
 left vague. I can imagine it might start with social enforcement
 (not accepting patches, ignoring emails) and could escalate to
 technical measures if necessary (asking vger admins to block an
 address). It probably make sense _not_ to get too specific at this
 point, and deal with specifics as they come up.


I think this is a sensible approach - it needs to be clear that there is 
a mechanism to deal with violations otherwise there's no point to having 
a CoC but we don't want to get bogged down by a whole sequence of what 
if someone does this that or the other.


I think the text below does a good job of setting out expectations 
without being too long


Best Wishes

Phillip


Signed-off-by: Jeff King 
---
Obviously related to the discussion in:

   https://public-inbox.org/git/71fba9e7-6314-6ef9-9959-6ae06843d...@gmail.com/

After some poking around at various CoC options, this one seemed like
the best fit to me. But I'm open to suggestions or more discussion. It
seems to me that the important piece is having _some_ CoC, and picking
something standard-ish seems a safe bet.

I did find this nice set of guidelines in an old discussion:

   
https://github.com/mhagger/git/commit/c6e6196be8fab3d48b12c4e42eceae6937538dee

I think it's missing some things that are "standard" in more modern CoCs
(in particular, there's not much discussion of enforcement or
responsibilities, and I think those are important for the "making people
comfortable" goal). But maybe there are bits we'd like to pick out for
other documents; not so much "_what_ we expect" as "here are some tips
on _how_".

If people are on board with this direction, it might be fun to pick up a
bunch of "Acked-by" trailers from people in the community who agree with
it. It might give it more weight if many members have publicly endorsed
it.

I've cc'd g...@sfconservancy.org here, because I think it's important for
all of the project committee members to endorse it (and because the
document puts us on the hook for enforcing it!).

  CODE_OF_CONDUCT.md | 85 ++
  1 file changed, 85 insertions(+)
  create mode 100644 CODE_OF_CONDUCT.md

diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00..b94f72b0b8
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,85 @@
+# Git Code of Conduct
+
+This code of conduct outlines our expectations for participants within
+the Git community, as well as steps for reporting unacceptable behavior.
+We are committed to providing a welcoming and inspiring community for
+all and expect our code of conduct to be honored. A

Re: [PATCH 0/1] git-config --add allows values from stdin

2019-09-23 Thread Phillip Wood

Hi Taylor and ZJ

On 22/09/2019 04:11, Taylor Blau wrote:

Hi ZJ,

On Tue, Sep 17, 2019 at 03:31:34PM +0200, Zeger-Jan van de Weg wrote:

When adding or updating configuration values using git-config, the
values could all be observed by different processes as these are passed
as arguments. In some environments all commands executed are also all
logged. When the value contains secrets, this is a side effect that
would be great to avoid.


How much extra security does this actually add? - do the processes that 
can observe the command line arguments also have read access to the git 
config file?


 At GitLab we use Rugged/libgit2 to circumvent

this property[1].

The following patch allows a value to be set through stdin when the user
passes a `--stdin` flag.


Interesting. I had thought some time ago about making an interactive
line-oriented 'mode' for using 'git-config(1)', which would allow
callers to add/delete/fetch multiple variables using only a single
process.

This would satisfy a more general use-case than yours: particularly my
idea was grown out of wanting to specify or read many configuration
entries at once when using a tool built around Git, such as Git LFS.

I had not considered tying '--stdin' to the '--add' (implicit or not)
mode of 'git-config(1)'. It is an interesting idea to be sure.

On the one hand, it lends itself to other modes, such as '--get'
combined with '--stdin', or '--unset' in the same fashion. One could
imagine that each of these would take either a key/value-pair (in the
case of '--add') or a set of key(s) (in the remaining cases). The most
desirable aspect is that this would allow for a clear path to this
series being picked up.


It would be great to be able to --get multiple values and I can see 
people wanting to be able to --unset them as well.



On the other hand, tying '--stdin' to a particular mode of using 'git
conifg' seems overly restrictive to me. If I am building a tool that
wants to fetch some values in the configuration, and then add/unset
others based on the results using only a single process, I don't think
that a mode-based '--stdin' flag gets the job done.


That's true but I don't know how common it is compared to a script 
wanting to read a bunch of config variables at startup (i.e. does it 
warrant the extra complexity)


Best Wishes

Phillip


One happy medium that comes to mind is a new '--interactive' mode, which
implies '--stdin' and would allow the above use-case, e.g.:

   $ git config --interactive <<\EOF
   get core.myval
   set core.foo bar
   unset core.baz
   EOF

(An off-topic note is that it would be interesting to allow more
fanciful options than 'get', e.g., 'get' with a '--type' specifier, or
some such).

I'm not sure if anyone actually wants to use 'git-config(1)' in this
way, but I figured that I would at least share some things that I was
thinking about when initially considering this proposal.


[1]: 
https://gitlab.com/gitlab-org/gitaly/blob/8ab5bd595984678838f3f09a96798b149e68a939/ruby/lib/gitlab/git/http_auth.rb#L14-15

Zeger-Jan van de Weg (1):
   Git config allows value setting from stdin

  Documentation/git-config.txt |  5 -
  builtin/config.c | 23 +--
  t/t1300-config.sh| 11 +++
  3 files changed, 36 insertions(+), 3 deletions(-)

--
2.23.0



Thanks,
Taylor



Re: [PATCH v2] rebase: introduce --update-branches option

2019-09-23 Thread Phillip Wood

Hi

On 09/09/2019 15:13, Johannes Schindelin wrote:

Hi,

On Mon, 9 Sep 2019, Phillip Wood wrote:


On 08/09/2019 00:44, Warren He wrote:

Everyone in this thread, thanks for your support and encouragement.
[...]

It should not really imply `--interactive`, but `--rebase-merges`.


`imply_interactive` doesn't fully switch on `--interactive`, i.e., causing
the
editor to open. It only selects the backend, which I think we're saying is
the
right thing. I've dropped the `-i` from the test description.

And we don't really have to imply --rebase-merges, in case someone would
prefer
to linearize things, which who knows? Running that non-rebase-merges command
in
the example scenario from my original post should give something like this:


I think it would probably be less confusing to default to preserving merges


s/preserving/rebasing/?


and having an option to turn that off - people are going to be surprised if
their history is linearized.


I don't think it makes any sense to linearize the history while updating
branches, as the commits will be all jumbled up. Imagine this history:

- A - B - C - D -
\   /
  E - F

Typically, it does not elicit any "bug" reports, but this can easily be
linearized to

- A' - B' - E' - C' - F' -

In my mind, it makes no sense to update any local branches that pointed
to C and F to point to C' and F', respectively.



I agree


[...]

* * *

And then there's the discussion about using `exec git branch -f`. To
summarize
the issues collected from the entire thread:

1. the changes aren't atomically applied at the end of the rebase
2. it fails when the branch is checked out in a worktree
3. it clobbers the branch if anything else updates it during the rebase
4. the way we prepare the unprefixed branch doesn't work right some exotic
cases
5. the reflog message it leaves is uninformative

For #4, I think we've lucked out actually. The `load_ref_decorations`
routine we
use determines that a ref is `DECORATION_REF_LOCAL` under the condition
`starts_with(refname, "refs/heads/")` (log-tree.c:114, add_ref_decoration),
so
`prettify_refname` will find the prefix and skip it. But that's an invariant
maintained by two pieces of code pretty far away from each other.

For #5, for the convenience of readers, the reflog entry it leaves looks
like this:

```
00873f2 feat-e@{0}: branch: Reset to HEAD
```

Not great.

I haven't made any changes to this yet, but I've thought about what I want.
My
favorite so far is to add a new todo command that just does everything
right. It
would make a temparary ref `refs/rewritten-heads/xxx` (or something), and
update
`refs/heads/xxx` at the end.


I think that's the best way to do it. If we had a command like 'branch
' that creates a ref to remember the current HEAD and saves the
current branch head. Then at the end rebase can update the branches to point
to the saved commits if the branch is unchanged. If the rebase is aborted then
we don't end up with some branches updated and others not.


I'd avoid cluttering the space with more commands. For `branch`, for
example, the natural short command would be `b`, but that already means
`break`.


We could just not have a short name, after all --update-branch is hardly 
a short alternative




In contrast, I would think that

label --update-branch my-side-track

would make for a nicer read than

label my-side-track
branch my-side-track


I agree it would be nice to do both on a single line, my argument was 
mainly against using 'exec branch ...' so that we can defer the branch 
updates until the very end of the rebase. The branch command could set a 
label as well or we could add an option to label I'm not that bothered 
either way at the moment. Another possibility which we probably don't 
want is to have labels starting refs/ imply --update-branch



Of course, it would be a lot harder to bring back the safety of `git
update-ref`'s `` safe-guard, in either forms.


Is it that difficult to write the current branch HEAD to a file when we 
label it and then read those back at the end when we update the refs? or 
are you thinking of calling 'git branch' instead of 
ref_transaction_update()? I'm not sure what the advantage of 'git 
branch' is though.


Best Wishes

Phillip



And of course, the first form would _require_ the logic to be moved to
`make_script_with_merges()` because we could not otherwise guarantee
that the labels corresponding to local branch names aren't already in
use, for different commits.


Side Note
   I'd avoid creating another worktree local ref refs/rewritten-heads/.
   Either store them under refs/rewritten/ or refs/worktree/


Yep.

Ciao,
Dscho



Re: [PATCH] name-rev: avoid cutoff timestamp underflow

2019-09-23 Thread Phillip Wood

On 23/09/2019 09:37, SZEDER Gábor wrote:

On Sun, Sep 22, 2019 at 11:01:26PM +0200, Johannes Sixt wrote:

Am 22.09.19 um 21:53 schrieb SZEDER Gábor:

On Sun, Sep 22, 2019 at 07:57:36PM +0100, Phillip Wood wrote:

On 22/09/2019 19:01, SZEDER Gábor wrote:

+/*
+ * One day.  See the 'name a rev close to epoch' test in t6120 when
+ * changing this value
+ */
+#define CUTOFF_DATE_SLOP 86400
  typedef struct rev_name {
const char *tip_name;
@@ -481,8 +485,13 @@ int cmd_name_rev(int argc, const char **argv, const char 
*prefix)
add_object_array(object, *argv, &revs);
}
-   if (cutoff)
-   cutoff = cutoff - CUTOFF_DATE_SLOP;
+   if (cutoff) {
+   /* check for undeflow */
+   if (cutoff - CUTOFF_DATE_SLOP < cutoff)


Nice catch but wouldn't this be clearer as
   if (cutoff > CUTOFF_DATE_SLOP) ?


It would only be clearer now, with an unsigned 'timestamp_t'.  I
tried to future-proof for a signed 'timestamp_t' and a cutoff date
before the UNIX epoch.


Huh? For signed cutoff and positive CUTOFF_DATE_SLOP,
cutoff - CUTOFF_DATE_SLOP < cutoff is ALWAYS true. Signed interger
underflow is undefined behavior and signed integer arithmetic does not
wrap around!

IOW, the new condition makes only sense today, because cutoff is an
unsigned type, but breaks down should we switch to a signed type.


Yeah, that's what I meant with worrying about signed underflow in the
commit message.  As long as the cutoff is at least a day later than
the minimum value of our future signed 'timestamp_t', the condition
does the right thing.  And considering that oldest time a signed 64
bit timestamp can represent far exceeds the age of the universe, and
the oldest value of even a signed 32 bit timestamp is almost half the
age of the Earth, I wasn't too worried.



It's still going to trip up static analysers though isn't it? Also it 
will confuse readers who have to reason that it does not overflow in 
practice as we (probably?) never use very negative values


Best Wishes

Phillip


You need this on top:

diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index a4d8d312ab..2d83c2b172 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -487,10 +487,10 @@ int cmd_name_rev(int argc, const char **argv, const char 
*prefix)
  
  	if (cutoff) {

/* check for undeflow */
-   if (cutoff - CUTOFF_DATE_SLOP < cutoff)
+   if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
cutoff = cutoff - CUTOFF_DATE_SLOP;
else
-   cutoff = 0;
+   cutoff = TIME_MIN;
}
for_each_ref(name_ref, &data);
  
diff --git a/git-compat-util.h b/git-compat-util.h

index c68c61d07c..1bdc21a069 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -344,6 +344,7 @@ typedef uintmax_t timestamp_t;
  #define PRItime PRIuMAX
  #define parse_timestamp strtoumax
  #define TIME_MAX UINTMAX_MAX
+#define TIME_MIN 0
  
  #ifndef PATH_SEP

  #define PATH_SEP ':'


Re: [PATCH] name-rev: avoid cutoff timestamp underflow

2019-09-22 Thread Phillip Wood

Hi Gábor

On 22/09/2019 19:01, SZEDER Gábor wrote:

When 'git name-rev' is invoked with commit-ish parameters, it tries to
save some work, and doesn't visit commits older than the committer
date of the oldest given commit minus a one day worth of slop.  Since
our 'timestamp_t' is an unsigned type, this leads to a timestamp
underflow when the committer date of the oldest given commit is within
a day of the UNIX epoch.  As a result the cutoff timestamp ends up
far-far in the future, and 'git name-rev' doesn't visit any commits,
and names each given commit as 'undefined'.

Check whether substacting the slop from the oldest committer date
would lead to an underflow, and use a 0 as cutoff in that case.  This
way it will handle commits shortly after the epoch even if we were to
switch to a signed 'timestamp_t' (but then we'll have to worry about
signed underflow for very old commits).

Note that the type of the cutoff timestamp variable used to be signed
before 5589e87fd8 (name-rev: change a "long" variable to timestamp_t,
2017-05-20).  The behavior was still the same even back then, but the
underflow didn't happen when substracting the slop from the oldest
committer date, but when comparing the signed cutoff timestamp with
unsigned committer dates in name_rev().  IOW, this underflow bug is as
old as 'git name-rev' itself.

Signed-off-by: SZEDER Gábor 
---

This patch adds a test at the end of 't6120-describe.sh', so it will
conflict with my non-recursive name-rev patch series, which adds a
test there as well, but the conflict should be wasy to resolve.

   https://public-inbox.org/git/20190919214712.7348-7-szeder@gmail.com/

  builtin/name-rev.c  | 15 ---
  t/t6120-describe.sh | 15 +++
  2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index c785fe16ba..a4d8d312ab 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -9,7 +9,11 @@
  #include "sha1-lookup.h"
  #include "commit-slab.h"
  
-#define CUTOFF_DATE_SLOP 86400 /* one day */

+/*
+ * One day.  See the 'name a rev close to epoch' test in t6120 when
+ * changing this value
+ */
+#define CUTOFF_DATE_SLOP 86400
  
  typedef struct rev_name {

const char *tip_name;
@@ -481,8 +485,13 @@ int cmd_name_rev(int argc, const char **argv, const char 
*prefix)
add_object_array(object, *argv, &revs);
}
  
-	if (cutoff)

-   cutoff = cutoff - CUTOFF_DATE_SLOP;
+   if (cutoff) {
+   /* check for undeflow */
+   if (cutoff - CUTOFF_DATE_SLOP < cutoff)


Nice catch but wouldn't this be clearer as
  if (cutoff > CUTOFF_DATE_SLOP) ?

Best Wishes

Phillip

+   cutoff = cutoff - CUTOFF_DATE_SLOP;
+   else
+   cutoff = 0;
+   }
for_each_ref(name_ref, &data);
  
  	if (transform_stdin) {

diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 2b883d8174..965e633c32 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -424,4 +424,19 @@ test_expect_success 'describe complains about missing 
object' '
test_must_fail git describe $ZERO_OID
  '
  
+test_expect_success 'name-rev a rev shortly after epoch' '

+   test_when_finished "git checkout master" &&
+
+   git checkout --orphan no-timestamp-underflow &&
+   # Any date closer to epoch than the CUTOFF_DATE_SLOP constant
+   # in builtin/name-rev.c.
+   GIT_COMMITTER_DATE="@1234 +" \
+   git commit -m "committer date shortly after epoch" &&
+   near_commit_oid=$(git rev-parse HEAD) &&
+
+   echo "$near_commit_oid no-timestamp-underflow" >expect &&
+   git name-rev $near_commit_oid >actual &&
+   test_cmp expect actual
+'
+
  test_done



Re: [PATCH v4 0/6] rebase -i: support more options

2019-09-09 Thread Phillip Wood

On 09/09/2019 19:02, Junio C Hamano wrote:

Rohit Ashiwal  writes:


Following the suggestion of Phillip I've rebased my patch on master (745f681289)
and cherry-picking b0a3186140.


Sorry, but that's horrible.  The latter does not even cleanly apply
on the former.


Yes I had assumed that the cherry pick would become the first patch of 
this series and be dropped from pw/rebase-i-show-HEAD-to-reword. I 
should have been more explicit about that.



Let me see if I can find time to whip this into a reasonable shape.


As pw/rebase-i-show-HEAD-to-reword is slated for next perhaps these 
could build on that. The first patch needs am -3 to apply to that branch 
but the result looks ok and the rest apply as is.


Best Wishes

Phillip


Thanks.



Re: [PATCH v2] rebase: introduce --update-branches option

2019-09-09 Thread Phillip Wood

Hi Warren

On 08/09/2019 00:44, Warren He wrote:

Everyone in this thread, thanks for your support and encouragement.
[...]

It should not really imply `--interactive`, but `--rebase-merges`.


`imply_interactive` doesn't fully switch on `--interactive`, i.e., causing the
editor to open. It only selects the backend, which I think we're saying is the
right thing. I've dropped the `-i` from the test description.

And we don't really have to imply --rebase-merges, in case someone would prefer
to linearize things, which who knows? Running that non-rebase-merges command in
the example scenario from my original post should give something like this:


I think it would probably be less confusing to default to preserving 
merges and having an option to turn that off - people are going to be 
surprised if their history is linearized.



```
  A - B  (master)
\
  F  (feat-f)
\
  E  (feat-e)
\
  H  (my-dev)
```

So for now I haven't moved the implementation into `make_script_with_merges`.


> [...]>

[handling `fixup`/`squash` chains]


I've moved `todo_list_add_branch_updates` to run before
`todo_list_rearrange_squash`. The rearranging pulls fixups out, causing the
branch update to "fall" onto the items before, and reinserts them between a
commit and its branch update, casing them to be included in the updated branch.
which is my opinion of the right thing to do. I've added a test about this with
the following scenario:

```
  A - B  (master)
\
  I - J - fixup! I (fixup-early)
  \
K - fixup! J  (fixup-late)
```

which results in the following todo list with `--autosquash`:

```
pick 9eadc32 I
fixup 265fa32 fixup! I
pick a0754fc J
fixup e7d1999 fixup! J
exec git branch -f fixup-early
pick c8bc4af K
```


That makes sense I think


I'd like to suggest [`test_cmp_rev`] instead


I've updated the test to use `test_cmp_rev`. It's not with your suggested
invocation though. We don't update the `C` tag. I've referred to the rebased `C`
with `test_cmp_rev linear-early HEAD^` and similar for the other checks.


That sounds right


* * *

And then there's the discussion about using `exec git branch -f`. To summarize
the issues collected from the entire thread:

1. the changes aren't atomically applied at the end of the rebase
2. it fails when the branch is checked out in a worktree
3. it clobbers the branch if anything else updates it during the rebase
4. the way we prepare the unprefixed branch doesn't work right some exotic cases
5. the reflog message it leaves is uninformative

For #4, I think we've lucked out actually. The `load_ref_decorations` routine we
use determines that a ref is `DECORATION_REF_LOCAL` under the condition
`starts_with(refname, "refs/heads/")` (log-tree.c:114, add_ref_decoration), so
`prettify_refname` will find the prefix and skip it. But that's an invariant
maintained by two pieces of code pretty far away from each other.

For #5, for the convenience of readers, the reflog entry it leaves looks like 
this:

```
00873f2 feat-e@{0}: branch: Reset to HEAD
```

Not great.

I haven't made any changes to this yet, but I've thought about what I want. My
favorite so far is to add a new todo command that just does everything right. It
would make a temparary ref `refs/rewritten-heads/xxx` (or something), and update
`refs/heads/xxx` at the end.


I think that's the best way to do it. If we had a command like 'branch 
' that creates a ref to remember the current HEAD and saves 
the current branch head. Then at the end rebase can update the branches 
to point to the saved commits if the branch is unchanged. If the rebase 
is aborted then we don't end up with some branches updated and others not.


Side Note
  I'd avoid creating another worktree local ref refs/rewritten-heads/.
  Either store them under refs/rewritten/ or refs/worktree/

Best Wishes

Phillip



I agree that requiring a separate update-ref step at the end of the todo list is
unfriendly. Manually putting in some branch update commands and then realizing
that they weren't applied would be extremely frustrating. I don't see the option
of using existing tools as the easiest-to-use solution.

I'm reluctant to combine this with the existing `label` command. So far it
sounds like we generally want to be more willing to skip branch updates while
performing the rebase, with aforementioned scenarios where something else
updates the branch before we do, or if the branch becomes checked out in a
worktree. We don't want to mess up the structure of a `rebase -r` as a result of
skipping some branch updates. I think it would be conceptually simpler and
implementation-wise less tricky if we didn't combine it with the `label

Re: [PATCH] rebase: introduce --update-branches option

2019-09-03 Thread Phillip Wood

Hi Warren

On 03/09/2019 00:41, Warren He wrote:

Sometimes people have to rebase multiple related branches. One way to do that
quickly, when there are branches pointing to ancestors of a later branch (which
happens a lot if you try hard to pad your PR count on GitHub--I mean if you try
to make small, logically separate changes), is to rebase that later branch and
then reset ancestor branches to the rewritten commits. You just have to work
out which branches correspond to which of the new commits.

Here's an automated way to update those ancestor branches.


I think this would be really useful, but as it is implemented here it 
only updates branch heads that are in the todo list. This means that if 
I have a branch structure like


A - B (master)
|
C - E (topic-2)
|
D (topic-1)

and I do `git rebase --update-branches master topic1` Then topic-2 will 
not be updated and if I do `git rebase --update-branches master topic2` 
then topic-1 will not be updated even though C is updated in both cases 
and is a common ancestor of topic-1 and topic-2. Conceptually to update 
all the branches descended from a rewritten commit would require using 
`git for-each-ref --contains $(git merge-base  )` and 
then using `git rev-list ..` on each of those 
refs to get the commits to generate the todo list.


Another case is applying fixup commits. In the example above if I squash 
a fixup for C from either branch I probably want to update both the 
branches descended from it.


One other thing is that if the user aborts the rebase then ideally we 
don't want to update all the branches so it would be better to store the 
updated heads as we go along and then update them all at the end of the 
rebase. Worktrees add another complication as if one of the branches 
that is to be updated is checked out in another worktree then we need 
some way to deal with that. If there are no local changes in that 
worktree then we could just update the local HEAD and working copy.


Best Wishes

Phillip



It's implemented as a function that processes a todo list, modeled after
`todo_list_add_exec_commands`. Currently steps are added as `exec git branch -f
`, which comes with the caveat that they're not applied atomically
when it finishes rebasing.

If you were to use this feature to rebase `my-dev` onto `master` in this
situation:

```
  A - B  (master)
   |\
   |  E  (feat-e)
\   \
  F  |   (feat-f)
\|
  G  (interim)
\
  H  (my-dev)
```

you'd get a todo list like this:

```
label onto

# Branch G
reset onto
pick 65945ab E
exec git branch -f feat-e
label G

reset onto
pick 4f0b0ad F
exec git branch -f feat-f
merge -C e50066c G # G
exec git branch -f interim
pick 539e556 H
```

Warren He (1):
   rebase: introduce --update-branches option

  Documentation/git-rebase.txt  |  8 +
  builtin/rebase.c  | 13 ++--
  sequencer.c   | 68 ++-
  sequencer.h   |  6 ++--
  t/t3431-rebase-update-branches.sh | 64 
  5 files changed, 154 insertions(+), 5 deletions(-)
  create mode 100755 t/t3431-rebase-update-branches.sh



Re: [PATCH 1/1] rebase -r: let `label` generate safer labels

2019-09-02 Thread Phillip Wood

Hi Matt

This is definitely worth fixing, I've got a couple of comments below

On 02/09/2019 15:01, Matt R via GitGitGadget wrote:

From: Matt R 

The `label` todo command in interactive rebases creates temporary refs
in the `refs/rewritten/` namespace. These refs are stored as loose refs,
i.e. as files in `.git/refs/rewritten/`, therefore they have to conform
with file name limitations on the current filesystem.

This poses a problem in particular on NTFS/FAT, where e.g. the colon
character is not a valid part of a file name.


Being picking I'll point out that ':' is not a valid in refs either. 
Looking at 
https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file I 
think only " and | are not allowed on NTFS/FAT but are valid in refs 
(see the man page for git check-ref-format for all the details). So the 
main limitation is actually what git allows in refs.



Let's safeguard against this by replacing not only white-space
characters by dashes, but all non-alpha-numeric ones.

However, we exempt non-ASCII UTF-8 characters from that, as it should be
quite possible to reflect branch names such as `↯↯↯` in refs/file names.

Signed-off-by: Matthew Rogers 
Signed-off-by: Johannes Schindelin 
---
  sequencer.c  | 12 +++-
  t/t3430-rebase-merges.sh |  5 +
  2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/sequencer.c b/sequencer.c
index 34ebf8ed94..23f4a0876a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -4635,8 +4635,18 @@ static int make_script_with_merges(struct 
pretty_print_context *pp,
else
strbuf_addbuf(&label, &oneline);
  
+		/*

+* Sanitize labels by replacing non-alpha-numeric characters
+* (including white-space ones) by dashes, as they might be
+* illegal in file names (and hence in ref names).
+*
+* Note that we retain non-ASCII UTF-8 characters (identified
+* via the most significant bit). They should be all acceptable
+* in file names. We do not validate the UTF-8 here, that's not
+* the job of this function.
+*/
for (p1 = label.buf; *p1; p1++)
-   if (isspace(*p1))
+   if (!(*p1 & 0x80) && !isalnum(*p1))
*(char *)p1 = '-';


I'm sightly concerned that this opens the possibility for unexpected 
effects if two different labels get sanitized to the same string. I 
suspect it's unlikely to happen in practice but doing something like 
percent encoding non-alphanumeric characters would avoid the problem 
entirely.


Best Wishes

Phillip


strbuf_reset(&buf);
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 7b6c4847ad..737396f944 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -441,4 +441,9 @@ test_expect_success '--continue after resolving conflicts 
after a merge' '
test_path_is_missing .git/MERGE_HEAD
  '
  
+test_expect_success '--rebase-merges with commit that can generate bad characters for filename' '

+   git checkout -b colon-in-label E &&
+   git merge -m "colon: this should work" G &&
+   git rebase --rebase-merges --force-rebase E
+'
  test_done



Re: git-diff passes : args to GIT_EXTERNAL_DIFF incorrectly?

2019-08-30 Thread Phillip Wood

On 30/08/2019 14:23, Dmitry Nikulin wrote:

On Fri, 30 Aug 2019 at 13:16, Phillip Wood  wrote:

I'm not sure why the last argument is being split in
your example. It is not split in the example below


I have replicated the splitting issue on my small demo repo [1]:

$ env GIT_EXTERNAL_DIFF=./print_argv.py git diff -M origin/branch1
origin/branch1-mv -- file1.txt file1-mv.txt
['./print_argv.py',
  'file1.txt',
  '/tmp/EWaCSc_file1.txt',
  '2bef330804cb3f6962e45a72a12a3071ee9b5888',
  '100644',
  '/tmp/mtEiSc_file1-mv.txt',
  'f8fd6737fbe5a45c97ba9c9de495dc46ff11eccd',
  '100644',
  'file1-mv.txt',
  'similarity index 90%\n'
  'rename from file1.txt\n'
  'rename to file1-mv.txt\n'
  'index 2bef330..f8fd673 100644\n']


That's strange - What OS are you using? Does python do any 
pre-processing of arguments with newlines in them?



This is, however, tangential to the original problem: documenting the
external diff CLI interface for diffing two blobs. Here is what I am
seeing:

$ env GIT_EXTERNAL_DIFF=./print_argv.py git diff
origin/branch1:file1.txt origin/branch1-mv:file1-mv.txt
['./print_argv.py',
  'file1.txt',
  '/tmp/n9USvy_file1.txt',
  '2bef330804cb3f6962e45a72a12a3071ee9b5888',
  '100644',
  '/tmp/Zst0uy_file1-mv.txt',
  'f8fd6737fbe5a45c97ba9c9de495dc46ff11eccd',
  '100644',
  'file1-mv.txt',
  'index 2bef330..f8fd673 100644\n']

The meaning and origin of the last arg remains mysterious, and the
other args do not conform to the published documentation[2], which
states that the args should be:


The documentation is incomplete it should document the extra fields 
passed when it detects renames.



 path old-file old-hex old-mode new-file new-hex new-mode

Instead the args that are passed are:

 path old-filename old-file old-hex old-mode new-file new-hex
new-mode new-filename something


I think what is happening is that because you're passing different 
filenames in to get the blobs the 'pass rename information' code is 
being triggered so it shows the new filename as the name used to get the 
 second blob and then passes the header which only has an index line as 
there isn't any real rename information.


Best Wishes

Phillip


[1]: https://github.com/dniku/git-external-diff-argv
[2]: 
https://www.git-scm.com/docs/git#Documentation/git.txt-codeGITEXTERNALDIFFcode



Re: git-diff passes : args to GIT_EXTERNAL_DIFF incorrectly?

2019-08-30 Thread Phillip Wood

Hi Dmitry

On 29/08/2019 15:36, Dmitry Nikulin wrote:

Thank you for the reply.
[...]
However, for the original repository where I first faced this problem
(https://github.com/yandexdataschool/Practical_RL), Git passes a very
weird set of args to the external diff:

$ env GIT_EXTERNAL_DIFF=./print_argv.py git diff -M master coursera --
week02_value_based/seminar_vi.ipynb
week2_model_based/practice_vi.ipynb
['./print_argv.py',
  'week02_value_based/seminar_vi.ipynb',
  '/tmp/amudWz_seminar_vi.ipynb',
  '8f8016963c888b7dd8dd20f60b7d6fdb41b26c1d',
  '100644',
  '/tmp/Ub7zPz_practice_vi.ipynb',
  '21db80f53b632d975a9af0acbaf397eb717cde2c',
  '100644',
  'week2_model_based/practice_vi.ipynb',
  'similarity index 82%\n'
  'rename from week02_value_based/seminar_vi.ipynb\n'
  'rename to week2_model_based/practice_vi.ipynb\n'
  'index 8f80169..21db80f 100644\n']

I would guess that this is a bug. There can clearly be a hotfix (after
all, Git passes all of the information to the external that it should
per the spec, that is, -path, -hex, -mode;
adding, however, some garbage). 


When git detects a rename it adds two parameters to the end of the 
argument list for the external diff program. The first extra argument is 
the new name and the second is the header with the similarity 
information[1]. I'm not sure why the last argument is being split in 
your example. It is not split in the example below


$git mv git.c renamed.c
$env GIT_EXTERNAL_DIFF='printf "|%s|\\n"' git diff HEAD
|git.c|
|/tmp/lMQpP8_git.c|
|c1ee7124edcfb0417539134d50212e997dc71c1f|
|100644|
|renamed.c|
|c1ee7124edcfb0417539134d50212e997dc71c1f|
|100644|
|renamed.c|
|similarity index 100%
rename from git.c
rename to renamed.c
|

Best Wishes

Phillip

[1] https://github.com/git/git/blob/master/diff.c#L4204


I do not know though to what extent
this information is correct. You say that this information is lost
when I use the : notation; however, Git seems to pass
paths and hexes correctly. This only leaves open the question of file
mode. Perhaps it could be preserved at least for some cases, such as
when the blob is retrieved from a path in a tree?



Re: [PATCH 1/1] checkout: add simple check for 'git checkout -b'

2019-08-29 Thread Phillip Wood

Hi Stolee

On 29/08/2019 18:01, Derrick Stolee via GitGitGadget wrote:

From: Derrick Stolee 

The 'git switch' command was created to separate half of the
behavior of 'git checkout'. It specifically has the mode to
do nothing with the index and working directory if the user
only specifies to create a new branch and change HEAD to that
branch. This is also the behavior most users expect from
'git checkout -b', but for historical reasons it also performs
an index update by scanning the working directory. This can be
slow for even moderately-sized repos.

A performance fix for 'git checkout -b' was introduced by
fa655d8411 (checkout: optimize "git checkout -b "
2018-08-16). That change includes details about the config
setting checkout.optimizeNewBranch when the sparse-checkout
feature is required. The way this change detected if this
behavior change is safe was through the skip_merge_working_tree()
method. This method was complex and needed to be updated
as new options were introduced.

This behavior was essentially reverted by 65f099b ("switch:
no worktree status unless real branch switch happens"
2019-03-29). Instead, two members of the checkout_opts struct
were used to distinguish between 'git checkout' and 'git switch':

 * switch_branch_doing_nothing_is_ok
 * only_merge_on_switching_branches

These settings have opposite values depending on if we start
in cmd_checkout or cmd_switch.

The message for 64f099b includes "Users of big repos are
encouraged to move to switch." Making this change while
'git switch' is still experimental is too aggressive.

Create a happy medium between these two options by making
'git checkout -b ' behave just like 'git switch',
but only if we read exactly those arguments. This must
be done in cmd_checkout to avoid the arguments being
consumed by the option parsing logic.

This differs from the previous change by fa644d8 in that
the config option checkout.optimizeNewBranch remains
deleted. This means that 'git checkout -b' will ignore
the index merge even if we have a sparse-checkout file.
While this is a behavior change for 'git checkout -b',
it matches the behavior of 'git switch -c'.

Signed-off-by: Derrick Stolee 
---
  builtin/checkout.c | 9 +
  1 file changed, 9 insertions(+)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6123f732a2..116200cf90 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1713,6 +1713,15 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
opts.overlay_mode = -1;
opts.checkout_index = -2;/* default on */
opts.checkout_worktree = -2; /* default on */
+   
+   if (argc == 3 && !strcmp(argv[1], "-b")) {
+   /*
+* User ran 'git checkout -b ' and expects


What if the user ran 'git checkout -b'? Then argc == 2.

Best Wishes

Phillip


+* the same behavior as 'git switch -c '.
+*/
+   opts.switch_branch_doing_nothing_is_ok = 0;
+   opts.only_merge_on_switching_branches = 1;
+   }
  
  	options = parse_options_dup(checkout_options);

options = add_common_options(&opts, options);



Re: error: cannot cherry-pick during a revert

2019-08-29 Thread Phillip Wood

Hi Mike

On 29/08/2019 00:25, Mike Hommey wrote:

Hi,

This just happened to me while cherry-pick'ing:

$ git cherry-pick HEAD@{1}
error: could not apply 614fe5e629b84... try
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add ' or 'git rm '
hint: and commit the result with 'git commit'
Recorded preimage for 'taskcluster/ci/build/linux.yml'

(... this is where I fix my conflict ...)

$ git add -u
$ git cherry-pick --continue
error: cannot cherry-pick during a revert.
fatal: cherry-pick failed


Oh dear that's not good


So apparently, cherry-pick thinks it was doing a revert when it hit a
conflict?

(This is with git 2.23)


I wondered if this was due to some of the recent changes adding --skip 
to cherry-pick and revert but I can't see anything obvious at the 
moment. To get that error the sequencer has loaded a todo file (in 
read_populate_todo()) which starts with a revert command. Is it possible 
you were reverting a sequence of commits before you ran the cherry-pick? 
(a single pick or revert does not create a todo list). It could be that 
there was an old todo list left over from a while ago - historically the 
sequencer hasn't been all that good at cleaning up after itself if the 
user committed the final pick or revert with 'git commit' and forgot to 
run 'cherry-pick/revert --continue' afterwards.


Best Wishes

Phillip


Mike



Re: [PATCH 10/11] introduce container_of macro

2019-08-28 Thread Phillip Wood

On 27/08/2019 15:49, Derrick Stolee wrote:

On 8/25/2019 10:43 PM, Eric Wong wrote:

This macro is popular within the Linux kernel for supporting
intrusive data structures such as linked lists, red-black trees,
and chained hash tables while allowing the compiler to do
type checking.

I intend to use this to remove the limitation of "hashmap_entry"
being location-dependent and to allow more compile-time type
checking.

This macro already exists in our source as "list_entry" in
list.h and making "list_entry" an alias to "container_of"
as the Linux kernel has done is a possibility.

[snip]

+/*
+ * container_of - Get the address of an object containing a field.
+ *
+ * @ptr: pointer to the field.
+ * @type: type of the object.
+ * @member: name of the field within the object.
+ */
+#define container_of(ptr, type, member) \
+   ((type *) ((char *)(ptr) - offsetof(type, member)))
+
  #endif


I think it would be good to include at least one use of this
macro in this patch. As it stands, I need to look at the next
patch to make sense of what this is doing.

It took me a little while to parse what is happening here.
'ptr' is a pointer to the generic struct (in our case,
'struct hashmap_entry *'), while 'type' is the parent type,
and 'member' is the name of the member in 'type' that is
of type typeof(*ptr).


It took me a couple of minutes to figure it out as well. The rest of 
this patch series adds some very welcome type safety changes, at first 
sight this patch threatens to undermine that as there is no check (and 
no compiler independent way to check) that type == typeof(*ptr). It 
would also be helpful if the commit message could explain how this can 
be used to improve type safety.


Best Wishes

Phillip


Perhaps this is easier to grok for others than it was for me.

-Stolee



Re: [PATCH 04/11] hashmap_entry: detect improper initialization

2019-08-28 Thread Phillip Wood

Hi Eric

On 27/08/2019 10:49, Eric Wong wrote:

Johannes Schindelin  wrote:

Hi Eric,

On Mon, 26 Aug 2019, Eric Wong wrote:


By renaming the "hash" field to "_hash", it's easy to spot
improper initialization of hashmap_entry structs which
can leave "hashmap_entry.next" uninitialized.


Would you mind elaborating a bit? This explanation does not enlighten
me, sadly, all I see is that it makes it (slightly) harder for me to
maintain Git for Windows' patches on top of `pu`, as the FSCache patches
access that field directly (so even if they rebase cleanly, the build
breaks).


I renamed it to intentionally break my build.

That way I could easily spot if there were any other improper
initializations of the .hash field.  It's fine to revert,
actually, it could be more of a "showing my work" patch.


I'm still a bit confused as the changed initializations already used 
hashmap_entry_init() and so presumably were already initializing 
hashmap_entry.next correctly. Is there a way to get 'make coccicheck' 
detect incorrect initializations, this renaming wont prevent bad code 
being added in the future.


Best Wishes

Phillip


(AFAIK, it's a pretty common practice, but maybe not here :x)

I've also pondered adding a
"hashmap_entry_hash(const struct hashmap_entry *)"
accessor method for reading the field value (but not setting
it), but it's a bit verbose...

I'm also wondering where/if hashmap offers a real benefit over
khash nowadays; the latter ought to have better locality.
Would like benchmark at some point in the future;
but safety fixes first :)



Re: [PATCH v5 0/2] Honor .gitattributes with rebase --am

2019-08-26 Thread Phillip Wood

Hi Brian

On 26/08/2019 00:33, brian m. carlson wrote:

This series makes rebase --am honor the .gitattributes file for
subsequent patches when a patch changes it.

Note that there are two places we load attributes in ll-merge.c, but
this code only handles the one that git am uses.  The two cannot be
unified because the one in ll_merge_marker_size intentionally doesn't
load the merge attribute, since it wants to always use the recursive
strategy.  Loading it anyway causes t4017 to fail.

Changes from v4:
* Wrap lines in apply.c.
* Handle merge and conflict-marker-size attributes.
* Add tests for am and am -3 in addition to rebase.


I've only had time for a quick look at these but the changes look good 
to me. Thanks for taking the time to add the tests for am and the code 
for handling the merge attributes


Best Wishes

Phillip


Changes from v3:
* Check for both addition and removal of .gitattributes files.
* Switch from "test_config" to "git config".

Changes from v2:
* Rename has_path_suffix to ends_with_path_components.

Changes from v1:
* Add has_path_suffix in a separate commit.

brian m. carlson (2):
   path: add a function to check for path suffix
   am: reload .gitattributes after patching it

  apply.c   | 11 ++
  convert.c | 11 +-
  convert.h |  6 ++
  ll-merge.c| 19 +
  ll-merge.h|  1 +
  path.c| 39 +++
  path.h|  3 +++
  t/t3400-rebase.sh | 36 
  t/t4150-am.sh | 52 +++
  9 files changed, 164 insertions(+), 14 deletions(-)

Range-diff against v4:
1:  fa825e4b40 ! 1:  2077a0829e apply: reload .gitattributes after patching it
 @@ Metadata
  Author: brian m. carlson 
  
   ## Commit message ##

 -apply: reload .gitattributes after patching it
 +am: reload .gitattributes after patching it
  
  When applying multiple patches with git am, or when rebasing using the

  am backend, it's possible that one of our patches has updated a
 @@ Commit message
  
  To ensure we write the correct data into the working tree, expire the

  cache after each patch that touches a path ending in ".gitattributes".
 +Since we load these attributes in multiple separate files, we must
 +expire them accordingly.
 +
 +Verify that both the am and rebase code paths work correctly, 
including
 +the conflict marker size with am -3.
  
  Signed-off-by: brian m. carlson 
  
 @@ apply.c: static int apply_patch(struct apply_state *state,

*listp = patch;
listp = &patch->next;
  +
 -+ if ((patch->new_name && 
ends_with_path_components(patch->new_name, GITATTRIBUTES_FILE)) ||
 -+ (patch->old_name && 
ends_with_path_components(patch->old_name, GITATTRIBUTES_FILE)))
 ++ if ((patch->new_name &&
 ++  ends_with_path_components(patch->new_name,
 ++GITATTRIBUTES_FILE)) ||
 ++ (patch->old_name &&
 ++  ends_with_path_components(patch->old_name,
 ++GITATTRIBUTES_FILE)))
  + flush_attributes = 1;
}
else {
 @@ apply.c: static int apply_patch(struct apply_state *state,
strbuf_release(&buf);
  
   ## convert.c ##

 +@@
 + #include "pkt-line.h"
 + #include "sub-process.h"
 + #include "utf8.h"
 ++#include "ll-merge.h"
 +
 + /*
 +  * convert.c - convert a file when checking it out and checking it in.
  @@ convert.c: struct conv_attrs {
const char *working_tree_encoding; /* Supported encoding or default 
encoding if NULL */
   };
 @@ convert.c: static void convert_attrs(const struct index_state *istate,
  +{
  + attr_check_free(check);
  + check = NULL;
 ++ reset_merge_attributes();
  +}
  +
   int would_convert_to_git_filter_fd(const struct index_state *istate, 
const char *path)
 @@ convert.h: void convert_to_git_filter_fd(const struct index_state 
*istate,
*
* Streaming conversion support
  
 + ## ll-merge.c ##

 +@@ ll-merge.c: struct ll_merge_driver {
 +  char *cmdline;
 + };
 +
 ++static struct attr_check *merge_attributes;
 ++static struct attr_check *load_merge_attributes(void)
 ++{
 ++ if (!merge_attributes)
 ++ merge_attributes = attr_check_initl("merge", 
"conflict-marker-size", NULL);
  

Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-26 Thread Phillip Wood

On 20/08/2019 19:32, Phillip Wood wrote:

On 20/08/2019 19:24, Junio C Hamano wrote:

Phillip Wood  writes:


Do you know why -m and -i aren't affected?


I had to look, but I believe the answer is because they use the
sequencer, and the sequencer calls git merge-recursive as a separate
process, and so the writing of the tree is only done in a subprocess,
which can't persist state.


The sequencer has been running in a single process for a while now. We
do fork for 'git merge' sometimes when processing 'merge' commands but
'pick' commands are all done in a single process by calling
do_recursive_merge().

Best Wishes

Phillip


Should we move the merge-recursive code into the main process, we'll
likely have the same problem there.


So we actually have the same issue already?


I don't think so, I modified Brian's test to call 'rebase -i' and it 
passes but no one seems to know why.


I spent some time digging into this and the attributes are reloaded 
before each pick. This is because check_updates() called by 
unpack_trees() calls git_attr_set_direction(GIT_ATTR_CHECKOUT) at the 
start of the function and git_attr_set_direction(GIT_ATTR_CHECKIN) at 
the end of the function. This has the effect of dropping all loaded 
attributes as git_attr_set_direction() calls drop_all_attr_stacks() when 
the direction is changed.


Best Wishes

Phillip


Best Wishes

Phillip


Re: [PATCH 3/3] sequencer: simplify root commit creation

2019-08-22 Thread Phillip Wood

On 19/08/2019 17:09, Eric Sunshine wrote:

On Mon, Aug 19, 2019 at 5:18 AM Phillip Wood via GitGitGadget
 wrote:

Adapt try_to_commit() to create a new root commit rather than special
casing this in run_git_commit(). The significantly reduces the amount of


s/The/This/


Thanks Eric - well spotted as ever. Thanks Junio for fixing this up in pu.

Best Wishes

Phillip


special case code for creating the root commit and reduces the number of
commit code paths we have to worry about.

Signed-off-by: Phillip Wood 


Re: [PATCH v3 1/6] rebase -i: add --ignore-whitespace flag

2019-08-20 Thread Phillip Wood

Hi Rohit

On 20/08/2019 04:45, Rohit Ashiwal wrote:

There are two backends available for rebasing, viz, the am and the
interactive. Naturally, there shall be some features that are
implemented in one but not in the other. One such flag is
--ignore-whitespace which indicates merge mechanism to treat lines
with only whitespace changes as unchanged. Wire the interactive
rebase to also understand the --ignore-whitespace flag by
translating it to -Xignore-space-change.

Signed-off-by: Rohit Ashiwal 
---
  Documentation/git-rebase.txt| 13 -
  builtin/rebase.c| 22 +++--
  t/t3422-rebase-incompatible-options.sh  |  1 -
  t/t3433-rebase-options-compatibility.sh | 65 +
  4 files changed, 94 insertions(+), 7 deletions(-)
  create mode 100755 t/t3433-rebase-options-compatibility.sh

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 6156609cf7..873eb5768c 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -371,8 +371,16 @@ If either  or --root is given on the command 
line, then the
  default is `--no-fork-point`, otherwise the default is `--fork-point`.
  
  --ignore-whitespace::

+   Behaves differently depending on which backend is selected.
++
+'am' backend: When applying a patch, ignore changes in whitespace in
+context lines if necessary.
++
+'interactive' backend: Treat lines with only whitespace changes as
+unchanged for the sake of a three-way merge.
+


Thanks for spelling out exactly what this does. I had not appreciated 
the difference before. Does this mean that if I have a branch with some 
whitespace cleanups I'll get different results if I rebase it with the 
sequencer compared to am? (I suspect from the description that the 
sequencer will simply ignore all my whitespace changes)


I think this is ready if we can live with the difference - I'm not 
entirely convinced that adding an option with the same name and a 
different behavior is going to improve things though.


Best Wishes

Phillip


  --whitespace=::
-   These flag are passed to the 'git apply' program
+   This flag is passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
  +
  See also INCOMPATIBLE OPTIONS below.
@@ -520,7 +528,6 @@ The following options:
   * --committer-date-is-author-date
   * --ignore-date
   * --whitespace
- * --ignore-whitespace
   * -C
  
  are incompatible with the following options:

@@ -543,6 +550,8 @@ In addition, the following pairs of options are 
incompatible:
   * --preserve-merges and --interactive
   * --preserve-merges and --signoff
   * --preserve-merges and --rebase-merges
+ * --preserve-merges and --ignore-whitespace
+ * --rebase-merges and --ignore-whitespace
   * --rebase-merges and --strategy
   * --rebase-merges and --strategy-option
  
diff --git a/builtin/rebase.c b/builtin/rebase.c

index 670096c065..f8a618d54c 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,7 @@ struct rebase_options {
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
+   int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
char *cmd;
@@ -99,6 +100,7 @@ struct rebase_options {
  
  static struct replay_opts get_replay_opts(const struct rebase_options *opts)

  {
+   struct strbuf strategy_buf = STRBUF_INIT;
struct replay_opts replay = REPLAY_OPTS_INIT;
  
  	replay.action = REPLAY_INTERACTIVE_REBASE;

@@ -114,9 +116,15 @@ static struct replay_opts get_replay_opts(const struct 
rebase_options *opts)
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
+
if (opts->strategy_opts)
-   parse_strategy_opts(&replay, opts->strategy_opts);
+   strbuf_addstr(&strategy_buf, opts->strategy_opts);
+   if (opts->ignore_whitespace)
+   strbuf_addstr(&strategy_buf, " --ignore-space-change");
+   if (strategy_buf.len)
+   parse_strategy_opts(&replay, strategy_buf.buf);
  
+	strbuf_release(&strategy_buf);

return replay;
  }
  
@@ -511,6 +519,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)

argc = parse_options(argc, argv, prefix, options,
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
  
+	opts.strategy_opts = xstrdup_or_null(opts.strategy_opts);

+
if (!is_null_oid(&squash_onto))
opts.squash_onto = &squash_onto;
  
@@ -964,6 +974,8 @@ static int run_am(struct rebase_options *opts)

am.git_cmd = 1;
argv_array_push(&am.args, "am");
  
+	if (opts->ignore_whitespace)

+   argv_array_push(&am.args, "--igno

Re: [PATCH v3 0/6] rebase -i: support more options

2019-08-20 Thread Phillip Wood

On 20/08/2019 18:53, Junio C Hamano wrote:

Phillip Wood  writes:


Hi Rohit

On 20/08/2019 04:45, Rohit Ashiwal wrote:

I've tries to incorporated all the suggestions.


It is helpful if you can list the changes to remind us all what we
said. (as a patch author I find composing that is helpful to remind me
if there's anything I've forgotten to address)

Also there are a couple of things that were discussed such as
splitting up the author and passing it round as a  tuple and testing a non-default timezone which aren't included -
that's fine but it helps if you take a moment to explain why in the
cover letter.



Some points:
- According to v2.0.0's git-am.sh, ignore-date should override
  committer-date-is-author-date. Ergo, we are not barfing out
  when both flags are provided.
- Should the 'const' qualifier be removed[2]? Since it is leaving
  a false impression that author should not be free()'d.


The author returned by read_author_ident() is owned by the strbuf that
you pass to read_author_ident() which is confusing.

Best Wishes

Phillip


I've looked at this round, but will push out v2 for today's
integration cycle, mostly due to lack of time, but there do not seem
to be great difference between the iterations.

The "ignore-date" step conflicts semantically with b0a31861
("sequencer: simplify root commit creation", 2019-08-19) but in a
good way.  Without the clean-up b0a31861 makes, we need to munge the
timestamp in two places, but with it, there is only one place that
needs to modify the timestamp for the feature (in try_to_commit()).


That was my hope


You may want to see if these "more options" topic can take advantage
of the "simplify root commit creation" by building on top of some
form of it (I do not know offhand if b0a31861 ("sequencer: simplify
root commit creation", 2019-08-19) must build on other two patches
to fix "rebase -i" or it can be split out as an independent
clean-up), and if it is feasible, work with your student to make it
happen, perhaps?


If it is separated out from the first two there will be a minor textual 
conflict as the first patch in that series changes the root commit 
creation to stop it writing CHERRY_PICK_HEAD and then b0a31861 deletes 
the modified version but it shouldn't be a problem to resolve manually. 
Rohit do you want to try cherry-picking b0a31861 onto master and then 
rebasing your patches on top of it? - it would be nice to simplify things.


Best Wishes

Phillip


Thanks.



Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-20 Thread Phillip Wood

On 20/08/2019 19:24, Junio C Hamano wrote:

Phillip Wood  writes:


Do you know why -m and -i aren't affected?


I had to look, but I believe the answer is because they use the
sequencer, and the sequencer calls git merge-recursive as a separate
process, and so the writing of the tree is only done in a subprocess,
which can't persist state.


The sequencer has been running in a single process for a while now. We
do fork for 'git merge' sometimes when processing 'merge' commands but
'pick' commands are all done in a single process by calling
do_recursive_merge().

Best Wishes

Phillip


Should we move the merge-recursive code into the main process, we'll
likely have the same problem there.


So we actually have the same issue already?


I don't think so, I modified Brian's test to call 'rebase -i' and it 
passes but no one seems to know why.


Best Wishes

Phillip


Re: [PATCH v3 5/6] rebase -i: support --ignore-date

2019-08-20 Thread Phillip Wood

On 20/08/2019 18:42, Junio C Hamano wrote:

Rohit Ashiwal  writes:


+/* Construct a free()able author string with current time as the author date */
+static char *ignore_author_date(const char *author)
+{
+   int len = strlen(author);


Mental note: ignore_author_date() would not allow author==NULL as its input.


@@ -1020,10 +1047,20 @@ static int run_git_commit(struct repository *r,
  
  		if (res <= 0)

res = error_errno(_("could not read '%s'"), defmsg);
-   else
+   else {
+   if (opts->ignore_date) {
+   char *new_author = ignore_author_date(author);
+   if (!author)
+   BUG("ignore-date can only be used with "
+   "rebase, which must set the author "
+   "before committing the tree");


Yet, author is used and then checked for NULL-ness, which is
backwards.  Before we have a chance to issue this BUG(), we would
already have segfaulted inside ignore_author_date().



Good catch!


Re: [PATCH v3 0/6] rebase -i: support more options

2019-08-20 Thread Phillip Wood

Hi Rohit

On 20/08/2019 04:45, Rohit Ashiwal wrote:

I've tries to incorporated all the suggestions.


It is helpful if you can list the changes to remind us all what we said. 
(as a patch author I find composing that is helpful to remind me if 
there's anything I've forgotten to address)


Also there are a couple of things that were discussed such as splitting 
up the author and passing it round as a  tuple 
and testing a non-default timezone which aren't included - that's fine 
but it helps if you take a moment to explain why in the cover letter.




Some points:
   - According to v2.0.0's git-am.sh, ignore-date should override
 committer-date-is-author-date. Ergo, we are not barfing out
 when both flags are provided.
   - Should the 'const' qualifier be removed[2]? Since it is leaving
 a false impression that author should not be free()'d.


The author returned by read_author_ident() is owned by the strbuf that 
you pass to read_author_ident() which is confusing.


Best Wishes

Phillip



[1]: git show v2.0.0:git-am.sh
[2]: https://github.com/git/git/blob/v2.23.0/sequencer.c#L959

Rohit Ashiwal (6):
   rebase -i: add --ignore-whitespace flag
   sequencer: add NULL checks under read_author_script
   rebase -i: support --committer-date-is-author-date
   sequencer: rename amend_author to author_to_rename
   rebase -i: support --ignore-date
   rebase: add --reset-author-date

  Documentation/git-rebase.txt|  26 +++--
  builtin/rebase.c|  53 +++---
  sequencer.c | 135 ++--
  sequencer.h |   2 +
  t/t3422-rebase-incompatible-options.sh  |   2 -
  t/t3433-rebase-options-compatibility.sh | 100 ++
  6 files changed, 289 insertions(+), 29 deletions(-)
  create mode 100755 t/t3433-rebase-options-compatibility.sh

Range-diff:
1:  4cd0aa3084 ! 1:  e82ed8cad5 rebase -i: add --ignore-whitespace flag
 @@ -19,10 +19,13 @@
   default is `--no-fork-point`, otherwise the default is `--fork-point`.
   
   --ignore-whitespace::

 -+ This flag is either passed to the 'git apply' program
 -+ (see linkgit:git-apply[1]), or to 'git merge' program
 -+ (see linkgit:git-merge[1]) as `-Xignore-space-change`,
 -+ depending on which backend is selected by other options.
 ++ Behaves differently depending on which backend is selected.
 +++
 ++'am' backend: When applying a patch, ignore changes in whitespace in
 ++context lines if necessary.
 +++
 ++'interactive' backend: Treat lines with only whitespace changes as
 ++unchanged for the sake of a three-way merge.
  +
   --whitespace=::
  - These flag are passed to the 'git apply' program
 @@ -63,7 +66,7 @@
   
   static struct replay_opts get_replay_opts(const struct rebase_options *opts)

   {
 -+ char *strategy_opts = opts->strategy_opts;
 ++ struct strbuf strategy_buf = STRBUF_INIT;
struct replay_opts replay = REPLAY_OPTS_INIT;
   
   	replay.action = REPLAY_INTERACTIVE_REBASE;

 @@ -71,24 +74,19 @@
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
 -- if (opts->strategy_opts)
 -- parse_strategy_opts(&replay, opts->strategy_opts);
 -+
 -+ if (opts->ignore_whitespace) {
 -+ struct strbuf buf = STRBUF_INIT;
 -+
 -+ if (strategy_opts)
 -+ strbuf_addstr(&buf, strategy_opts);
  +
 -+ strbuf_addstr(&buf, " --ignore-space-change");
 -+ free(strategy_opts);
 -+ strategy_opts = strbuf_detach(&buf, NULL);
 -+ }
 -+ if (strategy_opts)
 -+ parse_strategy_opts(&replay, strategy_opts);
 +  if (opts->strategy_opts)
 +- parse_strategy_opts(&replay, opts->strategy_opts);
 ++ strbuf_addstr(&strategy_buf, opts->strategy_opts);
 ++ if (opts->ignore_whitespace)
 ++ strbuf_addstr(&strategy_buf, " --ignore-space-change");
 ++ if (strategy_buf.len)
 ++ parse_strategy_opts(&replay, strategy_buf.buf);
   
 ++	strbuf_release(&strategy_buf);

return replay;
   }
 +
  @@
argc = parse_options(argc, argv, prefix, options,
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
2:  e2c0304587 = 2:  209057b361 sequencer: add NULL checks under 
read_author_script
3:  6aed57ae2e ! 3:  a4e6644ef8 rebase -i: support 
--committer-date-is-author-date
 @@ -21,10 +21,12 @@
  +
   --ignore-date::
  - These flags are passed to 'git am' to easily change the dates
 +- of the rebased comm

Re: [PATCH v3 5/6] rebase -i: support --ignore-date

2019-08-20 Thread Phillip Wood
"));
@@ -2592,6 +2636,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->committer_date_is_author_date = 1;
}
  
+		if (file_exists(rebase_path_ignore_date())) {

+   opts->allow_ff = 0;
+   opts->ignore_date = 1;
+   }
+
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
  
@@ -2676,6 +2725,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,

write_file(rebase_path_signoff(), "--signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
+   if (opts->ignore_date)
+   write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
  
@@ -3601,6 +3652,8 @@ static int do_merge(struct repository *r,

argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
+   if (opts->ignore_date)
+   push_dates(&cmd);
  
  		/* Add the tips to be merged */

for (j = to_merge; j; j = j->next)
@@ -3874,7 +3927,8 @@ static int pick_commits(struct repository *r,
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit ||
-   opts->committer_date_is_author_date));
+   opts->committer_date_is_author_date ||
+   opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;
  
diff --git a/sequencer.h b/sequencer.h

index e3881e9275..bf5a79afdb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -44,6 +44,7 @@ struct replay_opts {
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;
+   int ignore_date;
  
  	int mainline;
  
diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh

index b2419a2b75..c060fcd10b 100755
--- a/t/t3433-rebase-options-compatibility.sh
+++ b/t/t3433-rebase-options-compatibility.sh
@@ -81,4 +81,20 @@ test_expect_success '--committer-date-is-author-date works 
with interactive back
test_cmp authortime committertime
  '
  
+# Checking for + in author time is enough since default

+# timezone is UTC, but the timezone used while committing
+# sets to +0530.


I'm still worried that this will hide some breakage in the future. Can 
we add a test for rebase -r as well to check that code please.


Best Wishes

Phillip


+test_expect_success '--ignore-date works with am backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   grep "+" authortime
+'
+
+test_expect_success '--ignore-date works with interactive backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date -i HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   grep "+" authortime
+'
  test_done



Re: [PATCH v3 3/6] rebase -i: support --committer-date-is-author-date

2019-08-20 Thread Phillip Wood
  }
  
+	if (options.committer_date_is_author_date)

+   options.flags |= REBASE_FORCE;
+
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
-   if (!strcmp(option, "--committer-date-is-author-date") ||
-   !strcmp(option, "--ignore-date") ||
+   if (!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
diff --git a/sequencer.c b/sequencer.c
index 30d77c2682..29b67bc1ae 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, 
"rebase-merge/refs-to-delete")
   * command-line.
   */
  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
  static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
  static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
  static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -879,6 +880,17 @@ static char *get_author(const char *message)
return NULL;
  }
  
+/* Returns a "date" string that needs to be free()'d by the caller */

+static char *read_author_date_or_null(void)
+{
+   char *date;
+
+   if (read_author_script(rebase_path_author_script(),
+  NULL, NULL, &date, 0))
+   return NULL;
+   return date;
+}
+
  /* Read author-script and return an ident line (author  timestamp) */
  static const char *read_author_ident(struct strbuf *buf)
  {
@@ -964,6 +976,25 @@ static int run_git_commit(struct repository *r,
  {
struct child_process cmd = CHILD_PROCESS_INIT;
  
+	if (opts->committer_date_is_author_date) {

+   size_t len;
+   int res = -1;
+   struct strbuf datebuf = STRBUF_INIT;
+   char *date = read_author_date_or_null();
+
+   if (!date)
+   return -1;


It is good to this this new error checking


+
+   strbuf_addf(&datebuf, "@%s", date);
+   free(date);
+
+   date = strbuf_detach(&datebuf, &len);
+   res = setenv("GIT_COMMITTER_DATE", date, 1);
+   free(date);


This could be simplified slightly by doing
res = setenv("GIT_COMMITTER_DATE", datebuf.buf. 1);
strbuf_release(&datebuf);


+
+   if (res)
+   return -1;
+   }
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
const char *author = NULL;
@@ -1400,7 +1431,6 @@ static int try_to_commit(struct repository *r,
  
  	if (parse_head(r, ¤t_head))

return -1;
-
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
@@ -1427,6 +1457,21 @@ static int try_to_commit(struct repository *r,
commit_list_insert(current_head, &parents);
}
  
+	if (opts->committer_date_is_author_date) {

+   int len = strlen(author);
+   struct ident_split ident;
+   struct strbuf date = STRBUF_INIT;
+
+   split_ident_line(&ident, author, len);
+
+   if (!ident.date_begin)
+   return error(_("corrupted author without date 
information"));


I had to read the source of split_ident_line() to check this was safe, I 
think it is better to use the return value to check for errors  - a 
quick greps shows that this is what all the other callers do.



+
+   strbuf_addf(&date, "@%s", ident.date_begin);


I still think this will pass any junk after a corrupted timezone, it 
would be better to do


	strbuf_addf(&date, "@%.*s %.*s", ident.date_begin, ident.data_end - 
ident.date_begin, ident.tz_begin, ident.tz_end - ident.tz_begin);



+   setenv("GIT_COMMITTER_DATE", date.buf, 1);


The code above (in run_git_commit()) checks the return value of setenv() 
and returns an error if it failed should this be doing the same?


Best Wishes

Phillip


+   strbuf_release(&date);
+   }
+
if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
@@ -2542,6 +2587,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}
  
+	

Re: [PATCH 2/2] rebase.c: make sure current branch isn't moved when autostashing

2019-08-20 Thread Phillip Wood

Hi Ben

I need to have a longer look at this (I don't understand why we're 
calling reset --hard after we've stashed the changes) but I notice that 
the test lines you're changing predate the switch to the builtin rebase 
so those changes are not related to the branch switching problem.


Best Wishes

Phillip

On 18/08/2019 10:53, Ben Wijen wrote:

The rebase --autostash incorrectly moved the current branch to orig_head, where
orig_head -- commit object name of tip of the branch before rebasing

It seems this was incorrectly taken over from git-legacy-rebase.sh

Signed-off-by: Ben Wijen 
---
  builtin/rebase.c| 18 ++
  t/t3420-rebase-autostash.sh |  4 
  2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 670096c065..a928f44941 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1968,9 +1968,6 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
state_dir_path("autostash", &options);
struct child_process stash = CHILD_PROCESS_INIT;
struct object_id oid;
-   struct commit *head =
-   lookup_commit_reference(the_repository,
-   &options.orig_head);
  
  			argv_array_pushl(&stash.args,

 "stash", "create", "autostash", NULL);
@@ -1991,17 +1988,14 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
options.state_dir);
write_file(autostash, "%s", oid_to_hex(&oid));
printf(_("Created autostash: %s\n"), buf.buf);
-   if (reset_head(&head->object.oid, "reset --hard",
+
+   /*
+* We might not be on orig_head yet:
+* Make sure to reset w/o switching branches...
+*/
+   if (reset_head(NULL, "reset --hard",
   NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
die(_("could not reset --hard"));
-   printf(_("HEAD is now at %s"),
-  find_unique_abbrev(&head->object.oid,
- DEFAULT_ABBREV));
-   strbuf_reset(&buf);
-   pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
-   if (buf.len > 0)
-   printf(" %s", buf.buf);
-   putchar('\n');
  
  			if (discard_index(the_repository->index) < 0 ||

repo_read_index(the_repository) < 0)
diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 867e4e0b17..2ea1909881 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -37,7 +37,6 @@ test_expect_success setup '
  create_expected_success_am () {
cat >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-   HEAD is now at $(git rev-parse --short feature-branch) third commit
First, rewinding head to replay your work on top of it...
Applying: second commit
Applying: third commit
@@ -48,7 +47,6 @@ create_expected_success_am () {
  create_expected_success_interactive () {
q_to_cr >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-   HEAD is now at $(git rev-parse --short feature-branch) third commit
Applied autostash.
Successfully rebased and updated refs/heads/rebased-feature-branch.
EOF
@@ -57,7 +55,6 @@ create_expected_success_interactive () {
  create_expected_failure_am () {
cat >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-   HEAD is now at $(git rev-parse --short feature-branch) third commit
First, rewinding head to replay your work on top of it...
Applying: second commit
Applying: third commit
@@ -70,7 +67,6 @@ create_expected_failure_am () {
  create_expected_failure_interactive () {
cat >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-   HEAD is now at $(git rev-parse --short feature-branch) third commit
Applying autostash resulted in conflicts.
Your changes are safe in the stash.
You can run "git stash pop" or "git stash drop" at any time.



Re: [PATCH 1/2] t3420: never change upstream branch

2019-08-20 Thread Phillip Wood

Hi Ben

On 18/08/2019 10:53, Ben Wijen wrote:

When using `git rebase --autostash  ` and
the workarea is dirty, the active branch is incorrectly reset
to the rebase  branch.

This test will check for such behavior.

Signed-off-by: Ben Wijen 
---
  t/t3420-rebase-autostash.sh | 9 +
  1 file changed, 9 insertions(+)

diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index b8f4d03467..867e4e0b17 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -306,4 +306,13 @@ test_expect_success 'branch is left alone when possible' '
test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
  '
  
+test_expect_success 'never change upstream branch' '

+   test_when_finished "git reset --hard && git branch -D upstream" &&
+   git checkout -b upstream unrelated-onto-branch &&
+   echo changed >file0 &&
+   git add file0 &&
+   git rebase --autostash upstream feature-branch &&
+   test $(git rev-parse upstream) = $(git rev-parse unrelated-onto-branch)


In addition to Junio's suggestions I'd add using
test_cmp_rev upstream unrelated-onto-branch
for the last line.

Best Wishes

Phillip


+'
+
  test_done



Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-20 Thread Phillip Wood

On 20/08/2019 04:05, brian m. carlson wrote:

On 2019-08-19 at 09:55:27, Phillip Wood wrote:

On 19/08/2019 10:41, Phillip Wood wrote:

[...]

diff --git a/convert.c b/convert.c
index 94ff837649..030e9b81b9 100644
--- a/convert.c
+++ b/convert.c
@@ -1293,10 +1293,11 @@ struct conv_attrs {
   const char *working_tree_encoding; /* Supported encoding or
default encoding if NULL */
   };
+static struct attr_check *check;


I was concerned about the impact adding a file global if we ever want to
multi-thread this for submodules, but looking through the file there are
a couple of others already so this isn't creating a new problem.


Doh, I've just realized it was static already - ignore that.


And I just realized that I didn't read the entire thread before
responding.  Sorry about that.


One thing did occur to me though - does this patch reset attributes like the
merge marker length (they're less critical though if there is a conflict
after an attribute change it would be nice to have the correct length) or
just the ones for filtering files?


It resets "crlf", "ident", "filter", "eol", "text", and
"working-tree-encoding".  Things it doesn't reset include "whitespace",
"export-ignore", "export-subst", "merge", and "conflict-marker-size".
Of these, I think only the latter two are relevant.

I'll update that in v5.


Thanks, one other thought I had was that this is really a bug in 'am' 
rather than 'rebase'. There has been some talk of switching the default 
rabase backend to the sequencer so maybe it would be better to test 'am' 
rather than 'rebase' to ensure we still check 'am' is working properly 
after any switch in the rebase backend. (perhaps we should be testing 
rebase and rebase --interactive separately as well to prevent any future 
regressions I'm not sure)


Best Wishes

Phillip



Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-20 Thread Phillip Wood

Hi Brian

On 20/08/2019 03:45, brian m. carlson wrote:

On 2019-08-19 at 09:41:42, Phillip Wood wrote:

Hi Brian

On 18/08/2019 19:44, brian m. carlson wrote:

When applying multiple patches with git am, or when rebasing using the
am backend, it's possible that one of our patches has updated a
gitattributes file. Currently, we cache this information, so if a
file in a subsequent patch has attributes applied, the file will be
written out with the attributes in place as of the time we started the
rebase or am operation, not with the attributes applied by the previous
patch. This problem does not occur when using the -m or -i flags to
rebase.


Do you know why -m and -i aren't affected?


I had to look, but I believe the answer is because they use the
sequencer, and the sequencer calls git merge-recursive as a separate
process, and so the writing of the tree is only done in a subprocess,
which can't persist state.


The sequencer has been running in a single process for a while now. We 
do fork for 'git merge' sometimes when processing 'merge' commands but 
'pick' commands are all done in a single process by calling 
do_recursive_merge().


Best Wishes

Phillip


Should we move the merge-recursive code into the main process, we'll
likely have the same problem there.


diff --git a/apply.c b/apply.c
index cde95369bb..d57bc635e4 100644
--- a/apply.c
+++ b/apply.c
@@ -4643,6 +4643,7 @@ static int apply_patch(struct apply_state *state,
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
int res = 0;
+   int flush_attributes = 0;
state->patch_input_file = filename;
if (read_patch_file(&buf, fd) < 0)
@@ -4670,6 +4671,10 @@ static int apply_patch(struct apply_state *state,
patch_stats(state, patch);
*listp = patch;
listp = &patch->next;
+
+   if ((patch->new_name && 
ends_with_path_components(patch->new_name, GITATTRIBUTES_FILE)) ||
+   (patch->old_name && 
ends_with_path_components(patch->old_name, GITATTRIBUTES_FILE)))
+   flush_attributes = 1;


style nit - these lines are very long compared to 80 characters


They are.  They aren't two different from other lines in the file, and I
thought that leaving them that way would preserve the similarities, but
I can also wrap them.  I'll send out a v5 with wrapped lines.


diff --git a/convert.c b/convert.c
index 94ff837649..030e9b81b9 100644
--- a/convert.c
+++ b/convert.c
@@ -1293,10 +1293,11 @@ struct conv_attrs {
const char *working_tree_encoding; /* Supported encoding or default 
encoding if NULL */
   };
+static struct attr_check *check;


I was concerned about the impact adding a file global if we ever want to
multi-thread this for submodules, but looking through the file there are a
couple of others already so this isn't creating a new problem.

+
   static void convert_attrs(const struct index_state *istate,
  struct conv_attrs *ca, const char *path)
   {
-   static struct attr_check *check;
struct attr_check_item *ccheck = NULL;
if (!check) {
@@ -1339,6 +1340,12 @@ static void convert_attrs(const struct index_state 
*istate,
ca->crlf_action = CRLF_AUTO_INPUT;
   }


The portion I've included above demonstrates that this was already a
static variable, just one hidden in a function.  So yeah, this is no
worse than it already was.



Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-19 Thread Phillip Wood

On 19/08/2019 10:41, Phillip Wood wrote:

[...]

diff --git a/convert.c b/convert.c
index 94ff837649..030e9b81b9 100644
--- a/convert.c
+++ b/convert.c
@@ -1293,10 +1293,11 @@ struct conv_attrs {
  const char *working_tree_encoding; /* Supported encoding or 
default encoding if NULL */

  };
+static struct attr_check *check;


I was concerned about the impact adding a file global if we ever want to 
multi-thread this for submodules, but looking through the file there are 
a couple of others already so this isn't creating a new problem.


Doh, I've just realized it was static already - ignore that.

One thing did occur to me though - does this patch reset attributes like 
the merge marker length (they're less critical though if there is a 
conflict after an attribute change it would be nice to have the correct 
length) or just the ones for filtering files?


Best Wishes

Phillip



Best Wishes

Phillip


+
  static void convert_attrs(const struct index_state *istate,
    struct conv_attrs *ca, const char *path)
  {
-    static struct attr_check *check;
  struct attr_check_item *ccheck = NULL;
  if (!check) {
@@ -1339,6 +1340,12 @@ static void convert_attrs(const struct 
index_state *istate,

  ca->crlf_action = CRLF_AUTO_INPUT;
  }
+void reset_parsed_attributes(void)
+{
+    attr_check_free(check);
+    check = NULL;
+}
+
  int would_convert_to_git_filter_fd(const struct index_state *istate, 
const char *path)

  {
  struct conv_attrs ca;
diff --git a/convert.h b/convert.h
index 831559f10d..3710969d43 100644
--- a/convert.h
+++ b/convert.h
@@ -94,6 +94,12 @@ void convert_to_git_filter_fd(const struct 
index_state *istate,

  int would_convert_to_git_filter_fd(const struct index_state *istate,
 const char *path);
+/*
+ * Reset the internal list of attributes used by convert_to_git and
+ * convert_to_working_tree.
+ */
+void reset_parsed_attributes(void);
+
  /*
   *
   * Streaming conversion support
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 80b23fd326..23469cc789 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -301,6 +301,42 @@ test_expect_success 'rebase --am and 
--show-current-patch' '

  )
  '
+test_expect_success 'rebase --am and .gitattributes' '
+    test_create_repo attributes &&
+    (
+    cd attributes &&
+    test_commit init &&
+    git config filter.test.clean "sed -e 
'\''s/smudged/clean/g'\''" &&
+    git config filter.test.smudge "sed -e 
'\''s/clean/smudged/g'\''" &&

+
+    test_commit second &&
+    git checkout -b test HEAD^ &&
+
+    echo "*.txt filter=test" >.gitattributes &&
+    git add .gitattributes &&
+    test_commit third &&
+
+    echo "This text is smudged." >a.txt &&
+    git add a.txt &&
+    test_commit fourth &&
+
+    git checkout -b removal HEAD^ &&
+    git rm .gitattributes &&
+    git add -u &&
+    test_commit fifth &&
+    git cherry-pick test &&
+
+    git checkout test &&
+    git rebase master &&
+    grep "smudged" a.txt &&
+
+    git checkout removal &&
+    git reset --hard &&
+    git rebase master &&
+    grep "clean" a.txt
+    )
+'
+
  test_expect_success 'rebase--merge.sh and --show-current-patch' '
  test_create_repo conflict-merge &&
  (



Re: [PATCH v4 2/2] apply: reload .gitattributes after patching it

2019-08-19 Thread Phillip Wood

Hi Brian

On 18/08/2019 19:44, brian m. carlson wrote:

When applying multiple patches with git am, or when rebasing using the
am backend, it's possible that one of our patches has updated a
gitattributes file. Currently, we cache this information, so if a
file in a subsequent patch has attributes applied, the file will be
written out with the attributes in place as of the time we started the
rebase or am operation, not with the attributes applied by the previous
patch. This problem does not occur when using the -m or -i flags to
rebase.


Do you know why -m and -i aren't affected?


To ensure we write the correct data into the working tree, expire the
cache after each patch that touches a path ending in ".gitattributes".

Signed-off-by: brian m. carlson 
---
  apply.c   |  7 +++
  convert.c |  9 -
  convert.h |  6 ++
  t/t3400-rebase.sh | 36 
  4 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/apply.c b/apply.c
index cde95369bb..d57bc635e4 100644
--- a/apply.c
+++ b/apply.c
@@ -4643,6 +4643,7 @@ static int apply_patch(struct apply_state *state,
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
int res = 0;
+   int flush_attributes = 0;
  
  	state->patch_input_file = filename;

if (read_patch_file(&buf, fd) < 0)
@@ -4670,6 +4671,10 @@ static int apply_patch(struct apply_state *state,
patch_stats(state, patch);
*listp = patch;
listp = &patch->next;
+
+   if ((patch->new_name && 
ends_with_path_components(patch->new_name, GITATTRIBUTES_FILE)) ||
+   (patch->old_name && 
ends_with_path_components(patch->old_name, GITATTRIBUTES_FILE)))
+   flush_attributes = 1;


style nit - these lines are very long compared to 80 characters


}
else {
if (state->apply_verbosity > verbosity_normal)
@@ -4746,6 +4751,8 @@ static int apply_patch(struct apply_state *state,
if (state->summary && state->apply_verbosity > verbosity_silent)
summary_patch_list(list);
  
+	if (flush_attributes)

+   reset_parsed_attributes();
  end:
free_patch_list(list);
strbuf_release(&buf);
diff --git a/convert.c b/convert.c
index 94ff837649..030e9b81b9 100644
--- a/convert.c
+++ b/convert.c
@@ -1293,10 +1293,11 @@ struct conv_attrs {
const char *working_tree_encoding; /* Supported encoding or default 
encoding if NULL */
  };
  
+static struct attr_check *check;


I was concerned about the impact adding a file global if we ever want to 
multi-thread this for submodules, but looking through the file there are 
a couple of others already so this isn't creating a new problem.


Best Wishes

Phillip


+
  static void convert_attrs(const struct index_state *istate,
  struct conv_attrs *ca, const char *path)
  {
-   static struct attr_check *check;
struct attr_check_item *ccheck = NULL;
  
  	if (!check) {

@@ -1339,6 +1340,12 @@ static void convert_attrs(const struct index_state 
*istate,
ca->crlf_action = CRLF_AUTO_INPUT;
  }
  
+void reset_parsed_attributes(void)

+{
+   attr_check_free(check);
+   check = NULL;
+}
+
  int would_convert_to_git_filter_fd(const struct index_state *istate, const 
char *path)
  {
struct conv_attrs ca;
diff --git a/convert.h b/convert.h
index 831559f10d..3710969d43 100644
--- a/convert.h
+++ b/convert.h
@@ -94,6 +94,12 @@ void convert_to_git_filter_fd(const struct index_state 
*istate,
  int would_convert_to_git_filter_fd(const struct index_state *istate,
   const char *path);
  
+/*

+ * Reset the internal list of attributes used by convert_to_git and
+ * convert_to_working_tree.
+ */
+void reset_parsed_attributes(void);
+
  /*
   *
   * Streaming conversion support
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 80b23fd326..23469cc789 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -301,6 +301,42 @@ test_expect_success 'rebase --am and --show-current-patch' 
'
)
  '
  
+test_expect_success 'rebase --am and .gitattributes' '

+   test_create_repo attributes &&
+   (
+   cd attributes &&
+   test_commit init &&
+   git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" 
&&
+   git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" 
&&
+
+   test_commit second &&
+ 

Re: [PATCH 0/2] git rebase: Make sure upstream branch is left alone.

2019-08-19 Thread Phillip Wood

Hi Ben

On 18/08/2019 10:53, Ben Wijen wrote:

I found an issue with git rebase --autostash   with an dirty 
worktree/index.
It seems the currently active branch is moved, which is not correct.


I'm not sure I understand what you mean by "the currently active branch 
is moved". 'git rebase --autostash  ' should checkout 
 (presumably stashing any unstaged and uncommitted changes 
first) and then do rebase  - what's it doing instead?


Best Wishes

Phillip


The following patches contain both a test and a fix.

Ben Wijen (2):
   t3420: never change upstream branch
   rebase.c: make sure current branch isn't moved when autostashing

  builtin/rebase.c| 18 ++
  t/t3420-rebase-autostash.sh | 13 +
  2 files changed, 15 insertions(+), 16 deletions(-)



[PATCH 0/3] rebase -i: always update HEAD before rewording

2019-08-19 Thread Phillip Wood via GitGitGadget
This series contains a couple of patches to make the C version of rebase
--interactive behave more like the scripted version. The third patch is not
strictly related to the first two but is included here to avoid merge
conflicts.

Phillip Wood (3):
  rebase -i: always update HEAD before rewording
  rebase -i: check for updated todo after squash and reword
  sequencer: simplify root commit creation

 sequencer.c| 130 +
 t/t3404-rebase-interactive.sh  |  16 +++-
 t/t3429-rebase-edit-todo.sh|  21 -
 t/t7505-prepare-commit-msg-hook.sh |   8 +-
 t/t7505/expected-rebase-i  |   3 +-
 5 files changed, 75 insertions(+), 103 deletions(-)


base-commit: ff66981f4593aec0f3b3eeace0eacb7dbe44fd8c
Published-As: 
https://github.com/gitgitgadget/git/releases/tag/pr-312%2Fphillipwood%2Fwip%2Frebase-reword-update-head-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git 
pr-312/phillipwood/wip/rebase-reword-update-head-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/312
-- 
gitgitgadget


[PATCH 1/3] rebase -i: always update HEAD before rewording

2019-08-19 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

If the user runs git log while rewording a commit it is confusing if
sometimes we're amending the commit that's being reworded and at other
times we're creating a new commit depending on whether we could
fast-forward or not[1]. Fix this inconsistency by always committing the
picked commit and then running 'git commit --amend' to do the reword.

The first commit is performed by the sequencer without forking git
commit and does not impact on the speed of rebase. In a test rewording
100 commits with

GIT_EDITOR=true GIT_SEQUENCE_EDITOR='sed -i s/pick/reword/' \
../bin-wrappers/git rebase -i --root

and taking the best of three runs the current master took
957ms and with this patch it took 961ms.

This change fixes rewording the new root commit when rearranging commits
with --root.

Note that the new code no longer updates CHERRY_PICK_HEAD after creating
a root commit - I'm not sure why the old code was that creating that ref
after a successful commit, everywhere else it is removed after a
successful commit.

[1] 
https://public-inbox.org/git/xmqqlfvu4be3@gitster-ct.c.googlers.com/T/#m133009cb91cf0917bcf667300f061178be56680a

Reported-by: SZEDER Gábor 
Signed-off-by: Phillip Wood 
---
 sequencer.c| 19 +++
 t/t3404-rebase-interactive.sh  | 16 +---
 t/t7505-prepare-commit-msg-hook.sh |  8 +---
 t/t7505/expected-rebase-i  |  3 ++-
 4 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 34ebf8ed94..085777f4a1 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -986,12 +986,10 @@ static int run_git_commit(struct repository *r,
 
strbuf_release(&msg);
strbuf_release(&script);
-   if (!res) {
-   update_ref(NULL, "CHERRY_PICK_HEAD", &root_commit, NULL,
-  REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR);
+   if (!res)
res = update_ref(NULL, "HEAD", &root_commit, NULL, 0,
 UPDATE_REFS_MSG_ON_ERR);
-   }
+
return res < 0 ? error(_("writing root commit")) : 0;
}
 
@@ -1785,7 +1783,7 @@ static int do_pick_commit(struct repository *r,
char *author = NULL;
struct commit_message msg = { NULL, NULL, NULL, NULL };
struct strbuf msgbuf = STRBUF_INIT;
-   int res, unborn = 0, allow;
+   int res, unborn = 0, reword = 0, allow;
 
if (opts->no_commit) {
/*
@@ -1855,7 +1853,7 @@ static int do_pick_commit(struct repository *r,
opts);
if (res || command != TODO_REWORD)
goto leave;
-   flags |= EDIT_MSG | AMEND_MSG | VERIFY_MSG;
+   reword = 1;
msg_file = NULL;
goto fast_forward_edit;
}
@@ -1913,7 +1911,7 @@ static int do_pick_commit(struct repository *r,
}
 
if (command == TODO_REWORD)
-   flags |= EDIT_MSG | VERIFY_MSG;
+   reword = 1;
else if (is_fixup(command)) {
if (update_squash_messages(r, command, commit, opts))
return -1;
@@ -1997,13 +1995,18 @@ static int do_pick_commit(struct repository *r,
} else if (allow)
flags |= ALLOW_EMPTY;
if (!opts->no_commit) {
-fast_forward_edit:
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
res = do_commit(r, msg_file, author, opts, flags);
else
res = error(_("unable to parse commit author"));
+   if (!res && reword)
+fast_forward_edit:
+   res = run_git_commit(r, NULL, opts, EDIT_MSG |
+VERIFY_MSG | AMEND_MSG |
+(flags & ALLOW_EMPTY));
}
 
+
if (!res && final_fixup) {
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 461dd539ff..d2f1d5bd23 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1016,9 +1016,9 @@ test_expect_success 'rebase -i --root fixup root commit' '
test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
 '
 
-test_expect_success 'rebase -i --root reword root commit' '
+test_expect_success 'rebase -i --root reword original root commit' '
test_when_finished "test_might_fail git rebase --abort" &&
-   git checkout -b reword-root-branch master &&
+   git checkout -b reword-original-root-branch master &&
set_fake_editor &a

[PATCH 3/3] sequencer: simplify root commit creation

2019-08-19 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Adapt try_to_commit() to create a new root commit rather than special
casing this in run_git_commit(). The significantly reduces the amount of
special case code for creating the root commit and reduces the number of
commit code paths we have to worry about.

Signed-off-by: Phillip Wood 
---
 sequencer.c | 75 +++--
 1 file changed, 4 insertions(+), 71 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index a13e1a7466..758c780790 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -869,34 +869,6 @@ static char *get_author(const char *message)
return NULL;
 }
 
-/* Read author-script and return an ident line (author  timestamp) */
-static const char *read_author_ident(struct strbuf *buf)
-{
-   struct strbuf out = STRBUF_INIT;
-   char *name, *email, *date;
-
-   if (read_author_script(rebase_path_author_script(),
-  &name, &email, &date, 0))
-   return NULL;
-
-   /* validate date since fmt_ident() will die() on bad value */
-   if (parse_date(date, &out)){
-   warning(_("invalid date format '%s' in '%s'"),
-   date, rebase_path_author_script());
-   strbuf_release(&out);
-   return NULL;
-   }
-
-   strbuf_reset(&out);
-   strbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0));
-   strbuf_swap(buf, &out);
-   strbuf_release(&out);
-   free(name);
-   free(email);
-   free(date);
-   return buf->buf;
-}
-
 static const char staged_changes_advice[] =
 N_("you have staged changes in your working tree\n"
 "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -954,45 +926,6 @@ static int run_git_commit(struct repository *r,
 {
struct child_process cmd = CHILD_PROCESS_INIT;
 
-   if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
-   struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
-   const char *author = NULL;
-   struct object_id root_commit, *cache_tree_oid;
-   int res = 0;
-
-   if (is_rebase_i(opts)) {
-   author = read_author_ident(&script);
-   if (!author) {
-   strbuf_release(&script);
-   return -1;
-   }
-   }
-
-   if (!defmsg)
-   BUG("root commit without message");
-
-   if (!(cache_tree_oid = get_cache_tree_oid(r->index)))
-   res = -1;
-
-   if (!res)
-   res = strbuf_read_file(&msg, defmsg, 0);
-
-   if (res <= 0)
-   res = error_errno(_("could not read '%s'"), defmsg);
-   else
-   res = commit_tree(msg.buf, msg.len, cache_tree_oid,
- NULL, &root_commit, author,
- opts->gpg_sign);
-
-   strbuf_release(&msg);
-   strbuf_release(&script);
-   if (!res)
-   res = update_ref(NULL, "HEAD", &root_commit, NULL, 0,
-UPDATE_REFS_MSG_ON_ERR);
-
-   return res < 0 ? error(_("writing root commit")) : 0;
-   }
-
cmd.git_cmd = 1;
 
if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
@@ -1376,7 +1309,7 @@ static int try_to_commit(struct repository *r,
 struct object_id *oid)
 {
struct object_id tree;
-   struct commit *current_head;
+   struct commit *current_head = NULL;
struct commit_list *parents = NULL;
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
@@ -1411,7 +1344,8 @@ static int try_to_commit(struct repository *r,
}
parents = copy_commit_list(current_head->parents);
extra = read_commit_extra_headers(current_head, exclude_gpgsig);
-   } else if (current_head) {
+   } else if (current_head &&
+  (!(flags & CREATE_ROOT_COMMIT) || (flags & AMEND_MSG))) {
commit_list_insert(current_head, &parents);
}
 
@@ -1488,8 +1422,7 @@ static int do_commit(struct repository *r,
 {
int res = 1;
 
-   if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG) &&
-   !(flags & CREATE_ROOT_COMMIT)) {
+   if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
struct object_id oid;
struct strbuf sb = STRBUF_INIT;
 
-- 
gitgitgadget


[PATCH 2/3] rebase -i: check for updated todo after squash and reword

2019-08-19 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

While a rebase is stopped for the user to edit a commit message it can
be convenient for them to also edit the todo list. The scripted version
of rebase supported this but the C version does not. We already check to
see if the todo list has been updated by an exec command so extend this
to rewords and squashes. It only costs a single stat call to do this so
it should not affect the speed of the rebase (especially as it has just
stopped for the user to edit a message)

Note that for squashes the editor may be opened on a different pick to
the squash itself as we edit the message at the end of a chain fixups
and squashes.

Signed-off-by: Phillip Wood 
---
 sequencer.c | 42 -
 t/t3429-rebase-edit-todo.sh | 21 ++-
 2 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 085777f4a1..a13e1a7466 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1773,7 +1773,7 @@ static int do_pick_commit(struct repository *r,
  enum todo_command command,
  struct commit *commit,
  struct replay_opts *opts,
- int final_fixup)
+ int final_fixup, int *check_todo)
 {
unsigned int flags = opts->edit ? EDIT_MSG : 0;
const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r);
@@ -1999,11 +1999,14 @@ static int do_pick_commit(struct repository *r,
res = do_commit(r, msg_file, author, opts, flags);
else
res = error(_("unable to parse commit author"));
-   if (!res && reword)
+   *check_todo = !!(flags & EDIT_MSG);
+   if (!res && reword) {
 fast_forward_edit:
res = run_git_commit(r, NULL, opts, EDIT_MSG |
 VERIFY_MSG | AMEND_MSG |
 (flags & ALLOW_EMPTY));
+   *check_todo = 1;
+   }
}
 
 
@@ -3821,6 +3824,7 @@ static int pick_commits(struct repository *r,
while (todo_list->current < todo_list->nr) {
struct todo_item *item = todo_list->items + todo_list->current;
const char *arg = todo_item_get_arg(todo_list, item);
+   int check_todo = 0;
 
if (save_todo(todo_list, opts))
return -1;
@@ -3859,7 +3863,8 @@ static int pick_commits(struct repository *r,
command_to_string(item->command), NULL),
1);
res = do_pick_commit(r, item->command, item->commit,
-   opts, is_final_fixup(todo_list));
+opts, is_final_fixup(todo_list),
+&check_todo);
if (is_rebase_i(opts) && res < 0) {
/* Reschedule */
advise(_(rescheduled_advice),
@@ -3916,7 +3921,6 @@ static int pick_commits(struct repository *r,
} else if (item->command == TODO_EXEC) {
char *end_of_arg = (char *)(arg + item->arg_len);
int saved = *end_of_arg;
-   struct stat st;
 
if (!opts->verbose)
term_clear_line();
@@ -3927,17 +3931,8 @@ static int pick_commits(struct repository *r,
if (res) {
if (opts->reschedule_failed_exec)
reschedule = 1;
-   } else if (stat(get_todo_path(opts), &st))
-   res = error_errno(_("could not stat '%s'"),
- get_todo_path(opts));
-   else if (match_stat_data(&todo_list->stat, &st)) {
-   /* Reread the todo file if it has changed. */
-   todo_list_release(todo_list);
-   if (read_populate_todo(r, todo_list, opts))
-   res = -1; /* message was printed */
-   /* `current` will be incremented below */
-   todo_list->current = -1;
}
+   check_todo = 1;
} else if (item->command == TODO_LABEL) {
if ((res = do_label(r, arg, item->arg_len)))
reschedule = 1;
@@ -3973,6 +3968,20 @@ static int pick_commits(struct repository *r,
item->commit,
  

Re: [GSoC][PATCH v2 5/6] rebase -i: support --ignore-date

2019-08-17 Thread Phillip Wood

On 14/08/2019 20:33, Junio C Hamano wrote:

Phillip Wood  writes:


That's an important distinction, particularly if GIT_COMMITTER_DATE is
set in the environment - are we aiming to have the author and
committer dates match or are we just resetting the author date to now?
Rohit - do you know which --ignore-date does in the am based rebase?


The purpose "am --ignore-date" was to ignore "Date:" that came from
the patch message, overriding it with the current date.  It might
have become harder to read in the C version, but "git show v2.0.0:git-am.sh"
would be an easier way to read how "--ignore-date" wanted to behave.


Thanks for the pointer, looking at the code I agree that 
--reset-author-date would be a better alias. If GIT_COMMITTER_DATE is 
not set then the author and committer dates match, otherwise the author 
date is reset to the current time. The code also shows how we should be 
combining --ignore-date and --committer-date-is-author-date.


Best Wishes

Phillip


Re: minor interactive rebase regression: HEAD points to wrong commit while rewording

2019-08-15 Thread Phillip Wood

On 14/08/2019 22:20, SZEDER Gábor wrote:

On Mon, Aug 12, 2019 at 09:28:52PM +0100, Phillip Wood wrote:

Save the updated commit message, and after the editor opens up the
third commit's log message, check again where HEAD is pointing to now:

   ~/tmp/reword (master +|REBASE-i 2/3)$ head -n1 .git/COMMIT_EDITMSG
   third
   ~/tmp/reword (master +|REBASE-i 2/3)$ git log --oneline -1
   c3db735 (HEAD) second - updated


As second has been updated the sequencer cannot fast-forward to third so it
cherry-picks third and then passes --edit when it runs 'git commit' to
commit the cherry-pick. HEAD is updated once the reworded commit has been
created.

I think the scripted rebase always ran cherry-pick and then ran 'commit
--amend' afterwards if the commit was being reworded. The C implementation
is more efficient as it avoids creating an redundant commit but has the side
effect that HEAD is not updated before the reword which was surprising here.


I'm not sure about this more efficient thing.  I mean, 'git rebase' is
about to launch the editor to let the user type something...  Compared
to that the time spent in creating an extra commit object is surely
negligible.


I changed the sequencer to always commit the cherry-pick and then run 
'git commit --amend' for rewords [1]. Running


	time env GIT_EDITOR=true GIT_SEQUENCE_EDITOR='sed -i s/pick/reword/' 
../bin-wrappers/git rebase -i --root


over 100 commits I cannot see any real difference in the timings between 
master and that branch. Any difference is within the variation of the 
times of multiple runs. The change also fixes a bug when rewording a 
re-arranged root commit.


Best Wishes

Phillip

[1] https://github.com/phillipwood/git/commits/wip/rebase-reword-update-head


Re: [GSoC][PATCH v2 5/6] rebase -i: support --ignore-date

2019-08-14 Thread Phillip Wood

On 13/08/2019 22:45, Junio C Hamano wrote:

Rohit Ashiwal  writes:


  --ignore-date::
-   This flag is passed to 'git am' to change the author date
-   of the rebased commits (see linkgit:git-am[1]).
+   Instead of using the given author date, re-set it to the value
+   same as committer (current) date. This implies --force-rebase.


s/to the value same as .* date\./the current time./;

The more important thing is that we record the current timestamp as
the author date; that timestamp being very close to the committer
date of the resulting commit is a mere consequence of the fact that
we use the current time for committer date and much less important.


That's an important distinction, particularly if GIT_COMMITTER_DATE is 
set in the environment - are we aiming to have the author and committer 
dates match or are we just resetting the author date to now? Rohit - do 
you know which --ignore-date does in the am based rebase?


Best Wishes

Phillip



Again, I think reset-author-date would be a better synonym to this
one.



Re: [GSoC][PATCH v2 5/6] rebase -i: support --ignore-date

2019-08-14 Thread Phillip Wood

Hi Junio & Rohit

On 13/08/2019 18:21, Junio C Hamano wrote:

Phillip Wood  writes:


+static void push_dates(struct child_process *child)
+{
+   time_t now = time(NULL);
+   struct strbuf date = STRBUF_INIT;
+
+   strbuf_addf(&date, "@%"PRIuMAX, (uintmax_t)now);
+   argv_array_pushf(&child->args, "--date=%s", date.buf);


it doesn't matter but it might have been nicer to set both dates the
same way in the environment.
+   argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf);


We can see that this date string lacks timezone information, which
would likely fall back to whatever timezone the user is in.  Is that
what we want?  I am guessing it is, as we are dealing with "now"
timestamp, but wanted to double check.


I think we probably want to use the local timezone as you suggest


+   if (opts->ignore_date) {
+   if (!author)
+   BUG("ignore-date can only be used with "
+   "rebase, which must set the author "
+   "before committing the tree");
+   ignore_author_date(&author);


Is this leaking the old author? I'd rather see

tmp_author = ignore_author_date(author);
free(author);
author = tmp_author;


Or make sure ignore_author_date() does not leak the original, when
it rewrites its parameter.

But I have a larger question at the higher design level.  Why are we
passing a single string "author" around, instead of parsed and split
fields, like  tuple?  That would allow us
to replace only the time part a lot more easily.  Would it make the
other parts of the code more cumbersome (I didn't check---and if
that is the case, then that is a valid reason why we want to stick
to the current "a single string 'author' keeps the necessary info
for the 4-tuple" design).


It's a bit of a mess at the moment. There are places where we want a 
single author data string when calling commit_tree_extended(), and other 
places where we want to set the name, email and date in the environment 
when running 'git commit'. For the latter case we use a file which we 
read and write as the C version just follows what the shell script did. 
I think carrying round a  tuple would be the 
sensible way to go and we can build the author string when we need it. 
Doing that would hopefully eliminate having to read and write the author 
file so much. I haven't looked at how difficult it would be to change 
the existing code to do that. We should also really carry the commit 
message around in a variable and only write it to a file if a pick fails 
or we are editing the message and running 'git commit'. If we're just 
using commit_tree_extended() there is no need to be writing the message 
to a file and then reading it back in again later.


Best Wishes

Phillip


+   }
res = commit_tree(msg.buf, msg.len, cache_tree_oid,
  NULL, &root_commit, author,
  opts->gpg_sign);
+   }
strbuf_release(&msg);
strbuf_release(&script);
@@ -1053,6 +1087,8 @@ static int run_git_commit(struct repository *r,
argv_array_push(&cmd.args, "--amend");
if (opts->gpg_sign)
argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+   if (opts->ignore_date)
+   push_dates(&cmd);
if (defmsg)
argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
else if (!(flags & EDIT_MSG))
@@ -1515,6 +1551,11 @@ static int try_to_commit(struct repository *r,
reset_ident_date();
   +if (opts->ignore_date) {
+   ignore_author_date(&author);
+   free(author_to_free);


Where is author_to_free set? We should always free the old author, see
above.


Or require callers to pass a free()able memory to ignore_author_date()
and have the callee free the original?



Re: [GSoC][PATCH v2 3/6] rebase -i: support --committer-date-is-author-date

2019-08-14 Thread Phillip Wood

On 13/08/2019 18:06, Junio C Hamano wrote:

Phillip Wood  writes:
 [...]

+
+   strbuf_addf(&date, "@%s",ident.date_begin);


I think we should use %s.* and ident.date_end to be sure we getting
what we want. Your version is OK if the author is formatted correctly
but I'm uneasy about relying on that when we can get the verified end
from ident.


If the author line is not formatted correctly, split_ident_line()
would notice and return NULL in these fields, I think (in other
words, my take on the call to split_ident_line() above is not
necessarily done in order to "split", but primarily to validate that
the line is formatted correctly---and find the beginning of the
timestamp field).


I just had a read through split_ident_line() and it looks to me like it 
will ignore any junk after the timezone. So long as it sees '+' or '-' 
followed by at least one digit it will use that for the time zone and 
return success regardless of what follows it so I think we want to pay 
attention to the end data it returns for the date and timezone.



But your "pay attention to date_end" raises an interesting point.

The string that follows ident.date_begin would be a large integer
(i.e. number of seconds since epoch), a SP, a positive or negative
sign (i.e. east or west of GMT), 4 digits (i.e. timezone offset), so
if you want to leave something like "@1544328981" in the buffer, you
need to stop at .date_end to omit the timezone information.

On the other hand, if you do want the timezone information as well
(which I think is the case for this codepath), you should not stop
at there and have something like "@1544328981 +0900", the code as
written would give better result.


Good point, I had forgotten that split_ident_line() returned separate 
fields for the date and timezone. I agree that we want the timezone here 
too. I  I think it would be a good idea to beef up the tests to use a 
non default timezone to check that we are actually setting it correctly.


Best Wishes

Phillip



Re: [GSoC][PATCH v2 3/6] rebase -i: support --committer-date-is-author-date

2019-08-13 Thread Phillip Wood

On 12/08/2019 20:42, Rohit Ashiwal wrote:

rebase am already has this flag to "lie" about the committer date
by changing it to the author date. Let's add the same for
interactive machinery.

Signed-off-by: Rohit Ashiwal 
---
  Documentation/git-rebase.txt|  8 +++-
  builtin/rebase.c| 20 ++---
  sequencer.c | 57 -
  sequencer.h |  1 +
  t/t3422-rebase-incompatible-options.sh  |  1 -
  t/t3433-rebase-options-compatibility.sh | 19 +
  6 files changed, 96 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 28e5e08a83..697ce8e6ff 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -383,8 +383,12 @@ default is `--no-fork-point`, otherwise the default is 
`--fork-point`.
  See also INCOMPATIBLE OPTIONS below.
  
  --committer-date-is-author-date::

+   Instead of recording the time the rebased commits are
+   created as the committer date, reuse the author date
+   as the committer date. This implies --force-rebase.
+
  --ignore-date::
-   These flags are passed to 'git am' to easily change the dates
+   This flag is passed to 'git am' to change the author date


Very minor nit-pick. This has lost the plural for 'dates'. I'm not sure 
this is correct as there will be more than one date because the commits 
will have different dates. If it had said 'change the date of each 
rebased commit' then the singular would definitely be right but as it 
stands I'm not sure this is an improvement.


Best Wishes

Phillip


of the rebased commits (see linkgit:git-am[1]).
  +
  See also INCOMPATIBLE OPTIONS below.
@@ -522,7 +526,6 @@ INCOMPATIBLE OPTIONS
  
  The following options:
  
- * --committer-date-is-author-date

   * --ignore-date
   * --whitespace
   * -C
@@ -548,6 +551,7 @@ In addition, the following pairs of options are 
incompatible:
   * --preserve-merges and --signoff
   * --preserve-merges and --rebase-merges
   * --preserve-merges and --ignore-whitespace
+ * --preserve-merges and --committer-date-is-author-date
   * --rebase-merges and --ignore-whitespace
   * --rebase-merges and --strategy
   * --rebase-merges and --strategy-option
diff --git a/builtin/rebase.c b/builtin/rebase.c
index ab1bbb78ee..b1039f8db0 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -82,6 +82,7 @@ struct rebase_options {
int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
+   int committer_date_is_author_date;
char *cmd;
int allow_empty_message;
int rebase_merges, rebase_cousins;
@@ -114,6 +115,8 @@ static struct replay_opts get_replay_opts(const struct 
rebase_options *opts)
replay.allow_empty_message = opts->allow_empty_message;
replay.verbose = opts->flags & REBASE_VERBOSE;
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+   replay.committer_date_is_author_date =
+   opts->committer_date_is_author_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
  
@@ -533,6 +536,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)

warning(_("--[no-]rebase-cousins has no effect without "
  "--rebase-merges"));
  
+	if (opts.committer_date_is_author_date)

+   opts.flags |= REBASE_FORCE;
+
return !!run_rebase_interactive(&opts, command);
  }
  
@@ -981,6 +987,8 @@ static int run_am(struct rebase_options *opts)
  
  	if (opts->ignore_whitespace)

argv_array_push(&am.args, "--ignore-whitespace");
+   if (opts->committer_date_is_author_date)
+   argv_array_push(&opts->git_am_opts, 
"--committer-date-is-author-date");
if (opts->action && !strcmp("continue", opts->action)) {
argv_array_push(&am.args, "--resolved");
argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
@@ -1424,9 +1432,9 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
OPT_BOOL(0, "signoff", &options.signoff,
 N_("add a Signed-off-by: line to each commit")),
-   OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
- &options.git_am_opts, NULL,
- N_("passed to 'git am'"), PARSE_OPT_NOARG),
+   OPT_BOOL(0, "committer-date-is-author-date",
+&options.committer_date_is_author_date,

Re: [GSoC][PATCH v2 4/6] sequencer: rename amend_author to author_to_rename

2019-08-13 Thread Phillip Wood

Hi Rohit

On 12/08/2019 20:42, Rohit Ashiwal wrote:

The purpose of amend_author was to free() the malloc()'d string
obtained from get_author() while amending a commit. But we can
also use the variable to free() the author at our convenience.
Rename it to convey this meaning.


Thanks for rewording this

Best Wishes

Phillip



Signed-off-by: Rohit Ashiwal 
---
  sequencer.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index fbc0ed0cad..e186136ccc 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1424,7 +1424,7 @@ static int try_to_commit(struct repository *r,
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
struct strbuf commit_msg = STRBUF_INIT;
-   char *amend_author = NULL;
+   char *author_to_free = NULL;
const char *hook_commit = NULL;
enum commit_msg_cleanup_mode cleanup;
int res = 0;
@@ -1445,7 +1445,7 @@ static int try_to_commit(struct repository *r,
strbuf_addstr(msg, orig_message);
hook_commit = "HEAD";
}
-   author = amend_author = get_author(message);
+   author = author_to_free = get_author(message);
unuse_commit_buffer(current_head, message);
if (!author) {
res = error(_("unable to parse commit author"));
@@ -1534,7 +1534,7 @@ static int try_to_commit(struct repository *r,
free_commit_extra_headers(extra);
strbuf_release(&err);
strbuf_release(&commit_msg);
-   free(amend_author);
+   free(author_to_free);
  
  	return res;

  }



Re: [GSoC][PATCH v2 5/6] rebase -i: support --ignore-date

2019-08-13 Thread Phillip Wood
L(0, "ignore-whitespace", &options.ignore_whitespace,
@@ -1705,13 +1712,15 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
  
-	if (options.committer_date_is_author_date)

+   if (options.ignore_date)
+   options.committer_date_is_author_date = 0;


We should probably print an error if the user gives 
--committer-date-is-author-date and --author-date-is-committer-date (and 
in cmd_rebase__interactive() if we keep this option there)



+   if (options.committer_date_is_author_date ||
+   options.ignore_date)
options.flags |= REBASE_FORCE;
  
  	for (i = 0; i < options.git_am_opts.argc; i++) {

const char *option = options.git_am_opts.argv[i], *p;
-   if (!strcmp(option, "--ignore-date") ||
-   !strcmp(option, "--whitespace=fix") ||
+   if (!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
else if (skip_prefix(option, "-C", &p)) {
diff --git a/sequencer.c b/sequencer.c
index e186136ccc..aecd9b4ad8 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -148,6 +148,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, 
"rebase-merge/refs-to-delete")
   */
  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
  static GIT_PATH_FUNC(rebase_path_cdate_is_adate, 
"rebase-merge/cdate_is_adate")
+static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
  static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
  static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
  static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -919,6 +920,31 @@ static const char *read_author_ident(struct strbuf *buf)
return buf->buf;
  }
  
+static void ignore_author_date(const char **author)

+{
+   int len = strlen(*author);
+   struct ident_split ident;
+   struct strbuf new_author = STRBUF_INIT;
+
+   split_ident_line(&ident, *author, len);
+   len = ident.mail_end - ident.name_begin + 1;
+
+   strbuf_addf(&new_author, "%.*s", len, *author);
+   datestamp(&new_author);
+   *author = strbuf_detach(&new_author, NULL);
+}


It's good to see this using the indet api. I think this would be nicer 
if it took a char* returned the new author rather than changing the 
function argument, particularly as it does not free the string that is 
passed in so the ownership is unclear.



+
+static void push_dates(struct child_process *child)
+{
+   time_t now = time(NULL);
+   struct strbuf date = STRBUF_INIT;
+
+   strbuf_addf(&date, "@%"PRIuMAX, (uintmax_t)now);
+   argv_array_pushf(&child->args, "--date=%s", date.buf);


it doesn't matter but it might have been nicer to set both dates the 
same way in the environment.



+   argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf);
+   strbuf_release(&date);
+}
+
  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -1020,10 +1046,18 @@ static int run_git_commit(struct repository *r,
  
  		if (res <= 0)

res = error_errno(_("could not read '%s'"), defmsg);
-   else
+   else {
+   if (opts->ignore_date) {
+   if (!author)
+   BUG("ignore-date can only be used with "
+   "rebase, which must set the author "
+   "before committing the tree");
+   ignore_author_date(&author);


Is this leaking the old author? I'd rather see

tmp_author = ignore_author_date(author);
free(author);
author = tmp_author;


+   }
res = commit_tree(msg.buf, msg.len, cache_tree_oid,
  NULL, &root_commit, author,
  opts->gpg_sign);
+   }
  
  		strbuf_release(&msg);

strbuf_release(&script);
@@ -1053,6 +1087,8 @@ static int run_git_commit(struct repository *r,
argv_array_push(&cmd.args, "--amend");
if (opts->gpg_sign)
    argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+   if (opts->ignore_date)
+   push_dates(&cmd);
if (

Re: [GSoC][PATCH v2 3/6] rebase -i: support --committer-date-is-author-date

2019-08-13 Thread Phillip Wood

On 13/08/2019 11:38, Phillip Wood wrote:

Hi Rohit

[...]

@@ -964,6 +976,25 @@ static int run_git_commit(struct repository *r,
  {
  struct child_process cmd = CHILD_PROCESS_INIT;
+    if (opts->committer_date_is_author_date) {
+    size_t len;
+    int res = -1;
+    struct strbuf datebuf = STRBUF_INIT;
+    char *date = read_author_date_or_null();


You must always check the return value of functions that might return 
NULL. In this case we should return an error as you do in try_to 
_commit() later



+
+    strbuf_addf(&datebuf, "@%s", date);


GNU printf() will add something like '(null)' to the buffer if you pass 
a NULL pointer so I don't think we can be sure that this will not 
increase the length of the buffer if date is NULL.


I should have added that passing NULL to snprintf() and friends is going 
to be undefined behavior anyway so you shouldn't do it for that reason 
alone.


Best Wishes

Phillip

 An explicit check
above would be much clearer as well rather than checking len later. What 
happens if you don't add the '@' at the beginning? (I'm don't know much 
about git's date handling)



+    free(date);
+
+    date = strbuf_detach(&datebuf, &len);
+
+    if (len > 1)
+    res = setenv("GIT_COMMITTER_DATE", date, 1);
+
+    free(date);
+
+    if (res)
+    return -1;
+    }
  if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
  struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
  const char *author = NULL;
@@ -1400,7 +1431,6 @@ static int try_to_commit(struct repository *r,
  if (parse_head(r, ¤t_head))
  return -1;
-
  if (flags & AMEND_MSG) {
  const char *exclude_gpgsig[] = { "gpgsig", NULL };
  const char *out_enc = get_commit_output_encoding();
@@ -1427,6 +1457,21 @@ static int try_to_commit(struct repository *r,
  commit_list_insert(current_head, &parents);
  }
+    if (opts->committer_date_is_author_date) {
+    int len = strlen(author);
+    struct ident_split ident;
+    struct strbuf date = STRBUF_INIT;
+
+    split_ident_line(&ident, author, len);
+
+    if (!ident.date_begin)
+    return error(_("corrupted author without date 
information"));


We return an error if we cannot get the date - this is exactly what we 
should be doing above. It is also great to see a single version of this 
being used whether or not we are amending.



+
+    strbuf_addf(&date, "@%s",ident.date_begin);


I think we should use %s.* and ident.date_end to be sure we getting what 
we want. Your version is OK if the author is formatted correctly but I'm 
uneasy about relying on that when we can get the verified end from ident.


Best Wishes

Phillip


+    setenv("GIT_COMMITTER_DATE", date.buf, 1);
+    strbuf_release(&date);
+    }
+
  if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
  res = error(_("git write-tree failed to write a tree"));
  goto out;
@@ -2542,6 +2587,11 @@ static int read_populate_opts(struct 
replay_opts *opts)

  opts->signoff = 1;
  }
+    if (file_exists(rebase_path_cdate_is_adate())) {
+    opts->allow_ff = 0;
+    opts->committer_date_is_author_date = 1;
+    }
+
  if (file_exists(rebase_path_reschedule_failed_exec()))
  opts->reschedule_failed_exec = 1;
@@ -2624,6 +2674,8 @@ int write_basic_state(struct replay_opts *opts, 
const char *head_name,
  write_file(rebase_path_gpg_sign_opt(), "-S%s\n", 
opts->gpg_sign);

  if (opts->signoff)
  write_file(rebase_path_signoff(), "--signoff\n");
+    if (opts->committer_date_is_author_date)
+    write_file(rebase_path_cdate_is_adate(), "%s", "");
  if (opts->reschedule_failed_exec)
  write_file(rebase_path_reschedule_failed_exec(), "%s", "");
@@ -3821,7 +3873,8 @@ static int pick_commits(struct repository *r,
  setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
  if (opts->allow_ff)
  assert(!(opts->signoff || opts->no_commit ||
-    opts->record_origin || opts->edit));
+    opts->record_origin || opts->edit ||
+    opts->committer_date_is_author_date));
  if (read_and_refresh_cache(r, opts))
  return -1;
diff --git a/sequencer.h b/sequencer.h
index 6704acbb9c..e3881e9275 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -43,6 +43,7 @@ struct replay_opts {
  int verbose;
  int quiet;
  int reschedule_failed_exec;
+    int committer_date_is_author_date;
  int mainline;
diff --git a/t/t3422-rebase-incompatible-options.sh 
b/t/t3422-rebase-incompatible-op

Re: [GSoC][PATCH v2 1/6] rebase -i: add --ignore-whitespace flag

2019-08-13 Thread Phillip Wood

Hi Rohit

Thanks for the re-roll

On 12/08/2019 20:42, Rohit Ashiwal wrote:

There are two backends available for rebasing, viz, the am and the
interactive. Naturally, there shall be some features that are
implemented in one but not in the other. One such flag is
--ignore-whitespace which indicates merge mechanism to treat lines
with only whitespace changes as unchanged. Wire the interactive
rebase to also understand the --ignore-whitespace flag by
translating it to -Xignore-space-change.

Signed-off-by: Rohit Ashiwal 
---
  Documentation/git-rebase.txt| 10 +++-
  builtin/rebase.c| 29 +--
  t/t3422-rebase-incompatible-options.sh  |  1 -
  t/t3433-rebase-options-compatibility.sh | 65 +
  4 files changed, 97 insertions(+), 8 deletions(-)
  create mode 100755 t/t3433-rebase-options-compatibility.sh

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 6156609cf7..28e5e08a83 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -371,8 +371,13 @@ If either  or --root is given on the command 
line, then the
  default is `--no-fork-point`, otherwise the default is `--fork-point`.
  
  --ignore-whitespace::

+   This flag is either passed to the 'git apply' program
+   (see linkgit:git-apply[1]), or to 'git merge' program
+   (see linkgit:git-merge[1]) as `-Xignore-space-change`,
+   depending on which backend is selected by other options.


I still think this should document what it does rather than how it is 
implemented - see my previous comments.

+
  --whitespace=::
-   These flag are passed to the 'git apply' program
+   This flag is passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
  +
  See also INCOMPATIBLE OPTIONS below.
@@ -520,7 +525,6 @@ The following options:
   * --committer-date-is-author-date
   * --ignore-date
   * --whitespace
- * --ignore-whitespace
   * -C
  
  are incompatible with the following options:

@@ -543,6 +547,8 @@ In addition, the following pairs of options are 
incompatible:
   * --preserve-merges and --interactive
   * --preserve-merges and --signoff
   * --preserve-merges and --rebase-merges
+ * --preserve-merges and --ignore-whitespace
+ * --rebase-merges and --ignore-whitespace
   * --rebase-merges and --strategy
   * --rebase-merges and --strategy-option
  
diff --git a/builtin/rebase.c b/builtin/rebase.c

index 670096c065..ab1bbb78ee 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,7 @@ struct rebase_options {
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
+   int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
char *cmd;
@@ -99,6 +100,7 @@ struct rebase_options {
  
  static struct replay_opts get_replay_opts(const struct rebase_options *opts)

  {
+   char *strategy_opts = opts->strategy_opts;


strategy_opts is a shallow copy of opts->strategy_opts - this will cause 
problems later



struct replay_opts replay = REPLAY_OPTS_INIT;
  
  	replay.action = REPLAY_INTERACTIVE_REBASE;

@@ -114,8 +116,19 @@ static struct replay_opts get_replay_opts(const struct 
rebase_options *opts)
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
-   if (opts->strategy_opts)
-   parse_strategy_opts(&replay, opts->strategy_opts);
+
+   if (opts->ignore_whitespace) {
+   struct strbuf buf = STRBUF_INIT;
+
+   if (strategy_opts)
+   strbuf_addstr(&buf, strategy_opts);


I'd rewrite this as
if (opts->strategy_opts)
strbuf_addstr(&buf, opts->strategy_opts);

without the outer if testing opts->ignore_whitespace

+

then add
if (opts->ignore_whitespace)
here

+   strbuf_addstr(&buf, " --ignore-space-change");
+   free(strategy_opts);


and then you don't need this free() or strategy_opts. At the moment this 
has freed opts->stragety_opts which is what we were trying to avoid, in 
fact it's slightly worse than the last version because we don't change 
opts->strategy_opts to reflect the fact it has been freed. Also the 
caller cannot know if it has been freed as it depends what other options 
are set.



+   strategy_opts = strbuf_detach(&buf, NULL);
+   }
+   if (strategy_opts)
+   parse_strategy_opts(&replay, strategy_opts);


replace this withe
if (buf.len)
parse_strategy_opts(&replay, buf.buf);
    strbuf_release(&buf);

This way we never change opts->strategy_opts and we always release the 
temporary copy.


Best Wishes

Phillip

  
  	return replay;

  }
@@ -511

Re: [GSoC][PATCH v2 3/6] rebase -i: support --committer-date-is-author-date

2019-08-13 Thread Phillip Wood
;, NULL, &options.git_am_opts, N_("n"),
@@ -1697,10 +1705,12 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
  
+	if (options.committer_date_is_author_date)

+   options.flags |= REBASE_FORCE;
+
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
-   if (!strcmp(option, "--committer-date-is-author-date") ||
-   !strcmp(option, "--ignore-date") ||
+   if (!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
diff --git a/sequencer.c b/sequencer.c
index 30d77c2682..fbc0ed0cad 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, 
"rebase-merge/refs-to-delete")
   * command-line.
   */
  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
  static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
  static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
  static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -879,6 +880,17 @@ static char *get_author(const char *message)
return NULL;
  }
  
+/* Returns a "date" string that needs to be free()'d by the caller */

+static char *read_author_date_or_null(void)
+{
+   char *date;
+
+   if (read_author_script(rebase_path_author_script(),
+  NULL, NULL, &date, 0))
+   return NULL;
+   return date;
+}
+
  /* Read author-script and return an ident line (author  timestamp) */
  static const char *read_author_ident(struct strbuf *buf)
  {
@@ -964,6 +976,25 @@ static int run_git_commit(struct repository *r,
  {
struct child_process cmd = CHILD_PROCESS_INIT;
  
+	if (opts->committer_date_is_author_date) {

+   size_t len;
+   int res = -1;
+   struct strbuf datebuf = STRBUF_INIT;
+   char *date = read_author_date_or_null();


You must always check the return value of functions that might return 
NULL. In this case we should return an error as you do in try_to 
_commit() later



+
+   strbuf_addf(&datebuf, "@%s", date);


GNU printf() will add something like '(null)' to the buffer if you pass 
a NULL pointer so I don't think we can be sure that this will not 
increase the length of the buffer if date is NULL. An explicit check 
above would be much clearer as well rather than checking len later. What 
happens if you don't add the '@' at the beginning? (I'm don't know much 
about git's date handling)



+   free(date);
+
+   date = strbuf_detach(&datebuf, &len);
+
+   if (len > 1)
+   res = setenv("GIT_COMMITTER_DATE", date, 1);
+
+   free(date);
+
+   if (res)
+   return -1;
+   }
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
const char *author = NULL;
@@ -1400,7 +1431,6 @@ static int try_to_commit(struct repository *r,
  
  	if (parse_head(r, ¤t_head))

return -1;
-
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
@@ -1427,6 +1457,21 @@ static int try_to_commit(struct repository *r,
commit_list_insert(current_head, &parents);
}
  
+	if (opts->committer_date_is_author_date) {

+   int len = strlen(author);
+   struct ident_split ident;
+   struct strbuf date = STRBUF_INIT;
+
+   split_ident_line(&ident, author, len);
+
+   if (!ident.date_begin)
+       return error(_("corrupted author without date 
information"));


We return an error if we cannot get the date - this is exactly what we 
should be doing above. It is also great to see a single version of this 
being used whether or not we are amending.



+
+   strbuf_addf(&date, "@%s",ident.date_begin);


I think we should use %s.* and ident.date_end to be sure we getting what 
we want. Your version is OK if the author is formatted correctly but I'm 
uneasy about relying on that when we can get the verified end from ident.


Best Wishes

Phillip


+   setenv("GIT_COMMITTER_DAT

Re: minor interactive rebase regression: HEAD points to wrong commit while rewording

2019-08-12 Thread Phillip Wood

On 12/08/2019 18:50, SZEDER Gábor wrote:


When running interactive rebase to reword a commit message, I would
expect that the commit whose message I'm rewording is checked out.
This is not quite the case when rewording multiple subsequent commit
messages.

Let's start with four commits, and start an interactive rebase from
the first commit:

   $ git log --oneline
   5835aa1 (HEAD -> master) fourth
   64ecc64 third
   d5fad83 second
   384b86f first
   $ git rebase -i 384b86f

Update the instruction sheet to edit the log messages of two
subsequent commits:

   r d5fad83 second
   r 64ecc64 third
   pick 5835aa1 fourth

Now, after the editor opens up the second commit's log message, start
a new terminal and check where HEAD is pointing to:

   ~/tmp/reword (master|REBASE-i 1/3)$ head -n1 .git/COMMIT_EDITMSG
   second
   ~/tmp/reword (master|REBASE-i 1/3)$ git log --oneline -1
   d5fad83 (HEAD) second

So far so good.


Because the sequencer can fast-forwarded to second from first it does 
that and then run 'commit --amend' to do the reword.



Save the updated commit message, and after the editor opens up the
third commit's log message, check again where HEAD is pointing to now:

   ~/tmp/reword (master +|REBASE-i 2/3)$ head -n1 .git/COMMIT_EDITMSG
   third
   ~/tmp/reword (master +|REBASE-i 2/3)$ git log --oneline -1
   c3db735 (HEAD) second - updated


As second has been updated the sequencer cannot fast-forward to third so 
it cherry-picks third and then passes --edit when it runs 'git commit' 
to commit the cherry-pick. HEAD is updated once the reworded commit has 
been created.


I think the scripted rebase always ran cherry-pick and then ran 'commit 
--amend' afterwards if the commit was being reworded. The C 
implementation is more efficient as it avoids creating an redundant 
commit but has the side effect that HEAD is not updated before the 
reword which was surprising here.


I don't think I've ever looked at HEAD while rewording, my shell prompt 
gets the current pick from .git/rebase-merge/done so does not look at 
HEAD. While it might seem odd if the user looks at HEAD it's quite nice 
not to create a new commit only to amend it straight away when it's 
reworded. We have REBASE_HEAD which always points to the current pick - 
HEAD is also an unreliable indicator of the current pick if there are 
conflicts.


Best Wishes

Phillip


As you can see, HEAD still points to the (now rewritten) second
commit.

It's only HEAD, though: notice the '+' in the git prompt, indicating
that both the worktree and index are dirty.  And indeed, they both
already match the state of the currently reworded, i.e. third, commit:

   ~/tmp/reword (master +|REBASE-i 2/3)$ cat file
   third

This is good, because even though HEAD has not been updated yet, it
already allows users to take a look at the "big picture", i.e. actual
file contents, in case the diff included in the commit message
template doesn't show enough context.

This behavior changed in commit 18633e1a22 (rebase -i: use the
rebase--helper builtin, 2017-02-09); prior to that HEAD pointed to the
third commit while editing its log message.

It's important to reword subsequent commits.  When rewording multiple,
but non subsequent commits (e.g. reword, pick, reword in the
instruction sheet), then HEAD is pointing to the right commits during
both rewords.




Re: Incorrect behavior from git checkout --patch

2019-08-11 Thread Phillip Wood

Hi Dave

On 11/08/2019 10:54, Phillip Wood wrote:

Hi Dave

Thanks for the bug report. I've tried to reproduce it on the latest 
master, version 2.22.0 and 2.20.1 and am unable to do so.


Doh, I was doing 'git checkout -p HEAD', when I checkout from the index 
I can reproduce the bug and it is fixed by the patch I linked to earlier 
which will be in git 2.23.0. That will be released soon (we're at 
2.23.0.rc2 at the moment)


Thanks again for taking the time to report the bug

Best Wishes

Phillip


I thought it 
might be related to a bug I recently fixed[1] but it does not appear to 
be. I've appended the files I used below just in case I made a mistake 
translating your patches to files that can be used with git checkout.


Best Wishes

Phillip

[1] 
https://github.com/git/git/commit/1b074e15d0f976be2bc14f9528874a841c055213#diff-588be9a03d1f7e33db12f186aad5fde9 



pre-image

block_one {
line 1
line 2
line 3
2 4 6 8
line 4
line 5
line 6
2 4 6 8
line 7
line 8
line 9
2 4 6 8
line 10
line 11
line 12
}

block_two {
line 1
line 2
line 3
2 5 6 9
line 4
line 5
line 6
2 5 6 9
line 7
line 8
line 9
2 5 6 9
line 10
line 11
line 12
}

post-image

block_one {
line 1
line 1.5
line 2
line 2.5
line 3
2 4 6 8
line 4
line 4.5
line 5
line 5.5
line 6
2 4 6 8
line 7
line 7.5
line 8
line 8.5
line 9
2 4 6 8
line 10
line 10.5
line 11
line 11.5
line 12
}

block_two {
line 1
line 1.5
line 2
line 2.5
line 3
2 5 6 9
line 4
line 4.5
line 5
line 5.5
line 6
2 5 6 9
line 7
line 7.5
line 8
line 8.5
line 9
2 5 6 9
line 10
line 10.5
line 11
line 11.5
line 12
}



On 10/08/2019 21:12, Dave Kaminski wrote:
I am observing git checkout --patch making changes to the wrong lines 
of a file.


This is with a clean install of git version 2.20.1 on a debian docker
container (image tag 10.0 which is also "latest" as of this writing).

With a diff that looks like the following:

diff --git a/file.txt b/file.txt
index 868aa22..ea4d786 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
-2 5 6 9
+2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
-2 5 6 9
+2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 5 6 9
+2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

doing a `git checkout --patch -- ./file.txt`, splitting the diff into
hunks, and discarding all of the hunks that begin with numbers, e.g.

@@ -22,3 +32,3 @@
  line 3
-2 5 6 9
+2 4 6 8
  line 4

the expected state of the file in the working directory is this:

diff --git a/file.txt b/file.txt
index 868aa22..9ab67a1 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 5 6 9
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 5 6 9
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 5 6 9
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

but instead the actual state of the file is this:

diff --git a/file.txt b/file.txt
index 868aa22..76fe65d 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 4 6 8
+2 5 6 9
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 5 6 9
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 5 6 9
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 5 6 9
+2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

See the changes between "line 9" and "line 10" in both blocks that are
not correct.



Re: Incorrect behavior from git checkout --patch

2019-08-11 Thread Phillip Wood

Hi Dave

Thanks for the bug report. I've tried to reproduce it on the latest 
master, version 2.22.0 and 2.20.1 and am unable to do so. I thought it 
might be related to a bug I recently fixed[1] but it does not appear to 
be. I've appended the files I used below just in case I made a mistake 
translating your patches to files that can be used with git checkout.


Best Wishes

Phillip

[1] 
https://github.com/git/git/commit/1b074e15d0f976be2bc14f9528874a841c055213#diff-588be9a03d1f7e33db12f186aad5fde9


pre-image

block_one {
line 1
line 2
line 3
2 4 6 8
line 4
line 5
line 6
2 4 6 8
line 7
line 8
line 9
2 4 6 8
line 10
line 11
line 12
}

block_two {
line 1
line 2
line 3
2 5 6 9
line 4
line 5
line 6
2 5 6 9
line 7
line 8
line 9
2 5 6 9
line 10
line 11
line 12
}

post-image

block_one {
line 1
line 1.5
line 2
line 2.5
line 3
2 4 6 8
line 4
line 4.5
line 5
line 5.5
line 6
2 4 6 8
line 7
line 7.5
line 8
line 8.5
line 9
2 4 6 8
line 10
line 10.5
line 11
line 11.5
line 12
}

block_two {
line 1
line 1.5
line 2
line 2.5
line 3
2 5 6 9
line 4
line 4.5
line 5
line 5.5
line 6
2 5 6 9
line 7
line 7.5
line 8
line 8.5
line 9
2 5 6 9
line 10
line 10.5
line 11
line 11.5
line 12
}



On 10/08/2019 21:12, Dave Kaminski wrote:

I am observing git checkout --patch making changes to the wrong lines of a file.

This is with a clean install of git version 2.20.1 on a debian docker
container (image tag 10.0 which is also "latest" as of this writing).

With a diff that looks like the following:

diff --git a/file.txt b/file.txt
index 868aa22..ea4d786 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
-2 5 6 9
+2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
-2 5 6 9
+2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 5 6 9
+2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

doing a `git checkout --patch -- ./file.txt`, splitting the diff into
hunks, and discarding all of the hunks that begin with numbers, e.g.

@@ -22,3 +32,3 @@
  line 3
-2 5 6 9
+2 4 6 8
  line 4

the expected state of the file in the working directory is this:

diff --git a/file.txt b/file.txt
index 868aa22..9ab67a1 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 5 6 9
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 5 6 9
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
  2 5 6 9
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

but instead the actual state of the file is this:

diff --git a/file.txt b/file.txt
index 868aa22..76fe65d 100644
--- a/file.txt
+++ b/file.txt
@@ -1,35 +1,51 @@
  block_one {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 4 6 8
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 4 6 8
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 4 6 8
+2 5 6 9
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

  block_two {
  line 1
+line 1.5
  line 2
+line 2.5
  line 3
  2 5 6 9
  line 4
+line 4.5
  line 5
+line 5.5
  line 6
  2 5 6 9
  line 7
+line 7.5
  line 8
+line 8.5
  line 9
-2 5 6 9
+2 4 6 8
  line 10
+line 10.5
  line 11
+line 11.5
  line 12
  }

See the changes between "line 9" and "line 10" in both blocks that are
not correct.



Re: [GSoC][PATCHl 5/6] rebase -i: support --ignore-date

2019-08-08 Thread Phillip Wood

On 08/08/2019 12:42, Phillip Wood wrote:

On 06/08/2019 18:36, Rohit Ashiwal wrote:

rebase am already has this flag to "lie" about the author date
by changing it to the committer (current) date. Let's add the same
for interactive machinery.

Signed-off-by: Rohit Ashiwal 
---

>> [...[

  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, 
run:\n"

@@ -985,7 +997,7 @@ static int run_git_commit(struct repository *r,
  {
  struct child_process cmd = CHILD_PROCESS_INIT;
-    if (opts->committer_date_is_author_date &&
+    if (opts->committer_date_is_author_date && !opts->ignore_date &&
  setenv_committer_date_to_author_date())
  return 1;


We read the author script again just below, can set the committer date 
there by parsing the author string, that would mean you could use the 
same function that works on an author string in try_to_commit() (this 
comment should be on patch 3 I think)


It's a bit more complicated as you've done this to avoid the duplication 
in the previous version. I think it should be possible to do it by 
reading the author identity upfront (protected by 'if 
is_rebase_i(opts)') and processing it appropriately in the two code 
paths. (You might need to refactor some of the functions like 
read_env_script() to do this.) An alternative would be to refactor 
try_to_commit() so that it can create the root commit and delete the 
code here that does that.


Best Wishes

Phillip




  if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
@@ -1013,10 +1025,18 @@ static int run_git_commit(struct repository *r,
  if (res <= 0)
  res = error_errno(_("could not read '%s'"), defmsg);
-    else
+    else {
+    if (opts->ignore_date) {
+    if (!author)
+    BUG("ignore-date can only be used with "
+    "rebase -i, which must set the "


I know it's only a bug message but it's not just 'rebase -i' but 'rebase 
-k', 'rebase -m' ... that use this code path, it would be better just to 
say 'rebase'



+    "author before committing the tree");
+    ignore_author_date(&author);
+    }
  res = commit_tree(msg.buf, msg.len, cache_tree_oid,
    NULL, &root_commit, author,
    opts->gpg_sign);
+    }
  strbuf_release(&msg);
  strbuf_release(&script);
@@ -1046,6 +1066,8 @@ static int run_git_commit(struct repository *r,
  argv_array_push(&cmd.args, "--amend");
  if (opts->gpg_sign)
  argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+    if (opts->ignore_date)
+    argv_array_pushf(&cmd.args, "--date=%ld", time(NULL));


I think this is racy as it only sets the author date, the committer date 
may end up being different.



  if (defmsg)
  argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
  else if (!(flags & EDIT_MSG))
@@ -1425,7 +1447,7 @@ static int try_to_commit(struct repository *r,
  if (parse_head(r, ¤t_head))
  return -1;
  if (!(flags & AMEND_MSG) && opts->committer_date_is_author_date &&
-    setenv_committer_date_to_author_date())
+    !opts->ignore_date && setenv_committer_date_to_author_date())
  return -1;
  if (flags & AMEND_MSG) {
  const char *exclude_gpgsig[] = { "gpgsig", NULL };
@@ -1447,7 +1469,7 @@ static int try_to_commit(struct repository *r,
  res = error(_("unable to parse commit author"));
  goto out;
  }
-    if (opts->committer_date_is_author_date) {
+    if (opts->committer_date_is_author_date && !opts->ignore_date) {


If we only handled committer_date_is_author_date in a single place it 
wouldn't need to be changed twice in this patch



  char *date;
  int len = strlen(author);
  char *idx = memchr(author, '>', len);
@@ -1507,6 +1529,11 @@ static int try_to_commit(struct repository *r,
  reset_ident_date();
+    if (opts->ignore_date) {
+    ignore_author_date(&author);
+    free(author_to_free);
+    author_to_free = (char *)author;
+    }
  if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
   oid, author, opts->gpg_sign, extra)) {
  res = error(_("failed to write commit object"));
@@ -2583,6 +2610,11 @@ static int read_populate_opts(struct 
replay_opts *opts)

  opts->committer_date_is_

Re: [GSoC][PATCHl 1/6] rebase -i: add --ignore-whitespace flag

2019-08-08 Thread Phillip Wood

Hi Rohit

On 06/08/2019 18:36, Rohit Ashiwal wrote:

There are two backends available for rebasing, viz, the am and the
interactive. Naturally, there shall be some features that are
implemented in one but not in the other. One such flag is
--ignore-whitespace which indicates merge mechanism to treat lines
with only whitespace changes as unchanged. Wire the interactive
rebase to also understand the --ignore-whitespace flag by
translating it to -Xignore-space-change.

Signed-off-by: Rohit Ashiwal 
---
  Documentation/git-rebase.txt| 10 +++-
  builtin/rebase.c| 26 --
  t/t3422-rebase-incompatible-options.sh  |  1 -
  t/t3433-rebase-options-compatibility.sh | 65 +
  4 files changed, 95 insertions(+), 7 deletions(-)
  create mode 100755 t/t3433-rebase-options-compatibility.sh

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 5e4e927647..85404fea52 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -371,8 +371,13 @@ If either  or --root is given on the command 
line, then the
  default is `--no-fork-point`, otherwise the default is `--fork-point`.
  
  --ignore-whitespace::

+   This flag is either passed to the 'git apply' program
+   (see linkgit:git-apply[1]), or to 'git merge' program
+   (see linkgit:git-merge[1]) as `-Xignore-space-change`,
+   depending on which backend is selected by other options.


I think it would be better to document the effect of this option rather 
than the implementation detail. It is confusing at the moment as it 
talks about 'git merge' but we don't allow this option with merges.



+
  --whitespace=::
-   These flag are passed to the 'git apply' program
+   This flag is passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
  +
  See also INCOMPATIBLE OPTIONS below.
@@ -520,7 +525,6 @@ The following options:
   * --committer-date-is-author-date
   * --ignore-date
   * --whitespace
- * --ignore-whitespace
   * -C
  
  are incompatible with the following options:

@@ -543,6 +547,8 @@ In addition, the following pairs of options are 
incompatible:
   * --preserve-merges and --interactive
   * --preserve-merges and --signoff
   * --preserve-merges and --rebase-merges
+ * --preserve-merges and --ignore-whitespace
+ * --rebase-merges and --ignore-whitespace
   * --rebase-merges and --strategy
   * --rebase-merges and --strategy-option
  
diff --git a/builtin/rebase.c b/builtin/rebase.c

index db6ca9bd7d..3c195ddc73 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,7 @@ struct rebase_options {
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
+   int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
char *cmd;
@@ -97,7 +98,7 @@ struct rebase_options {
.git_format_patch_opt = STRBUF_INIT \
}
  
-static struct replay_opts get_replay_opts(const struct rebase_options *opts)

+static struct replay_opts get_replay_opts(struct rebase_options *opts)
  {
struct replay_opts replay = REPLAY_OPTS_INIT;
  
@@ -114,6 +115,17 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)


It's a shame this changes the rebase_options that are passed in, this 
function should ideally not modify what is passed in.



replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
+
+   if (opts->ignore_whitespace) {
+   struct strbuf buf = STRBUF_INIT;
+
+   if (opts->strategy_opts)
+   strbuf_addstr(&buf, opts->strategy_opts);
+
+   strbuf_addstr(&buf, " --ignore-space-change");
+   free(opts->strategy_opts);
+   opts->strategy_opts = strbuf_detach(&buf, NULL);
+   }


Instead of modifying opts->strategy_opts perhaps we could just use a 
temporary variable


Best Wishes

Phillip


if (opts->strategy_opts)
parse_strategy_opts(&replay, opts->strategy_opts);
  
@@ -511,6 +523,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)

argc = parse_options(argc, argv, NULL, options,
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
  
+	opts.strategy_opts = xstrdup_or_null(opts.strategy_opts);

+
if (!is_null_oid(&squash_onto))
opts.squash_onto = &squash_onto;
  
@@ -954,6 +968,8 @@ static int run_am(struct rebase_options *opts)

am.git_cmd = 1;
argv_array_push(&am.args, "am");
  
+	if (opts->ignore_whitespace)

+   argv_array_push(&am.args, "--ignore-whitespace");
if (opts->ac

Re: [GSoC][PATCHl 6/6] rebase: add --author-date-is-committer-date

2019-08-08 Thread Phillip Wood

Hi Rohit

On 06/08/2019 18:36, Rohit Ashiwal wrote:

The previous commit introduced --ignore-date flag to interactive
rebase, but the name is actually very vague in context of rebase -i
since there are two dates we can work with. Add an alias to convey
the precise purpose.


That's an excellent idea

Best Wishes

Phillip



Signed-off-by: Rohit Ashiwal 
---
  Documentation/git-rebase.txt | 1 +
  builtin/rebase.c | 2 ++
  2 files changed, 3 insertions(+)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index a5cdf8518b..bb60426911 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -388,6 +388,7 @@ See also INCOMPATIBLE OPTIONS below.
as the committer date. This implies --force-rebase.
  
  --ignore-date::

+--author-date-is-committer-date::
Lie about the author date by re-setting it to the value
same as committer (current) date. This implies --force-rebase.
  +
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7f464fc9ba..a9a42f9ee4 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1433,6 +1433,8 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
OPT_BOOL(0, "committer-date-is-author-date",
 &options.committer_date_is_author_date,
 N_("make committer date match author date")),
+   OPT_BOOL(0, "author-date-is-committer-date", 
&options.ignore_date,
+"ignore author date and use current date"),
OPT_BOOL(0, "ignore-date", &options.ignore_date,
 "ignore author date and use current date"),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),



Re: [GSoC][PATCHl 5/6] rebase -i: support --ignore-date

2019-08-08 Thread Phillip Wood
-1;
if (!(flags & AMEND_MSG) && opts->committer_date_is_author_date &&
-   setenv_committer_date_to_author_date())
+   !opts->ignore_date && setenv_committer_date_to_author_date())
return -1;
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
@@ -1447,7 +1469,7 @@ static int try_to_commit(struct repository *r,
res = error(_("unable to parse commit author"));
goto out;
}
-   if (opts->committer_date_is_author_date) {
+   if (opts->committer_date_is_author_date && !opts->ignore_date) {


If we only handled committer_date_is_author_date in a single place it 
wouldn't need to be changed twice in this patch



char *date;
int len = strlen(author);
char *idx = memchr(author, '>', len);
@@ -1507,6 +1529,11 @@ static int try_to_commit(struct repository *r,
  
  	reset_ident_date();
  
+	if (opts->ignore_date) {

+   ignore_author_date(&author);
+   free(author_to_free);
+   author_to_free = (char *)author;
+   }
if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
 oid, author, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object"));
@@ -2583,6 +2610,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->committer_date_is_author_date = 1;
}
  
+		if (file_exists(rebase_path_ignore_date())) {

+   opts->allow_ff = 0;
+   opts->ignore_date = 1;
+   }
+
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
  
@@ -2667,6 +2699,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,

write_file(rebase_path_signoff(), "--signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
+   if (opts->ignore_date)
+   write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
  
@@ -3484,6 +3518,9 @@ static int do_merge(struct repository *r,

argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
+   if (opts->ignore_date)
+   argv_array_pushf(&cmd.args,
+"GIT_AUTHOR_DATE=%ld", time(NULL));
  
  		/* Add the tips to be merged */

for (j = to_merge; j; j = j->next)
@@ -3756,7 +3793,8 @@ static int pick_commits(struct repository *r,
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit ||
-   opts->committer_date_is_author_date));
+   opts->committer_date_is_author_date ||
+   opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;
  
diff --git a/sequencer.h b/sequencer.h

index e6cba468db..73d0515a3e 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -44,6 +44,7 @@ struct replay_opts {
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;
+   int ignore_date;
  
  	int mainline;
  
diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh

index ceab48a831..95d99c4b7b 100755
--- a/t/t3433-rebase-options-compatibility.sh
+++ b/t/t3433-rebase-options-compatibility.sh
@@ -81,4 +81,20 @@ test_expect_success '--committer-date-is-author-date works 
with interactive back
test_cmp authortime committertime
  '
  
+# Checking for + in author time is enough since default

+# timezone is UTC, but the timezone used while committing
+# sets to +0530.


That sounds potentially fragile but I guess the timezone is unlikely to 
change in the future


Best Wishes

Phillip


+test_expect_success '--ignore-date works with am backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   grep "+" authortime
+'
+
+test_expect_success '--ignore-date works with interactive backend' '
+   git commit --amend --date="$GIT_AUTHOR_DATE" &&
+   git rebase --ignore-date -i HEAD^ &&
+   git show HEAD --pretty="format:%ai" >authortime &&
+   grep "+" authortime
+'
  test_done



Re: [GSoC][PATCHl 4/6] sequencer: rename amend_author to author_to_rename

2019-08-08 Thread Phillip Wood

Hi Rohit

On 06/08/2019 18:36, Rohit Ashiwal wrote:

The purpose of amend_author was to free() the malloc()'d string
obtained from get_author(). But the name does not actually convey
this purpose. Rename it to something meaningful.


The name was intended to covey that it was only used when amending a 
commit, I'm fine with the rename though.


Best Wishes

Phillip



Signed-off-by: Rohit Ashiwal 
---
  sequencer.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 65adf79222..d24a6fd585 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1417,7 +1417,7 @@ static int try_to_commit(struct repository *r,
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
struct strbuf commit_msg = STRBUF_INIT;
-   char *amend_author = NULL;
+   char *author_to_free = NULL;
const char *hook_commit = NULL;
enum commit_msg_cleanup_mode cleanup;
int res = 0;
@@ -1441,7 +1441,7 @@ static int try_to_commit(struct repository *r,
strbuf_addstr(msg, orig_message);
hook_commit = "HEAD";
}
-   author = amend_author = get_author(message);
+   author = author_to_free = get_author(message);
unuse_commit_buffer(current_head, message);
if (!author) {
res = error(_("unable to parse commit author"));
@@ -1526,7 +1526,7 @@ static int try_to_commit(struct repository *r,
free_commit_extra_headers(extra);
strbuf_release(&err);
strbuf_release(&commit_msg);
-   free(amend_author);
+   free(author_to_free);
  
  	return res;

  }



Re: [GSoC][PATCHl 3/6] rebase -i: support --committer-date-is-author-date

2019-08-08 Thread Phillip Wood
@ -1686,10 +1694,12 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
  
+	if (options.committer_date_is_author_date)

+   options.flags |= REBASE_FORCE;
+
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
-   if (!strcmp(option, "--committer-date-is-author-date") ||
-   !strcmp(option, "--ignore-date") ||
+   if (!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
diff --git a/sequencer.c b/sequencer.c
index a2d7b0925e..65adf79222 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, 
"rebase-merge/refs-to-delete")
   * command-line.
   */
  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
  static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
  static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
  static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -876,6 +877,17 @@ static char *get_author(const char *message)
return NULL;
  }
  
+/* Returns a "date" string that needs to be free()'d by the caller */

+static char *read_author_date_or_null(void)
+{
+   char *date;
+
+   if (read_author_script(rebase_path_author_script(),
+  NULL, NULL, &date, 0))
+   return NULL;
+   return date;
+}
+
  /* Read author-script and return an ident line (author  timestamp) */
  static const char *read_author_ident(struct strbuf *buf)
  {
@@ -904,6 +916,18 @@ static const char *read_author_ident(struct strbuf *buf)
return buf->buf;
  }
  
+static int setenv_committer_date_to_author_date(void)

+{
+   int res = 1;


In the git codebase it is conventional to return -1 for an error


+   char *date = read_author_date_or_null();
+
+   if (date)
+   res = setenv("GIT_COMMITTER_DATE", date, 1);
+
+   free(date);
+   return res;
+}
+
  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -961,6 +985,9 @@ static int run_git_commit(struct repository *r,
  {
struct child_process cmd = CHILD_PROCESS_INIT;
  
+	if (opts->committer_date_is_author_date &&

+   setenv_committer_date_to_author_date())
+   return 1;


-1 for errors please, as seen in the surrounding code.


if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
const char *author = NULL;
@@ -1397,7 +1424,9 @@ static int try_to_commit(struct repository *r,
  
  	if (parse_head(r, ¤t_head))

return -1;
-
+   if (!(flags & AMEND_MSG) && opts->committer_date_is_author_date &&
+   setenv_committer_date_to_author_date())
+   return -1;


I think it would be better to handle committer_date_is_author_date in a 
single place in this function, not have two implementations one of which 
is untested as shown in Stolee's latest test email. This function 
receives the author as a string so it should work with the author string 
once we have checked for amend.



if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
@@ -1418,6 +1447,17 @@ static int try_to_commit(struct repository *r,
res = error(_("unable to parse commit author"));
goto out;
}
+   if (opts->committer_date_is_author_date) {
+   char *date;
+   int len = strlen(author);
+   char *idx = memchr(author, '>', len);


what happens if there is a corrupted author without an email?  - We end 
up with undefined behavior.



+
+   ++idx;
+   date = malloc(author + len - idx);
+   memcpy(date, idx, author + len - idx);
+       setenv("GIT_COMMITTER_DATE", date, 1);
+   free(date);


git has a high level api for manipulation author/committer information 
in ident.c, it would be best to use that. In any case code like this 
should be using strbuf's rather than malloc



+ 

Re: amend warnings with no changes staged

2019-08-06 Thread Phillip Wood

On 06/08/2019 04:53, Junio C Hamano wrote:

Junio C Hamano  writes:


Jonathan Nieder  writes:


Some non-judgemental descriptive output like

$ git commit --amend --no-edit
No changes.
$

would address this case, without bothering people who are doing it
intentionally.  So I think there's room for a simple improvement here.


I do that to refresh the committer timestamp.


I do, too.  The proposal is, paraphrasing,

$ git commit --amend --no-edit
Ah, I see that you want me to refresh the committer timestamp.
Done, as requested.
$


Ah, OK then.  I somehow misread "No changes." as an error message.


Well, on second thought, I think "fatal: no changes" that exits with
non-zero, with "--force" as an escape hatch for those who want to
refresh the committer timestamp, would probably be more in line with
the expectation Lukas had when this thread was started, and I further
suspect that it might be a bit more end-user friendly.


I agree that this would be the must user friendly way of doing it. I 
think refreshing the timestamp is probably a niche use of '--amend' (out 
of interest what the the motivation for doing that?) although it does 
seem to popular with the other contributors to this thread. We could 
always have a transition period with an opt-in config variable. I find 
the current behavior quite annoying when I've forgotten to stage 
anything as there is no indication the the commit's content is 
unchanged. I've been using a wrapper script that errors out if there are 
no new changes staged with --amend --no-edit and found it very helpful 
(as is a proper --reword option rather than having to give --amend --only)


Best Wishes

Phillip



It is a backward incompatible behaviour, but I suspect that if I
were inventing "commit --amend" today, unlike 8588452c ("git-commit
--amend: allow empty commit.", 2006-03-04), I probably would design
it that way.  After all, failing and stopping is always a safer
option than going ahead with or without a report.

I am not sure which one between "go ahead anyway but report" and
"fail by default but allow forcing" I would prefer more.  At least
not yet.  But I won't rule the latter out at this point.

Thanks.



Re: Support for --stdin-paths in commit, add, etc

2019-08-01 Thread Phillip Wood

On 01/08/2019 14:25, Alexandr Miloslavskiy wrote:

On 31.07.2019 19:19, Jeff King wrote:

I don't have any real objection to adding stdin support for more
commands. Bu tin the specific case you're discussing, it seems like
using "git update-index" might already solve your problem. It's the
intended plumbing for scripted index updates, and it already supports
receiving paths from stdin.


I have now studied which git commands already use commandline splitting
in our application. For some of them, I didn't find comparable plumbing;
for others, I feel that a lot of new edge cases will arise, and it will
need a lot of testing to make sure things work as expected.

Therefore, for us it would be best if high-level commands also accepted
--stdin-paths. If I develop good enough patches for that, will you
accept them?

We're interested in these high-level commands:
1) git add
2) git rm
3) git checkout
4) git reset
5) git stash
6) git commit

Here's the list of detailed commands and plumbings I found:
01) git add
     'git update-index' doesn't seem to be able to skip ignored files.


No but it only takes paths not pathspecs, can you filter out the ignored 
paths first? From a UI point of view it would be better not to allow 
users to select ignored files if you don't want to be able to add them. 
If you want to use a pathspec then you can do 'git ls-files 
--exclude-standard -o -z  | git update-index --add -z --stdin'
git check-ignore --stdin should help if you have a list of paths and you 
want to remove the ignored ones (it's not great as it tells you which 
ones are ignored rather than filtering the list for you)



02) git add --force
     Probably 'git update-index --add --stdin'.
03) git checkout
     Probably 'git checkout-index --stdin'
04) git checkout HEAD
     Didn't find a plumbing to only affect named paths.


You can use a temporary index and do
GIT_INDEX_FILE=$tmp_index git read-tree HEAD && 
GIT_INDEX_FILE=$tmp_index git checkout-index --stdin &&

rm $tmp_index


05) git checkout --ours
     Probably 'git checkout-index --stage=2 --force --stdin'
06) git checkout --theirs
     Probably 'git checkout-index --stage=3 --force --stdin'
07) git rm [--force] [--cached]
     Probably 'git update-index --force-remove'
     Didn't find how to delete files from working tree.


You have to delete them yourself.


08) git reset -q HEAD
     Didn't find a plumbing to only affect named paths.


It's a bit of a pain but you can use 'git update-index -q --unmerged 
--refresh && git diff-index --cached -z HEAD' to get a list of paths in 
the index that differ from HEAD. The list contains the old oid for each 
path (see the man page for the format) and you can feed those into 'git 
update-index --index-info' to update the index.



09) git add --update
     Probably 'git update-index --again --add --stdin'
     Not sure that --again is good replacement.


or something like 'git update-index -q --refresh && git diff-files 
--name-only -z | git update-index -z --stdin'



10) git stash push [--keep-index] [--include-untracked] [--message]
     Didn't find plumbing for stashes.


stashes are just commits really so there are no plumbing commands 
specifically related to them.



11) git commit [--allow-empty] [--amend] [--signoff] [--no-verify]
   --file=CommitMessage.txt -o
     Didn't find a plumbing to only affect named staged paths.


You can use a temporary index, add the files you want to commit with 
update-index --stdin and then run 'git commit'


When I've been scripting I've sometimes wished that diff-index and 
diff-files had a --stdin option.


Best Wishes

Phillip


Re: [BUG]: Destructive behaviour of git revert

2019-07-30 Thread Phillip Wood

Hi Andreas

On 30/07/2019 18:24, Andreas Wiesinger wrote:

Hello,

git revert for merges will mark merged files as deleted and commit
them as if they would have been deleted, but that is for sure never
what anybody would expect and has deleted many files unintentionally
and unrecognized in our repo shortly.

I have reproduced this issue in a very small example repo here:
https://gitlab.com/electrocnic/git-revert-destructive-behaviour/tree/master

Expected behaviour would be:

A reverted merge should never mark any files or directories as
"deleted", and merging the branch where the other merge has been
reverted should not lead to the deletion of those files.


Thanks for creating an example. I've had a quick look at it and it 
appears that you have a merge that adds a new file from the branch being 
merged, then when you revert the merge that file is deleted. Could you 
explain what you want to happen when you revert that merge? The idea of 
revert is to undo the changes introduced by the commit that is being 
reverted, I'm struggling to understand why you think revert should not 
do this for files that are added.


Best Wishes

Phillip


I classify this behaviour as really really destructive and clearly a
bug, even if this behaviour is by intention. It should not be by
intention then..

Best regards,
Andreas



Re: [RFC PATCH 0/9] rebase -i: extend rebase.missingCommitsCheck to `--edit-todo' and co.

2019-07-29 Thread Phillip Wood

Hi Alban

On 25/07/2019 21:26, Alban Gruin wrote:

Hi Phillip,

Le 24/07/2019 à 15:29, Phillip Wood a écrit :

Hi Alban

Thanks for working on this, it's great to see you back on the list and I
think it would be a useful addition to rebase. Unfortunately I'm not
sure about this implementation though (although the early bug fix
patches are useful in their own right)

On 17/07/2019 15:39, Alban Gruin wrote:

To prevent mistakes when editing a branch, rebase features a knob,
rebase.missingCommitsCheck, to warn the user if a commit was dropped.
Unfortunately, this check is only effective for the initial edit, which
means that if you edit the todo list at a later point of the rebase and
dropped a commit, no warnings or errors would be issued.

This adds the ability to check if commits were dropped when resuming a
rebase (with `rebase --continue'), when editing the todo list (with
`rebase --edit-todo'), or when reloading the todo list after an `exec'
command.


I'm not sure if we really need to check the todo list when continuing or
after an exec command.


In which case I don’t really understand why there is an `error' mode if
one can completely bypass it with `--continue'.


That's an interesting point about `--continue`. Perhaps if `--edit-todo` 
detects deleted lines in error mode it should write a file to stop 
`--continue` continuing rather than having to validate the entire list 
each time we continue a rebase. Alternatively we could annotate the todo 
list with a message the dropped commits commented out and reopen the 
editor for the user to fix the problem, but that would cause scripted 
editors to enter a infinite loop as they're unlikely to fix the problem 
the second time round. A third possibility is to keep your code 
validating the list each time we run continue, but update the backup 
file with each edit so it detects added commits that are deleted in a 
later edit. This would also provide some protection for users who edit 
git-rebase-todo directly, though if they are using a script that deletes 
lines in git-rebase-todo directly it will suddenly stop working with 
this change if they have rebase.missingCommitsCheck set to error.


Having said all that we could decide that the existing error message is 
enough and allow the user to skip re-editing the list if they really did 
mean to remove those lines. It would be annoying to have to re-edit the 
list when one had intended to delete those lines.



The official way to edit the todo list is to run
'git rebase --edit-todo' and I'm not sure if we support scripts writing
to .git/rebase-merge/git-rebase-todo directly. If we only support the
check after --edit-todo then I think the implementation can be
simplified as we can just write a copy of the file before it is edited
and don't need to check .git/rebase-merge/done. Additionally that would
catch commits that are added by the user and then deleted in a later
edit. They wont be in the original list so I don't think this series
will detect their deletion.



True -- but with this solution, if a bad command is introduced, there
will be false negatives.  Given the pitfall of my solution, this should
be an acceptable trade-off.


We could detect a bad commit by checking the oid and not complaining if 
it is not valid. That's slightly complicated by labels, but we could 
fairly easily keep of list of the labels defined so far as we scan the 
list. That would also open the possibility of detecting errors where the 
user references an undefined label in `merge` or `reset` commands but 
that's a separate problem.


Best Wishes

Phillip


At the extreme I have a script around rebase that runs 'rebase -i HEAD'
and then fills in the todo list with a fake editor that adds 'reset ...'
as the first line to set the starting point of the rebase. I think
dscho's garden-shears script does something similar. Under the proposed
scheme if I subsequently edit the todo list it will not catch any
deleted commits as the original list is empty.

Best Wishes

Phillip



Cheers,
Alban



Re: [GSoC][PATCH v2 2/2] rebase -i: support --committer-date-is-author-date

2019-07-24 Thread Phillip Wood

Hi Rohit

On 23/07/2019 20:57, Rohit Ashiwal wrote:

Hi Phillip

On Sat, 20 Jul 2019 15:56:50 +0100 Phillip Wood  
wrote:


[...]


@@ -467,6 +470,9 @@ int cmd_rebase__interactive(int argc, const char **argv, 
const char *prefix)
OPT_BOOL(0, "autosquash", &opts.autosquash,
 N_("move commits that begin with squash!/fixup!")),
OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")),
+   OPT_BOOL(0, "committer-date-is-author-date",
+&opts.committer_date_is_author_date,
+N_("make committer date match author date")),


I guess it's good to do this for completeness but does
rebase--preserver-merges.sh support --committer-date-is-author-date? It
is the only caller of rebase--interactive I think so would be the only
user of this code.


Oh! Yes, I did it for the completeness. Let's add the flag while we
still have that _rebase--interactive_ command hanging out with us.


[...]


+   if (read_author_script(rebase_path_author_script(),
+  NULL, NULL, &date, 0))
+   die(_("failed to read author date"));


Can we have this return an error please - we try quite hard in the
sequencer not to die in library code.


Yes, we can through an error and continue, but then the user will
see the unchanged author date which is against his / her will but
it will not crash the program at least.


I dont think it should continue, the error should be propagated up to 
cmd_rebase() (In your patch I think one of the context lines in 
run_git_commit() shows this happening)





[...]


+   if (opts->committer_date_is_author_date) {
+   char *date = read_author_date_or_die();
+   argv_array_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s", date);
+   free(date);
+   }


It's a shame to be doing this twice is slightly different ways in the
same function (and again in try_to_commit() but I don't think that can
be avoided as not all callers of run_git_commit() go through
try_to_commit()). As I think the child inherits the current environment
modified by cmd.env_array we could just call setenv() at the top of the
function. It would be worth looking to see if it would be simpler to do
the setenv() call in the loop that picks the commits, then we would
avoid having to do it in do_merge() and try_to_commit() separately.


Ok, I'll have to change the code according to what Junio suggested.
Let's see how this area will look after that.


[...]


+   if (file_exists(rebase_path_cdate_is_adate())) {
+   opts->allow_ff = 0;


This is safe as we don't save the state of allow_ff for rebases so it
wont be overridden later. It would be an idea to add to the checks in
the assert() at the beginning of pick_commits() no we have another
option that implies --force-rebase.


Are you suggesting to modify this assert() call (in pick_commits())?

 if (opts->allow_ff)
 assert(!(opts->signoff || opts->no_commit ||
 opts->record_origin || opts->edit));


Yes I think it should check for opts->committer_date_is_author_date here

Best Wishes

Phillip


Thanks
Rohit



Re: [RFC PATCH 0/9] rebase -i: extend rebase.missingCommitsCheck to `--edit-todo' and co.

2019-07-24 Thread Phillip Wood

Hi Alban

Thanks for working on this, it's great to see you back on the list and I 
think it would be a useful addition to rebase. Unfortunately I'm not 
sure about this implementation though (although the early bug fix 
patches are useful in their own right)


On 17/07/2019 15:39, Alban Gruin wrote:

To prevent mistakes when editing a branch, rebase features a knob,
rebase.missingCommitsCheck, to warn the user if a commit was dropped.
Unfortunately, this check is only effective for the initial edit, which
means that if you edit the todo list at a later point of the rebase and
dropped a commit, no warnings or errors would be issued.

This adds the ability to check if commits were dropped when resuming a
rebase (with `rebase --continue'), when editing the todo list (with
`rebase --edit-todo'), or when reloading the todo list after an `exec'
command.


I'm not sure if we really need to check the todo list when continuing or 
after an exec command. The official way to edit the todo list is to run 
'git rebase --edit-todo' and I'm not sure if we support scripts writing 
to .git/rebase-merge/git-rebase-todo directly. If we only support the 
check after --edit-todo then I think the implementation can be 
simplified as we can just write a copy of the file before it is edited 
and don't need to check .git/rebase-merge/done. Additionally that would 
catch commits that are added by the user and then deleted in a later 
edit. They wont be in the original list so I don't think this series 
will detect their deletion.


At the extreme I have a script around rebase that runs 'rebase -i HEAD' 
and then fills in the todo list with a fake editor that adds 'reset ...' 
as the first line to set the starting point of the rebase. I think 
dscho's garden-shears script does something similar. Under the proposed 
scheme if I subsequently edit the todo list it will not catch any 
deleted commits as the original list is empty.


Best Wishes

Phillip


The idea to extend this feature was suggested to me more than a year ago
by Phillip Wood, if I'm not mistaken.  I postponed this until four month
ago, when ag/sequencer-reduce-rewriting-todo finally hit master, but I
had to stop because of other obligations.  I could go back to work one
month ago, when I did the bulk of this series, but I lacked time to
polish it, so it waited a bit more.  Now, I think it is in a good shape
to be sent, although it is still RFC-quality to me.  The advertised
functionality should work well, but perhaps there is some flaws I
missed.

The first two patches are new tests, demonstrating that after the
initial edit, the check is not done.  The next four are what could be
qualified as omissions from ag/sequencer-reduce-rewriting-todo, but they
are quite important (IMHO) for the rest of the series.  The last three
actually extend rebase.missingCommitsCheck.

This is based on master (9d418600f4, "The fifth batch").

The tip of this series is tagged as "edit-todo-drop-rfc" in
https://github.com/agrn/git.

Alban Gruin (9):
   t3404: demonstrate that --edit-todo does not check for dropped commits
   t3429: demonstrate that rebase exec does not check for dropped commits
   sequencer: update `total_nr' when adding an item to a todo list
   sequencer: update `done_nr' when skipping commands in a todo list
   sequencer: move the code writing total_nr on the disk to a new
 function
   sequencer: add a parameter to sequencer_continue() to accept a todo
 list
   rebase-interactive: todo_list_check() also uses the done list
   rebase-interactive: warn if commit is dropped with --edit-todo
   sequencer: have read_populate_todo() check for dropped commits

  builtin/rebase.c  |  2 +-
  builtin/revert.c  |  2 +-
  rebase-interactive.c  | 67 +++-
  rebase-interactive.h  |  6 ++-
  sequencer.c   | 53 ++
  sequencer.h   |  3 +-
  t/t3404-rebase-interactive.sh | 82 +++
  t/t3429-rebase-edit-todo.sh   | 44 ++-
  8 files changed, 224 insertions(+), 35 deletions(-)



Re: [GSoC][PATCH v2 1/1] rebase -i: add --ignore-whitespace flag

2019-07-22 Thread Phillip Wood
 parse_options(argc, argv, NULL, options,
>   builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
>  
> + opts.strategy_opts = xstrdup_or_null(opts.strategy_opts);
> +
>   if (!is_null_oid(&squash_onto))
>   opts.squash_onto = &squash_onto;
>  
> @@ -954,6 +970,8 @@ static int run_am(struct rebase_options *opts)
>   am.git_cmd = 1;
>   argv_array_push(&am.args, "am");
>  
> + if (opts->ignore_whitespace)
> + argv_array_push(&am.args, "--ignore-whitespace");
>   if (opts->action && !strcmp("continue", opts->action)) {
>   argv_array_push(&am.args, "--resolved");
>   argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
> @@ -1401,9 +1419,6 @@ int cmd_rebase(int argc, const char **argv, const char 
> *prefix)
>   PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
>   OPT_BOOL(0, "signoff", &options.signoff,
>N_("add a Signed-off-by: line to each commit")),
> - OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
> -   NULL, N_("passed to 'git am'"),
> -   PARSE_OPT_NOARG),
>   OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
> &options.git_am_opts, NULL,
> N_("passed to 'git am'"), PARSE_OPT_NOARG),
> @@ -1411,6 +1426,8 @@ int cmd_rebase(int argc, const char **argv, const char 
> *prefix)
> N_("passed to 'git am'"), PARSE_OPT_NOARG),
>   OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
> N_("passed to 'git apply'"), 0),
> + OPT_BOOL(0, "ignore-whitespace", &options.ignore_whitespace,
> +  N_("ignore changes in whitespace")),
>   OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
> N_("action"), N_("passed to 'git apply'"), 0),
>   OPT_BIT('f', "force-rebase", &options.flags,
> @@ -1821,6 +1838,9 @@ int cmd_rebase(int argc, const char **argv, const char 
> *prefix)
>   }
>  
>   if (options.rebase_merges) {
> + if (options.ignore_whitespace)
> + die(_("cannot combine '--rebase-merges' with "
> +   "'--ignore-whitespace'"));

I was going to ask why we cannot just pass -Xignore-space-change when
making the merge but the lines below seem to show we don't support merge
options yet.

>   if (strategy_options.nr)
>   die(_("cannot combine '--rebase-merges' with "
> "'--strategy-option'"));
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..303047a133 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -43,6 +43,7 @@ struct replay_opts {
>   int verbose;
>   int quiet;
>   int reschedule_failed_exec;
> + int ignore_whitespace;

Is this new field used anywhere - we add -Xignore-space-change to
replay_opts.xopts so why do we need this as well?

Best Wishes

Phillip

>  
>   int mainline;
>  
> diff --git a/t/t3422-rebase-incompatible-options.sh 
> b/t/t3422-rebase-incompatible-options.sh
> index a5868ea152..4342f79eea 100755
> --- a/t/t3422-rebase-incompatible-options.sh
> +++ b/t/t3422-rebase-incompatible-options.sh
> @@ -61,7 +61,6 @@ test_rebase_am_only () {
>  }
>  
>  test_rebase_am_only --whitespace=fix
> -test_rebase_am_only --ignore-whitespace
>  test_rebase_am_only --committer-date-is-author-date
>  test_rebase_am_only -C4
>  
> diff --git a/t/t3431-rebase-options-compatibility.sh 
> b/t/t3431-rebase-options-compatibility.sh
> new file mode 100755
> index 00..f38ae6f5fc
> --- /dev/null
> +++ b/t/t3431-rebase-options-compatibility.sh
> @@ -0,0 +1,66 @@
> +#!/bin/sh
> +#
> +# Copyright (c) 2019 Rohit Ashiwal
> +#
> +
> +test_description='tests to ensure compatibility between am and interactive 
> backends'
> +
> +. ./test-lib.sh
> +
> +# This is a special case in which both am and interactive backends
> +# provide the same outputs. It was done intentionally because
> +# --ignore-whitespace both the backends fall short of optimal
> +# behaviour.
> +test_expect_s

Re: [GSoC][PATCH v2 2/2] rebase -i: support --committer-date-is-author-date

2019-07-20 Thread Phillip Wood
EDIT_MSG))
@@ -1467,6 +1492,12 @@ static int try_to_commit(struct repository *r,
  
  	reset_ident_date();
  
+	if (opts->committer_date_is_author_date) {

+   char *date = read_author_date_or_die();
+   setenv("GIT_COMMITTER_DATE", date, 1);
+   free(date);
+   }
+
    if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
 oid, author, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object"));
@@ -2538,6 +2569,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}
  
+		if (file_exists(rebase_path_cdate_is_adate())) {

+   opts->allow_ff = 0;


This is safe as we don't save the state of allow_ff for rebases so it 
wont be overridden later. It would be an idea to add to the checks in 
the assert() at the beginning of pick_commits() no we have another 
option that implies --force-rebase.


Best Wishes

Phillip


+   opts->committer_date_is_author_date = 1;
+   }
+
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
  
@@ -2620,6 +2656,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,

write_file(rebase_path_gpg_sign_opt(), "-S%s\n", 
opts->gpg_sign);
if (opts->signoff)
write_file(rebase_path_signoff(), "--signoff\n");
+   if (opts->committer_date_is_author_date)
+   write_file(rebase_path_cdate_is_adate(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
  
@@ -3437,6 +3475,12 @@ static int do_merge(struct repository *r,

argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
+   if (opts->committer_date_is_author_date) {
+   char *date = read_author_date_or_die();
+   argv_array_pushf(&cmd.env_array,
+"GIT_COMMITTER_DATE=%s", date);
+   free(date);
+   }
  
  		/* Add the tips to be merged */

for (j = to_merge; j; j = j->next)
diff --git a/sequencer.h b/sequencer.h
index 303047a133..0cfe184fc2 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -44,6 +44,7 @@ struct replay_opts {
int quiet;
int reschedule_failed_exec;
int ignore_whitespace;
+   int committer_date_is_author_date;
  
  	int mainline;
  
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh

index 4342f79eea..7402f7e3da 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -61,7 +61,6 @@ test_rebase_am_only () {
  }
  
  test_rebase_am_only --whitespace=fix

-test_rebase_am_only --committer-date-is-author-date
  test_rebase_am_only -C4
  
  test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '

diff --git a/t/t3431-rebase-options-compatibility.sh 
b/t/t3431-rebase-options-compatibility.sh
index f38ae6f5fc..c3f7f6d5d0 100755
--- a/t/t3431-rebase-options-compatibility.sh
+++ b/t/t3431-rebase-options-compatibility.sh
@@ -7,6 +7,9 @@ test_description='tests to ensure compatibility between am and 
interactive backe
  
  . ./test-lib.sh
  
+GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"

+export GIT_AUTHOR_DATE
+
  # This is a special case in which both am and interactive backends
  # provide the same outputs. It was done intentionally because
  # --ignore-whitespace both the backends fall short of optimal
@@ -63,4 +66,22 @@ test_expect_success '--ignore-whitespace works with 
interactive backend' '
test_cmp expect file
  '
  
+test_expect_success '--committer-date-is-author-date works with am backend' '

+   git rebase -f HEAD^ &&
+   git rebase --committer-date-is-author-date HEAD^ &&
+   git cat-file commit HEAD | sed -e "/^\$/q" >head &&
+   sed -ne "/^author /s/.*> //p" head >authortime &&
+   sed -ne "/^committer /s/.*> //p" head >committertime &&
+   test_cmp authortime committertime
+'
+
+test_expect_success '--committer-date-is-author-date works with interactive 
backend' '
+   git rebase -f HEAD^ &&
+   git rebase -i --committer-date-is-author-date HEAD^ &&
+   git cat-file commit HEAD | sed -e "/^\$/q" >head &&
+   sed -ne "/^author /s/.*> //p" head >authortime &&
+   sed -ne "/^committer /s/.*> //p" head >committertime &&
+   test_cmp authortime committertime
+'
+
  test_done



Re: What's cooking in git.git (Jul 2019, #01; Wed, 3)

2019-07-11 Thread Phillip Wood
On 08/07/2019 23:02, Junio C Hamano wrote:
> Phillip Wood  writes:
> 
>>> * pw/rebase-progress-test-cleanup (2019-07-01) 1 commit
>>>  - t3420: remove progress lines before comparing output
>>>  (this branch uses sg/rebase-progress.)
>>>
>>>  Test cleanup.
>>>
>>>  Will merge to 'next'.
>>
>> I've just posted an update to this which avoids the repeated printf calls
> 
> Thanks.  Picked up the one from "Date: Thu Jul 4 02:47:02 2019 -0700".

Yes, that's the one - sorry I forgot to add a link to my original email

Best Wishes

Phillip



Re: What's cooking in git.git (Jul 2019, #01; Wed, 3)

2019-07-04 Thread Phillip Wood
On 03/07/2019 23:28, Junio C Hamano wrote:
> Here are the topics that have been cooking.  Commits prefixed with
> '-' are only in 'pu' (proposed updates) while commits prefixed with
> '+' are in 'next'.  The ones marked with '.' do not appear in any of
> the integration branches, but I am still holding onto them.
> 
> The third batch of topics post 2.22 are now in 'master', and the tip
> of 'next' has been rewound.
> 
> You can find the changes described here in the integration branches
> of the repositories listed at
> 
> http://git-blame.blogspot.com/p/git-public-repositories.html
> 
> --
> [New Topics]
> 
> * pw/rebase-progress-test-cleanup (2019-07-01) 1 commit
>  - t3420: remove progress lines before comparing output
>  (this branch uses sg/rebase-progress.)
> 
>  Test cleanup.
> 
>  Will merge to 'next'.

I've just posted an update to this which avoids the repeated printf calls

Best Wishes

Phillip


Re: [PATCH 1/1] t3420: remove progress lines before comparing output

2019-07-04 Thread Phillip Wood
On 02/07/2019 18:23, Junio C Hamano wrote:
> Phillip Wood  writes:
> 
>>> As long as sed implementation used here does not do anything funny
>>> to CR, I think the approach to strip everything before the last CR
>>> on the line is sensible.  As I am not familiar with how Windows port
>>> of sed wants to treat a CR byte in the pattern, I am not sure about
>>> the precondition of the above statement, though.
>>
>> I wondered about that too, but it passes the CI tests under windows.
> 
> Hopefully Git for Windows, MinGW, and CygWin would all behave
> similarly.
> 
>>> I also have to wonder if we can/want to do this without an extra
>>> printf process every time we sanitize the output, though I do not
>>> think I care too deeply about it.
>>
>> I could add 're="$(printf ...)"' to the setup at the top of the file
>> if you want
> 
> As I do not care too deeply about it, we recently saw a lot about
> reducing number of processes in the tests, so apparently some folks
> care and I presume they want to see something like that to happen.
> I do not think $re is a good name for such a variable, though ;-)

Yes, $re was just a place holder - naming is hard ...

Best Wishes

Phillip



[PATCH v2 1/1] t3420: remove progress lines before comparing output

2019-07-04 Thread Phillip Wood via GitGitGadget
From: Phillip Wood 

Some of the tests check the output of rebase is what we expect. These
were added after a regression that added unwanted stash output when
using --autostash. They are useful as they prevent unintended changes to
the output of the various rebase commands. However they also include all
the progress output which is less useful as it only tests what would be
written to a dumb terminal which is not the normal use case. The recent
changes to fix clearing the line when printing progress necessarily
meant making an ugly change to these tests. Address this my removing the
progress output before comparing it to the expected output. We do this
by removing everything before the final "\r" on each line as we don't
care about the progress indicator, but we do care about what is printed
immediately after it.

Signed-off-by: Phillip Wood 
---
 t/t3420-rebase-autostash.sh | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 9186e90127..b8f4d03467 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -30,7 +30,8 @@ test_expect_success setup '
echo conflicting-change >file2 &&
git add . &&
test_tick &&
-   git commit -m "related commit"
+   git commit -m "related commit" &&
+   remove_progress_re="$(printf "s/.*\\r//")"
 '
 
 create_expected_success_am () {
@@ -48,8 +49,8 @@ create_expected_success_interactive () {
q_to_cr >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
HEAD is now at $(git rev-parse --short feature-branch) third commit
-   Rebasing (1/2)QRebasing (2/2)QApplied autostash.
-   Q   
 QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
+   Applied autostash.
+   Successfully rebased and updated refs/heads/rebased-feature-branch.
EOF
 }
 
@@ -67,13 +68,13 @@ create_expected_failure_am () {
 }
 
 create_expected_failure_interactive () {
-   q_to_cr >expected <<-EOF
+   cat >expected <<-EOF
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
HEAD is now at $(git rev-parse --short feature-branch) third commit
-   Rebasing (1/2)QRebasing (2/2)QApplying autostash resulted in conflicts.
+   Applying autostash resulted in conflicts.
Your changes are safe in the stash.
You can run "git stash pop" or "git stash drop" at any time.
-   Q   
 QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
+   Successfully rebased and updated refs/heads/rebased-feature-branch.
EOF
 }
 
@@ -109,7 +110,8 @@ testrebase () {
suffix=interactive
fi &&
create_expected_success_$suffix &&
-   test_i18ncmp expected actual
+   sed "$remove_progress_re" actual2 &&
+   test_i18ncmp expected actual2
'
 
test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
@@ -209,7 +211,8 @@ testrebase () {
suffix=interactive
fi &&
create_expected_failure_$suffix &&
-   test_i18ncmp expected actual
+   sed "$remove_progress_re" actual2 &&
+   test_i18ncmp expected actual2
'
 }
 
-- 
gitgitgadget


  1   2   3   4   5   6   7   8   9   10   >