All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits
@ 2012-03-30 19:48 Neil Horman
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
                   ` (10 more replies)
  0 siblings, 11 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-30 19:48 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Hey all-
	Based on your feedback from my earlier thread on this subject, I've come
up with this series as a first pass in enhancing git-rebases ability to handle
empty commits.  I'm not sure if its exactly what everyone wants, but I think its
a good start, and it works for what I need it to do here.

I started with adding a -keep-empty option to git-cherry-pick, which allows
non-fast forward commits that are empty to be cherry-pick without failing, and
requiring a separate git commit --allow-empty.

Building on that, I've added --keep-empty option to git-rebase.  For an
automatic rebase adding --keep-empty simply passes the --keep-empty flag along
to git cherry-pick so that the empty commits are preserved instead of discarded

for interactive rebases, I changed the default selection editor text somewhat.
By default, empty commits are allowed in this list.  With patch 4 here, empty
commits are commented out automatically, unless --keep-empty is selected (in
which case all commits are pick-ed).  The user sees additional text indicating
that empty commits are commented and if they wish to be kept, then they must be
uncommented.  The pick_one function then intellegently passes the --keep-empty
option allong to cherry-pick as needed.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH 1/4] git-cherry-pick: add keep-empty option
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-03-30 19:48 ` Neil Horman
  2012-03-30 20:34   ` Junio C Hamano
                     ` (2 more replies)
  2012-03-30 19:48 ` [PATCH 2/4] git-rebase: add keep_empty flag Neil Horman
                   ` (9 subsequent siblings)
  10 siblings, 3 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-30 19:48 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operaion.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-cherry-pick.txt |    7 +++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..3e975dc 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,13 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--keep-empty:
+	If a commit is not a fast forward, or if fast forwarding is not allowed,
+	cherry-picking an empty commit will fail, indicating that an explicit
+	invokation of git commit --allow-empty is required.  This option
+	overrides that behavior, allowing empty commits to be preserved
+	automatically in a cherry-pick
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..47d5522 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "keep-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 2/4] git-rebase: add keep_empty flag
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
@ 2012-03-30 19:48 ` Neil Horman
  2012-03-30 20:43   ` Junio C Hamano
  2012-03-30 19:48 ` [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits Neil Horman
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-03-30 19:48 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-rebase.txt |    6 ++++++
 git-rebase.sh                |    5 +++++
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..9717d3e 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Informs git-rebase that comits which are empty should not be
+	automatically removed.  This is at times useful when empty commits
+	are used to hold developer information and notes, but contain no real
+	code changes
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
  2012-03-30 19:48 ` [PATCH 2/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-03-30 19:48 ` Neil Horman
  2012-03-30 20:46   ` Junio C Hamano
  2012-03-30 20:47   ` Junio C Hamano
  2012-03-30 19:48 ` [PATCH 4/4] git-commit-interactive: Allow " Neil Horman
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-30 19:48 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Using the keep_empy environment variable, this change allows git-commit-am to
apply empty commits to the new branch we are rebasing to

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 git-rebase--am.sh |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..c1d1b60 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,21 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if [ -n "$keep_empty" ]
+then
+	# we have to do this the hard way.  git format-patch completly squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --keep-empty "$revisions" && move_to_original_branch
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
+	move_to_original_branch
+fi
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (2 preceding siblings ...)
  2012-03-30 19:48 ` [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits Neil Horman
@ 2012-03-30 19:48 ` Neil Horman
  2012-03-30 20:59   ` Junio C Hamano
  2012-03-30 20:32 ` [PATCH 0/4] Enhance git-rebases flexibiilty in handling " Junio C Hamano
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-03-30 19:48 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

This updates git-commit-interactive to recognize and make use of the keep_empty
flag.  When not set, git-rebase -i will now comment out commits that are empty,
and informs the user that commits which they wish to explicitly keep that are
empty should be uncommented, or --keep-empty should be specified.  if keep_empty
is specified, all commits, regardless of their empty status are included.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---
 1 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..97eeb21 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -191,12 +191,24 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+	is_empty=$(git show --pretty=format:%b "$@" | wc -l)
+
+	if [ $is_empty -eq 0 ]
+	then
+		empty_args=--keep-empty
+	fi
+
+	if [ -n "$keep_empty" ]
+	then
+		empty_args=--keep_empty
+	fi
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+	local comment_out
+
+	if [ -z "$keep_empty" ]
+	then
+		comment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)
+		if [ $comment_out -eq 0 ]
+		then
+			comment_out="#pick"
+		else
+			comment_out="pick"
+		fi
+	else
+		comment_out="pick"
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +828,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -849,6 +876,11 @@ cat >> "$todo" << EOF
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
 #
+# Note that commits which are empty at the time of rebasing are 
+# commented out.  If you wish to keep empty commits, either 
+# specify the --keep-empty option to the rebase command, or 
+# uncomment the commits you wish to keep
+#
 EOF
 
 has_action "$todo" ||
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (3 preceding siblings ...)
  2012-03-30 19:48 ` [PATCH 4/4] git-commit-interactive: Allow " Neil Horman
@ 2012-03-30 20:32 ` Junio C Hamano
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:32 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> for interactive rebases, I changed the default selection editor text somewhat.
> By default, empty commits are allowed in this list.  With patch 4 here, empty
> commits are commented out automatically, unless --keep-empty is selected (in
> which case all commits are pick-ed).  The user sees additional text indicating
> that empty commits are commented and if they wish to be kept, then they must be
> uncommented.  The pick_one function then intellegently passes the --keep-empty
> option allong to cherry-pick as needed.

Sounds like a sensible UI design.  I am a bit curious what it would do
when you try to "rebase -i" a series of commits, all of which are empty,
though.

> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>

Please do not do this; Cc: goes to your e-mail header, not here.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/4] git-cherry-pick: add keep-empty option
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
@ 2012-03-30 20:34   ` Junio C Hamano
  2012-03-30 21:15   ` Jeff King
  2012-03-31 12:57   ` Neil Horman
  2 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:34 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

It strikes me very strange why this is not called --allow-empty, but other
than that the addition look straightforward enough to me.  You would want
to add a test for this, though.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 2/4] git-rebase: add keep_empty flag
  2012-03-30 19:48 ` [PATCH 2/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-03-30 20:43   ` Junio C Hamano
  2012-03-31 12:59     ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:43 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> Add a command line switch to git-rebase to allow a user the ability to specify
> that they want to keep any commits in a series that are empty.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>

The same comments on Cc: apply to all of your patches.

>  Documentation/git-rebase.txt |    6 ++++++
>  git-rebase.sh                |    5 +++++
>  2 files changed, 11 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
> index 504945c..9717d3e 100644
> --- a/Documentation/git-rebase.txt
> +++ b/Documentation/git-rebase.txt
> @@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.
>  	will be reset to where it was when the rebase operation was
>  	started.
>  
> +--keep-empty::
> +	Informs git-rebase that comits which are empty should not be
> +	automatically removed.  This is at times useful when empty commits
> +	are used to hold developer information and notes, but contain no real
> +	code changes
> +

Unlike "cherry-pick", I think "--keep-empty" is a better name for the
option than "--allow-empty" in this context.  The difference is that from
the end-user's point of view, cherry-pick _replays_ commits that exist
elsewhere, and you are allowing the command to replay empty ones as well,
while rebase _rebuilds_ commits on the same branch, and you are telling
the command to keep empty ones.

"... which are empty should not be removed" is a bit of double-negation,
though.  Perhaps

	--keep-empty::
		Keep the commits that do not change anything from its
		parents in the result.  This is at times useful when empty
		commits are used to hold developer information and notes
		without having any real changes.

But as I rephrased the first part, the last line may have become redundant
and could safely be removed.

The patch does not seem to do anything other than accepting and silently
ignoring the option, though.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits
  2012-03-30 19:48 ` [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits Neil Horman
@ 2012-03-30 20:46   ` Junio C Hamano
  2012-03-31 13:01     ` Neil Horman
  2012-03-30 20:47   ` Junio C Hamano
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:46 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> Using the keep_empy environment variable, this change allows git-commit-am to

Is it an environment variable?  I thought not.

> apply empty commits to the new branch we are rebasing to
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>
> ---
>  git-rebase--am.sh |   20 +++++++++++++++-----
>  1 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/git-rebase--am.sh b/git-rebase--am.sh
> index c815a24..c1d1b60 100644
> --- a/git-rebase--am.sh
> +++ b/git-rebase--am.sh
> @@ -20,11 +20,21 @@ esac
>  
>  test -n "$rebase_root" && root_flag=--root
>  
> -git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> -	--src-prefix=a/ --dst-prefix=b/ \
> -	--no-renames $root_flag "$revisions" |
> -git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> -move_to_original_branch
> +if [ -n "$keep_empty" ]
> +then
> +	# we have to do this the hard way.  git format-patch completly squashes
> +	# empty commits and even if it didn't the format doesn't really lend
> +	# itself well to recording empty patches.  fortunately, cherry-pick
> +	# makes this easy
> +	git cherry-pick --keep-empty "$revisions" && move_to_original_branch
> +else
> +	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> +		--src-prefix=a/ --dst-prefix=b/ \
> +		--no-renames $root_flag "$revisions" |
> +	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> +	move_to_original_branch
> +fi

Factor out the "&& move_to_original_branch" at the end of then/else, like
this:

	if ...
        then
		...
        else
		...
        fi && move_to_original_branch

>  ret=$?
>  test 0 != $ret -a -d "$state_dir" && write_basic_state
>  exit $ret

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits
  2012-03-30 19:48 ` [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits Neil Horman
  2012-03-30 20:46   ` Junio C Hamano
@ 2012-03-30 20:47   ` Junio C Hamano
  2012-03-31 13:03     ` Neil Horman
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:47 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

Neil Horman <nhorman@tuxdriver.com> writes:

> Using the keep_empy environment variable, this change allows git-commit-am to
> apply empty commits to the new branch we are rebasing to
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>
> ---
>  git-rebase--am.sh |   20 +++++++++++++++-----
>  1 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/git-rebase--am.sh b/git-rebase--am.sh
> index c815a24..c1d1b60 100644
> --- a/git-rebase--am.sh
> +++ b/git-rebase--am.sh
> @@ -20,11 +20,21 @@ esac
>  
>  test -n "$rebase_root" && root_flag=--root
>  
> -git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> -	--src-prefix=a/ --dst-prefix=b/ \
> -	--no-renames $root_flag "$revisions" |
> -git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> -move_to_original_branch
> +if [ -n "$keep_empty" ]
> +then
> +	# we have to do this the hard way.  git format-patch completly squashes
> +	# empty commits and even if it didn't the format doesn't really lend
> +	# itself well to recording empty patches.  fortunately, cherry-pick
> +	# makes this easy
> +	git cherry-pick --keep-empty "$revisions" && move_to_original_branch

Does cherry-pick know the "--ignore-if-in-upstream" trick?  Otherwise I
suspect that this will introduce a severe regression to the command, as
the commits that are already in the new base you are rebasing to will all
be kept as empty commits, no?

> +else
> +	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> +		--src-prefix=a/ --dst-prefix=b/ \
> +		--no-renames $root_flag "$revisions" |
> +	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> +	move_to_original_branch
> +fi
> +
>  ret=$?
>  test 0 != $ret -a -d "$state_dir" && write_basic_state
>  exit $ret

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits
  2012-03-30 19:48 ` [PATCH 4/4] git-commit-interactive: Allow " Neil Horman
@ 2012-03-30 20:59   ` Junio C Hamano
  2012-03-31 13:11     ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-03-30 20:59 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> This updates git-commit-interactive to recognize and make use of the keep_empty
> flag.  When not set, git-rebase -i will now comment out commits that are empty,
> and informs the user that commits which they wish to explicitly keep that are
> empty should be uncommented, or --keep-empty should be specified.  if keep_empty
> is specified, all commits, regardless of their empty status are included.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>
> ---
>  git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---
>  1 files changed, 35 insertions(+), 3 deletions(-)
>
> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> index 5812222..97eeb21 100644
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -191,12 +191,24 @@ git_sequence_editor () {
>  
>  pick_one () {
>  	ff=--ff
> +	is_empty=$(git show --pretty=format:%b "$@" | wc -l)

That is a very expensive way to see if the commit is empty, no?

If and only if commit C is empty, "git rev-parse" on C^{tree} and
C^^{tree}" will yield the same tree object name.

> +	if [ $is_empty -eq 0 ]

Also this test (which by the way is against our coding style guideline)
shows that the variable is misnamed.

> +	then
> +		empty_args=--keep-empty
> +	fi
> +
> +	if [ -n "$keep_empty" ]
> +	then
> +		empty_args=--keep_empty
> +	fi
> +
>  	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
>  	case "$force_rebase" in '') ;; ?*) ff= ;; esac
>  	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
>  	test -d "$rewritten" &&
>  		pick_one_preserving_merges "$@" && return
> -	output git cherry-pick $ff "$@"
> +	output git cherry-pick $empty_args $ff "$@"
>  }
>  
>  pick_one_preserving_merges () {
> @@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
>  	sed -n "s/^>//p" |
>  while read -r shortsha1 rest
>  do
> +	local comment_out

bashism.

> +
> +	if [ -z "$keep_empty" ]
> +	then
> +		comment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)

Ditto.

> +		if [ $comment_out -eq 0 ]
> +		then
> +			comment_out="#pick"

Perhaps it is easier to read if you say "# pick"?

> +		else
> +			comment_out="pick"
> +		fi
> +	else
> +		comment_out="pick"
> +	fi
> +
>  	if test t != "$preserve_merges"
>  	then
> -		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
> +		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"

The variable comment_out is grossly misnamed.  Why not do it this way?

	comment_out=
	if test -z "$keep_empty" && is_empty_commit $shortsha1
        then
        	comment_out="# "
	fi

        if ...
        then
		printf "%s\n" "${leader}pick $shortsha1 $rest" >>"$todo"

> @@ -849,6 +876,11 @@ cat >> "$todo" << EOF
>  # If you remove a line here THAT COMMIT WILL BE LOST.
>  # However, if you remove everything, the rebase will be aborted.
>  #
> +# Note that commits which are empty at the time of rebasing are 
> +# commented out.  If you wish to keep empty commits, either 
> +# specify the --keep-empty option to the rebase command, or 
> +# uncomment the commits you wish to keep
> +#

Good.

I do not think " either specify...rebase command, or" is necessary here,
though.  This message is meant to be a quick reminder, not a tutorial.
Keep it short and sweet.

Also, you may probably want to add this text _only_ when you have actually
commented out something.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/4] git-cherry-pick: add keep-empty option
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
  2012-03-30 20:34   ` Junio C Hamano
@ 2012-03-30 21:15   ` Jeff King
  2012-03-31 12:57   ` Neil Horman
  2 siblings, 0 replies; 121+ messages in thread
From: Jeff King @ 2012-03-30 21:15 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Phil Hord, Junio C Hamano

On Fri, Mar 30, 2012 at 03:48:39PM -0400, Neil Horman wrote:

> +--keep-empty:
> +	If a commit is not a fast forward, or if fast forwarding is not allowed,
> +	cherry-picking an empty commit will fail, indicating that an explicit
> +	invokation of git commit --allow-empty is required.  This option
> +	overrides that behavior, allowing empty commits to be preserved
> +	automatically in a cherry-pick

This didn't parse very well for me. A commit cannot be "a fast forward"
by itself. Fast-forwarding is an operation that depends on the
relationship between commits.

I think what you are trying to say is that this option is used only if
the "--ff" logic does not kick in. Maybe it would be clearer to get to
the point early, and mention --ff later, like:

  --keep-empty:
          By default, cherry-picking an empty commit will fail,
          indicating that an explicit invocation of `git commit
          --allow-empty` is required. This option overrides that
          behavior, allowing empty commits to be preserved automatically
          in a cherry-pick. Note that when "--ff" is in effect, empty
          commits that meet the "fast-forward" requirement will be kept
          even without this option.

Like Junio, I agree this should simply be called --allow-empty.

> diff --git a/sequencer.c b/sequencer.c
> index a37846a..71929ba 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
>   */
>  static int run_git_commit(const char *defmsg, struct replay_opts *opts)
>  {
> -	/* 6 is max possible length of our args array including NULL */
> -	const char *args[6];
> +	/* 7 is max possible length of our args array including NULL */
> +	const char *args[7];
>  	int i = 0;

It might be nice to refactor this to use argv_array, which handles the
allocation automatically.

> +	if (opts->allow_empty)
> +		args[i++] = "--allow-empty";
> +

What happens if I cherry-pick a commit that is not empty, but that
becomes empty because its changes have already been applied?

-Peff

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/4] git-cherry-pick: add keep-empty option
  2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
  2012-03-30 20:34   ` Junio C Hamano
  2012-03-30 21:15   ` Jeff King
@ 2012-03-31 12:57   ` Neil Horman
  2 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-31 12:57 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano

On Fri, Mar 30, 2012 at 03:48:39PM -0400, Neil Horman wrote:
> git cherry-pick fails when picking a non-ff commit that is empty.  The advice
> given with the failure is that a git-commit --allow-empty should be issued to
> explicitly add the empty commit during the cherry pick.  This option allows a
> user to specify before hand that they want to keep the empty commit.  This
> eliminates the need to issue both a cherry pick and a commit operaion.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>
As you and Jeff noted, I can certainly change keep-empty to allow-empty, both
here and in the rebase command.  I'll add a test for it as well, early this
comming week.  Thanks!

Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 2/4] git-rebase: add keep_empty flag
  2012-03-30 20:43   ` Junio C Hamano
@ 2012-03-31 12:59     ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-31 12:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Fri, Mar 30, 2012 at 01:43:22PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Add a command line switch to git-rebase to allow a user the ability to specify
> > that they want to keep any commits in a series that are empty.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > CC: Jeff King <peff@peff.net>
> > CC: Phil Hord <phil.hord@gmail.com>
> > CC: Junio C Hamano <gitster@pobox.com>
> 
> The same comments on Cc: apply to all of your patches.
> 
Roger that.

> >  Documentation/git-rebase.txt |    6 ++++++
> >  git-rebase.sh                |    5 +++++
> >  2 files changed, 11 insertions(+), 0 deletions(-)
> >
> > diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
> > index 504945c..9717d3e 100644
> > --- a/Documentation/git-rebase.txt
> > +++ b/Documentation/git-rebase.txt
> > @@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.
> >  	will be reset to where it was when the rebase operation was
> >  	started.
> >  
> > +--keep-empty::
> > +	Informs git-rebase that comits which are empty should not be
> > +	automatically removed.  This is at times useful when empty commits
> > +	are used to hold developer information and notes, but contain no real
> > +	code changes
> > +
> 
> Unlike "cherry-pick", I think "--keep-empty" is a better name for the
> option than "--allow-empty" in this context.  The difference is that from
> the end-user's point of view, cherry-pick _replays_ commits that exist
> elsewhere, and you are allowing the command to replay empty ones as well,
> while rebase _rebuilds_ commits on the same branch, and you are telling
> the command to keep empty ones.
> 
> "... which are empty should not be removed" is a bit of double-negation,
> though.  Perhaps
> 
> 	--keep-empty::
> 		Keep the commits that do not change anything from its
> 		parents in the result.  This is at times useful when empty
> 		commits are used to hold developer information and notes
> 		without having any real changes.
> 
> But as I rephrased the first part, the last line may have become redundant
> and could safely be removed.
> 
Ack, I can make the above changes.

> The patch does not seem to do anything other than accepting and silently
> ignoring the option, though.
> 
It does, as the use of the option is pushed into the type specific rebase
scripts.  I probably should have rolled this patch in with one of those. I'll
squash it in when I repost.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits
  2012-03-30 20:46   ` Junio C Hamano
@ 2012-03-31 13:01     ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-31 13:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Fri, Mar 30, 2012 at 01:46:13PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Using the keep_empy environment variable, this change allows git-commit-am to
> 
> Is it an environment variable?  I thought not.
> 
Sorry, I use the term loosely.  keep_empty is the script variable I use to track
the keep-empty option.  I can fix up the commit message on my repost.

> > +	# makes this easy
> > +	git cherry-pick --keep-empty "$revisions" && move_to_original_branch
> > +else
> > +	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> > +		--src-prefix=a/ --dst-prefix=b/ \
> > +		--no-renames $root_flag "$revisions" |
> > +	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> > +	move_to_original_branch
> > +fi
> 
> Factor out the "&& move_to_original_branch" at the end of then/else, like
> this:
> 
> 	if ...
>         then
> 		...
>         else
> 		...
>         fi && move_to_original_branch
> 
Will do, thanks!
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits
  2012-03-30 20:47   ` Junio C Hamano
@ 2012-03-31 13:03     ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-31 13:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Fri, Mar 30, 2012 at 01:47:56PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Using the keep_empy environment variable, this change allows git-commit-am to
> > apply empty commits to the new branch we are rebasing to
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > CC: Jeff King <peff@peff.net>
> > CC: Phil Hord <phil.hord@gmail.com>
> > CC: Junio C Hamano <gitster@pobox.com>
> > ---
> >  git-rebase--am.sh |   20 +++++++++++++++-----
> >  1 files changed, 15 insertions(+), 5 deletions(-)
> >
> > diff --git a/git-rebase--am.sh b/git-rebase--am.sh
> > index c815a24..c1d1b60 100644
> > --- a/git-rebase--am.sh
> > +++ b/git-rebase--am.sh
> > @@ -20,11 +20,21 @@ esac
> >  
> >  test -n "$rebase_root" && root_flag=--root
> >  
> > -git format-patch -k --stdout --full-index --ignore-if-in-upstream \
> > -	--src-prefix=a/ --dst-prefix=b/ \
> > -	--no-renames $root_flag "$revisions" |
> > -git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
> > -move_to_original_branch
> > +if [ -n "$keep_empty" ]
> > +then
> > +	# we have to do this the hard way.  git format-patch completly squashes
> > +	# empty commits and even if it didn't the format doesn't really lend
> > +	# itself well to recording empty patches.  fortunately, cherry-pick
> > +	# makes this easy
> > +	git cherry-pick --keep-empty "$revisions" && move_to_original_branch
> 
> Does cherry-pick know the "--ignore-if-in-upstream" trick?  Otherwise I
> suspect that this will introduce a severe regression to the command, as
> the commits that are already in the new base you are rebasing to will all
> be kept as empty commits, no?
> 
Hmm, you may be correct.  I'd not really thought of that.  I can borrow the
format-patch code for that option and incorporate it into cherry-pick to fix
that up.  Would that be sufficient?

Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits
  2012-03-30 20:59   ` Junio C Hamano
@ 2012-03-31 13:11     ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-03-31 13:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Fri, Mar 30, 2012 at 01:59:02PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > This updates git-commit-interactive to recognize and make use of the keep_empty
> > flag.  When not set, git-rebase -i will now comment out commits that are empty,
> > and informs the user that commits which they wish to explicitly keep that are
> > empty should be uncommented, or --keep-empty should be specified.  if keep_empty
> > is specified, all commits, regardless of their empty status are included.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > CC: Jeff King <peff@peff.net>
> > CC: Phil Hord <phil.hord@gmail.com>
> > CC: Junio C Hamano <gitster@pobox.com>
> > ---
> >  git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---
> >  1 files changed, 35 insertions(+), 3 deletions(-)
> >
> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> > index 5812222..97eeb21 100644
> > --- a/git-rebase--interactive.sh
> > +++ b/git-rebase--interactive.sh
> > @@ -191,12 +191,24 @@ git_sequence_editor () {
> >  
> >  pick_one () {
> >  	ff=--ff
> > +	is_empty=$(git show --pretty=format:%b "$@" | wc -l)
> 
> That is a very expensive way to see if the commit is empty, no?
> 
> If and only if commit C is empty, "git rev-parse" on C^{tree} and
> C^^{tree}" will yield the same tree object name.
> 
Ah, you see, I'm learning something :).  I can fix that up.

> > +	if [ $is_empty -eq 0 ]
> 
> Also this test (which by the way is against our coding style guideline)
> shows that the variable is misnamed.
> 
Ok, sorry about that.  I'll switch that to use test

> > +	then
> > +		empty_args=--keep-empty
> > +	fi
> > +
> > +	if [ -n "$keep_empty" ]
> > +	then
> > +		empty_args=--keep_empty
> > +	fi
> > +
> >  	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
> >  	case "$force_rebase" in '') ;; ?*) ff= ;; esac
> >  	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
> >  	test -d "$rewritten" &&
> >  		pick_one_preserving_merges "$@" && return
> > -	output git cherry-pick $ff "$@"
> > +	output git cherry-pick $empty_args $ff "$@"
> >  }
> >  
> >  pick_one_preserving_merges () {
> > @@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
> >  	sed -n "s/^>//p" |
> >  while read -r shortsha1 rest
> >  do
> > +	local comment_out
> 
> bashism.
> 
Roger.

> > +
> > +	if [ -z "$keep_empty" ]
> > +	then
> > +		comment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)
> 
> Ditto.
> 
> > +		if [ $comment_out -eq 0 ]
> > +		then
> > +			comment_out="#pick"
> 
> Perhaps it is easier to read if you say "# pick"?
> 
Sure, easy enough fix

> > +		else
> > +			comment_out="pick"
> > +		fi
> > +	else
> > +		comment_out="pick"
> > +	fi
> > +
> >  	if test t != "$preserve_merges"
> >  	then
> > -		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
> > +		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
> 
> The variable comment_out is grossly misnamed.  Why not do it this way?
> 
I think you meant to assign leader there instead of comment_out, but your point
is a good one :).

> 	comment_out=
> 	if test -z "$keep_empty" && is_empty_commit $shortsha1
>         then
>         	comment_out="# "
> 	fi
> 
>         if ...
>         then
> 		printf "%s\n" "${leader}pick $shortsha1 $rest" >>"$todo"
> 
> > @@ -849,6 +876,11 @@ cat >> "$todo" << EOF
> >  # If you remove a line here THAT COMMIT WILL BE LOST.
> >  # However, if you remove everything, the rebase will be aborted.
> >  #
> > +# Note that commits which are empty at the time of rebasing are 
> > +# commented out.  If you wish to keep empty commits, either 
> > +# specify the --keep-empty option to the rebase command, or 
> > +# uncomment the commits you wish to keep
> > +#
> 
> Good.
> 
> I do not think " either specify...rebase command, or" is necessary here,
> though.  This message is meant to be a quick reminder, not a tutorial.
> Keep it short and sweet.
> 
Copy that, I'll tone down the verbosity.

> Also, you may probably want to add this text _only_ when you have actually
> commented out something.
> 
Easily done.  thanks!
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2]
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (4 preceding siblings ...)
  2012-03-30 20:32 ` [PATCH 0/4] Enhance git-rebases flexibiilty in handling " Junio C Hamano
@ 2012-04-05 19:39 ` Neil Horman
  2012-04-05 19:39   ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Neil Horman
                     ` (4 more replies)
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (4 subsequent siblings)
  10 siblings, 5 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --ignore-if-made-empty, which allows the user to restrict the 
application of --allow-empty to only those commits which were initially empty 
(not those commits made empty by a prior commit).  It also enhances git-rebase
to add a --keep-empty option, which implies the use of the above new options to
cherry-pick.  

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
@ 2012-04-05 19:39   ` Neil Horman
  2012-04-05 20:12     ` Junio C Hamano
  2012-04-05 19:39   ` [PATCH 2/5] git-cherry-pick: add allow-empty option [v2] Neil Horman
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

As a convienience, it would be nice if we could pop entries off the argv_array
structs so that if they had multiple uses in a function, we wouldn't have to
clear them and repopulate common entries.  This patch adds the argv_array_pop
function to do just that.  Common entries can be added to an argv_array first,
then useage specific ones can be added on the end and removed later on.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 argv-array.c |   12 ++++++++++++
 argv-array.h |    1 +
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/argv-array.c b/argv-array.c
index a4e0420..ce24a48 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
 	argv_array_push_nodup(array, strbuf_detach(&v, NULL));
 }
 
+int argv_array_pop(struct argv_array *array, unsigned int num)
+{
+	if (num > array->argc)
+		return -1;
+
+	for(num--; num>0; num--) {
+		free((char **)array->argv[num]);
+		array->argv[num] = NULL;
+	}
+	return 0;
+}
+
 void argv_array_clear(struct argv_array *array)
 {
 	if (array->argv != empty_argv) {
diff --git a/argv-array.h b/argv-array.h
index 74dd2b1..8233243 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
 void argv_array_push(struct argv_array *, const char *);
 __attribute__((format (printf,2,3)))
 void argv_array_pushf(struct argv_array *, const char *fmt, ...);
+int argv_array_pop(struct argv_array *, unsigned int num);
 void argv_array_clear(struct argv_array *);
 
 #endif /* ARGV_ARRAY_H */
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 2/5] git-cherry-pick: add allow-empty option [v2]
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
  2012-04-05 19:39   ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Neil Horman
@ 2012-04-05 19:39   ` Neil Horman
  2012-04-05 19:39   ` [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty " Neil Horman
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operaion.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..c283d8c 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty:
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
  2012-04-05 19:39   ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Neil Horman
  2012-04-05 19:39   ` [PATCH 2/5] git-cherry-pick: add allow-empty option [v2] Neil Horman
@ 2012-04-05 19:39   ` Neil Horman
  2012-04-05 21:01     ` Junio C Hamano
  2012-04-06 18:30     ` Johannes Sixt
  2012-04-05 19:39   ` [PATCH 4/5] git-cherry-pick: Add test to validate new options [v2] Neil Horman
  2012-04-05 19:39   ` [PATCH 5/5] git-rebase: add keep_empty flag [v2] Neil Horman
  4 siblings, 2 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve
empty commits, we open ourselves to the possibility of preserving commits that
are made empty by a previous merge as well, which is almost certainly not what
we want (most of the time).  To handle this, we can add the ignore-if-made-empty
option.  If enabled, it will look at cherry-picked commits, and if the origional
sha1 has the same tree as its parent, then the cherry-pick is comitted as an
empty commit, otherwise the commit is skipped (because it previously made
changes to the tree, but no longer does).

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-cherry-pick.txt |   10 +++-
 builtin/revert.c                  |    2 +
 sequencer.c                       |  113 ++++++++++++++++++++++++++++++++-----
 sequencer.h                       |    1 +
 4 files changed, 111 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index c283d8c..bb7eb4a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,7 +103,7 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
---allow-empty:
+--allow-empty:::
 	By default, cherry-picking an empty commit will fail,
 	indicating that an explicit invocation of `git commit
 	--allow-empty` is required. This option overrides that
@@ -112,6 +112,14 @@ effect to your index in a row.
 	commits that meet the "fast-forward" requirement will be kept
 	even without this option.
 
+--ignore-if-made-empty::
+	If the --allow-empty option is used, all empty commits are kept,
+	including those which were made empty due to a previous change.
+	While this may be desireable, likely it is not.  This option
+	restricts the scope of --allow-empty to only those commits which
+	were created as empty commits (i.e. if for commit C,  C^{tree} and 
+	C^^{tree} are identical).
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..0fa76ca 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,6 +115,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
@@ -122,6 +123,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
 			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "ignore-if-made-empty", &opts->ignore_if_made_empty, "ignore commits already in tree"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index 71929ba..a512598 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -258,26 +259,107 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  * If we are revert, or if our cherry-pick results in a hand merge,
  * we had better say that the current user is responsible for that.
  */
-static int run_git_commit(const char *defmsg, struct replay_opts *opts)
-{
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
+{
+	struct argv_array array;
+	int rc;
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
+
+	if ((!empty) && (opts->ignore_if_made_empty)) {
+		/* Note: This implies --dry-run */
+		argv_array_push(&array, "--porcelain");
+		if (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {
+			/* The dry run exit code of 1 tells us this is
+ 			 * an empty commit, just skip it.
+ 			 */
+			argv_array_clear(&array);
+			return 0;
+		}
+		argv_array_pop(&array, 1);
+	}
+
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+	
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
+
+
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
+
+static int is_origional_commit_empty(struct commit *commit)
+{
+	struct argv_array argv_array;
+	struct child_process cp;
+	char ptree[41], pptree[41];
+	int pipefd[2];
+	FILE *output;
+	int ret = 0;
+
+	if (pipe2(pipefd, 0) < 0)
+		return 0;
+
+	output = xfdopen(pipefd[0], "r");
+
+	argv_array_init(&argv_array);
+	memset(&cp, 0, sizeof(struct child_process));
 
-	args[i] = NULL;
+	argv_array_push(&argv_array, "rev-parse");
+	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	cp.git_cmd = 1;
+	cp.no_stdin = 1;
+	cp.no_stderr = 1;
+	cp.out = pipefd[1];
+	cp.argv = argv_array.argv;
+
+	if (start_command(&cp) < 0)
+		goto out;
+
+	if (fscanf(output, "%s\n", ptree) < 1)
+		goto out;
+
+	finish_command(&cp);
+
+	fclose(output);
+	close(pipefd[0]);
+	argv_array_clear(&argv_array);
+
+	if (pipe2(pipefd, 0) < 0)
+		return 0;
+
+	output = xfdopen(pipefd[0], "r");
+
+	argv_array_push(&argv_array, "rev-parse");
+	argv_array_pushf(&argv_array, "%s^^{tree}", sha1_to_hex(commit->object.sha1));
+	cp.argv = argv_array.argv;
+
+	if (start_command(&cp) < 0)
+		goto out;
+
+	if (fscanf(output, "%s\n", pptree) < 1)
+		goto out;
+
+	finish_command(&cp);
+	close(pipefd[0]);
+
+	if (!strncmp(ptree, pptree, 40))
+		ret = 1;
+out:
+	fclose(output);
+	argv_array_clear(&argv_array);	
+	return ret;
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +371,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +497,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_origional_commit_empty(commit);
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -435,7 +520,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		rerere(opts->allow_rerere_auto);
 	} else {
 		if (!opts->no_commit)
-			res = run_git_commit(defmsg, opts);
+			res = run_git_commit(defmsg, opts, empty_commit);
 	}
 
 	free_message(&msg);
diff --git a/sequencer.h b/sequencer.h
index e2cd725..3e1106f 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int ignore_if_made_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 4/5] git-cherry-pick: Add test to validate new options [v2]
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-05 19:39   ` [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty " Neil Horman
@ 2012-04-05 19:39   ` Neil Horman
  2012-04-05 19:39   ` [PATCH 5/5] git-rebase: add keep_empty flag [v2] Neil Horman
  4 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Since we've added the --allow-empty and --ignore-if-made-empty
options to git cherry-pick we should also add a test to ensure that its working
properly

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 t/t3505-cherry-pick-empty.sh |   31 ++++++++++++++++++++++++++++++-
 1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..049ed28 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,28 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fouth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" && {
+		git cherry-pick empty-branch2
+		test "$?" = 1 
+	}
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master && {
+		git cherry-pick --allow-empty empty-branch2
+		test "$?" = 0
+	}
+'
+
+test_expect_success 'cherry pick with --ignore-if-made-empty' '
+	git checkout master && {
+		git cherry-pick --allow-empty --ignore-if-made-empty empty-branch2
+		test "$?" = 0
+	}
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH 5/5] git-rebase: add keep_empty flag [v2]
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
                     ` (3 preceding siblings ...)
  2012-04-05 19:39   ` [PATCH 4/5] git-cherry-pick: Add test to validate new options [v2] Neil Horman
@ 2012-04-05 19:39   ` Neil Horman
  4 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 19:39 UTC (permalink / raw)
  To: git; +Cc: Neil Horman, Jeff King, Phil Hord, Junio C Hamano

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Jeff King <peff@peff.net>
CC: Phil Hord <phil.hord@gmail.com>
CC: Junio C Hamano <gitster@pobox.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   40 +++++++++++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..a7194f7 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if [ -n "$keep_empty" ]
+then
+	# we have to do this the hard way.  git format-patch completly squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty --ignore-if-made-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..beb06cf 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,12 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	ptree=$(git rev-parse "$1"^{tree})
+	pptree=$(git rev-parse "$1"^^{tree})
+	return test "$ptree" = "$pptree"
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +197,23 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
+	if is_emtpy_commit $@ 
+	then
+		empty_args="--allow-empty --ignore-if-made-empty"
+	fi
+
+	if test -n "$keep_empty" 
+	then
+		empty_args="--allow_empty --ignore-if-made-empty"
+	fi
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +797,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $sha1
+	then
+		comment_out="# pick"
+	else
+		comment_out="pick"
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +826,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +876,15 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	cat >> "$todo" << EOF
+	# Note that commits which are empty at the time of rebasing are 
+	# commented out. 
+	EOF
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 19:39   ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Neil Horman
@ 2012-04-05 20:12     ` Junio C Hamano
  2012-04-05 23:24       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-05 20:12 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> As a convienience, it would be nice if we could pop entries off the argv_array
> structs so that if they had multiple uses in a function, we wouldn't have to
> clear them and repopulate common entries.  This patch adds the argv_array_pop
> function to do just that.  Common entries can be added to an argv_array first,
> then useage specific ones can be added on the end and removed later on.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>


> CC: Jeff King <peff@peff.net>
> CC: Phil Hord <phil.hord@gmail.com>
> CC: Junio C Hamano <gitster@pobox.com>
> ---

Please don't do "Cc:" here; they belong to your e-mail header.

> diff --git a/argv-array.c b/argv-array.c
> index a4e0420..ce24a48 100644
> --- a/argv-array.c
> +++ b/argv-array.c
> @@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
>  	argv_array_push_nodup(array, strbuf_detach(&v, NULL));
>  }
>  
> +int argv_array_pop(struct argv_array *array, unsigned int num)
> +{
> +	if (num > array->argc)
> +		return -1;

If your use case is "After using an argv_array for the first invocation,
truncate it while keeping the common ones that appear early, so that ones
that are specific to the second invocation can be pushed", it strikes me
somewhat odd why you would want to specify "how many to pop".

Wouldn't argv_array_truncate() or argv_array_setlen() make more sense?


> +	for(num--; num>0; num--) {

Gaah.

> +		free((char **)array->argv[num]);
> +		array->argv[num] = NULL;
> +	}
> +	return 0;
> +}
> +
>  void argv_array_clear(struct argv_array *array)
>  {
>  	if (array->argv != empty_argv) {
> diff --git a/argv-array.h b/argv-array.h
> index 74dd2b1..8233243 100644
> --- a/argv-array.h
> +++ b/argv-array.h
> @@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);
>  void argv_array_push(struct argv_array *, const char *);
>  __attribute__((format (printf,2,3)))
>  void argv_array_pushf(struct argv_array *, const char *fmt, ...);
> +int argv_array_pop(struct argv_array *, unsigned int num);
>  void argv_array_clear(struct argv_array *);
>  
>  #endif /* ARGV_ARRAY_H */

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 19:39   ` [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty " Neil Horman
@ 2012-04-05 21:01     ` Junio C Hamano
  2012-04-05 23:45       ` Neil Horman
  2012-04-06 18:06       ` Neil Horman
  2012-04-06 18:30     ` Johannes Sixt
  1 sibling, 2 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-04-05 21:01 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> Subject: Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]

Please don't do this.  The tools do not strip the garbage at the end.

Instead, do it like either one of these:

	Subject: [PATCH 3/5 (v2)] mumble mumble...
	Subject: [PATCH v2 3/5] mumble mumble...

The latter is more appropriate when resending everything, including the
ones that did not change from the earlier round.

> Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve
> empty commits, we open ourselves to the possibility of preserving commits that
> are made empty by a previous merge as well, which is almost certainly not what
> we want (most of the time).  To handle this, we can add the ignore-if-made-empty
> option.  If enabled, it will look at cherry-picked commits, and if the origional
> sha1 has the same tree as its parent, then the cherry-pick is comitted as an
> empty commit, otherwise the commit is skipped (because it previously made
> changes to the tree, but no longer does).
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index c283d8c..bb7eb4a 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -103,7 +103,7 @@ effect to your index in a row.
>  	cherry-pick'ed commit, then a fast forward to this commit will
>  	be performed.
>  
> ---allow-empty:
> +--allow-empty:::

A single colon is already buggy, but three colons is equally bad.  Please
fix that in the original point this bug was introduced.  I guess it was
2/5 of this series?

> @@ -112,6 +112,14 @@ effect to your index in a row.
>  	commits that meet the "fast-forward" requirement will be kept
>  	even without this option.
>  
> +--ignore-if-made-empty::
> +	If the --allow-empty option is used, all empty commits are kept,

Literal strings the user may type are typically set in tt font
(i.e. `--allow-empty`).

> +	including those which were made empty due to a previous change.
> +	While this may be desireable, likely it is not.

Mental note.  Up to this point, the reader is told that "--allow-empty"
alone is likely to do a wrong thing.

> +	This option
> +	restricts the scope of --allow-empty to only those commits which
> +	were created as empty commits ...

And the user is asked to give "--ignore-if-made-empty" in addition to
"--allow-empty" to get a saner and more likely to be useful behaviour.
Isn't that backwards?  This "the other option is insane, and please make
it saner" option needs a lot more typing than the more insane option.

I would expect that "--allow-empty" would by default filter ones that are
originally non-empty but are made unnecessary (we are allowing empty
commits in the original history to be cherry-picked, but the general
principle that unnecessary commits must not be picked still is in effect).
If you want to give a user the other more insane mode of operation, it is
OK to let the user give a different option *instead* *of* the saner
"--allow-empty".

Perhaps name that "--keep-unnecessary-commit" (it is no longer about
allowing empty commits in the original history to be picked; it is about
keeping unnecessary and irrelevant commits in the resulting history).

And error out if both options are given.

> +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
> +{
> +	struct argv_array array;
> +	int rc;
> +
> +	argv_array_init(&array);
> +	argv_array_push(&array, "commit");
> +	argv_array_push(&array, "-n");
> +
> +	if ((!empty) && (opts->ignore_if_made_empty)) {

Style: lose the extra and unnecessary parentheses, especially when the
expression inside them are so trivial, i.e.

	if (!empty && opts->ignore_if_made_empty) {

although I suspect that redesign of the command line interface might make
it a moot point to polish this part of the code without major rethinking.

> +		/* Note: This implies --dry-run */
> +		argv_array_push(&array, "--porcelain");
> +		if (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {

The only thing you want to check at this point is if the contents of the
index being committed is the same as the tree of HEAD.  Why do we even
want to incur this much overhead?

Isn't running "diff-index --cached HEAD" sufficient?

> +			/* The dry run exit code of 1 tells us this is
> + 			 * an empty commit, just skip it.
> + 			 */

	/*
         * Our multi-line comments are
         * formatted this way.
         */

> +			argv_array_clear(&array);
> +			return 0;
> +		}
> +		argv_array_pop(&array, 1);
> +	}
> +
>  
>  	if (opts->signoff)
> +		argv_array_push(&array, "-s");
>  	if (!opts->edit) {
> +		argv_array_push(&array, "-F");
> +		argv_array_push(&array, defmsg);
>  	}
> +	
>  	if (opts->allow_empty)
> +		argv_array_push(&array, "--allow-empty");
> +
> +
> +	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
> +	argv_array_clear(&array);
> +	return rc;
> +}
> +
> +static int is_origional_commit_empty(struct commit *commit)

What is origional?

Is there a reason why this series is not marked as WIP or RFC?

I am starting to wonder if it is worth spending time on careful reviewing,
or it would be sufficient to give a cursory review quickly to give you
more time to polish your re-roll.

> +{
> +	struct argv_array argv_array;
> +	struct child_process cp;
> +	char ptree[41], pptree[41];
> +	int pipefd[2];
> +	FILE *output;
> +	int ret = 0;
> +
> +	if (pipe2(pipefd, 0) < 0)
> +		return 0;
> +
> +	output = xfdopen(pipefd[0], "r");
> +
> +	argv_array_init(&argv_array);
> +	memset(&cp, 0, sizeof(struct child_process));
>  
> -	args[i] = NULL;
> +	argv_array_push(&argv_array, "rev-parse");
> +	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));
>  
> -	return run_command_v_opt(args, RUN_GIT_CMD);
> +	cp.git_cmd = 1;
> +	cp.no_stdin = 1;
> +	cp.no_stderr = 1;
> +	cp.out = pipefd[1];
> +	cp.argv = argv_array.argv;
> +
> +	if (start_command(&cp) < 0)
> +		goto out;
> +
> +	if (fscanf(output, "%s\n", ptree) < 1)
> +		goto out;
> +
> +	finish_command(&cp);
> +
> +	fclose(output);
> +	close(pipefd[0]);
> +	argv_array_clear(&argv_array);
> +
> +	if (pipe2(pipefd, 0) < 0)

Huh?  "man pipe2" and see if it is portable.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 20:12     ` Junio C Hamano
@ 2012-04-05 23:24       ` Neil Horman
  2012-04-06  0:12         ` Neil Horman
                           ` (2 more replies)
  0 siblings, 3 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-05 23:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > As a convienience, it would be nice if we could pop entries off the argv_array
> > structs so that if they had multiple uses in a function, we wouldn't have to
> > clear them and repopulate common entries.  This patch adds the argv_array_pop
> > function to do just that.  Common entries can be added to an argv_array first,
> > then useage specific ones can be added on the end and removed later on.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> 
> 
> > CC: Jeff King <peff@peff.net>
> > CC: Phil Hord <phil.hord@gmail.com>
> > CC: Junio C Hamano <gitster@pobox.com>
> > ---
> 
> Please don't do "Cc:" here; they belong to your e-mail header.
> 
You mean place them below the snip line?  I can do that.

> > diff --git a/argv-array.c b/argv-array.c
> > index a4e0420..ce24a48 100644
> > --- a/argv-array.c
> > +++ b/argv-array.c
> > @@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)
> >  	argv_array_push_nodup(array, strbuf_detach(&v, NULL));
> >  }
> >  
> > +int argv_array_pop(struct argv_array *array, unsigned int num)
> > +{
> > +	if (num > array->argc)
> > +		return -1;
> 
> If your use case is "After using an argv_array for the first invocation,
> truncate it while keeping the common ones that appear early, so that ones
> that are specific to the second invocation can be pushed", it strikes me
> somewhat odd why you would want to specify "how many to pop".
> 
Why?  It seems perfectly logical to me to be able to, as a convienience, specify
how many items to pop, and the api call seems pleasantly symmetric to the
push[f] calls.

> Wouldn't argv_array_truncate() or argv_array_setlen() make more sense?
> 
No, truncate is vague about its meaning.  Truncate to zero would be useless, as
its equivalent to the clear call at that point, and truncating to a specific
value is exactly the same as what I have currently, minus the symmetry to the
push[f] calls.  Likewise setlen doesn't seem to fit in properly, plus theres the
possibility there of believing the api call might be able to set a length longer
than what exists in the array already, which, while silly, requires additional
error checking.  Popping a fixed number of elements off an argv_array that have
previously been pushed makes perfectly good sense to me.

> 
> > +	for(num--; num>0; num--) {
> 
> Gaah.
> 
Eeek :).  If you want something else equally....equal here, please ask for it.
I prefer for loops, but if you would rather have a while loop here, I'm fine
with that.

Regards
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 21:01     ` Junio C Hamano
@ 2012-04-05 23:45       ` Neil Horman
  2012-04-06  1:20         ` Junio C Hamano
  2012-04-06 18:06       ` Neil Horman
  1 sibling, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-05 23:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Subject: Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
> 
> Please don't do this.  The tools do not strip the garbage at the end.
> 
> Instead, do it like either one of these:
> 
> 	Subject: [PATCH 3/5 (v2)] mumble mumble...
> 	Subject: [PATCH v2 3/5] mumble mumble...
> 
> The latter is more appropriate when resending everything, including the
> ones that did not change from the earlier round.
> 
Thats fine, I typically use tools that strip everything inside all braces, I'll
update this on my next re-roll.

> > Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve
> > empty commits, we open ourselves to the possibility of preserving commits that
> > are made empty by a previous merge as well, which is almost certainly not what
> > we want (most of the time).  To handle this, we can add the ignore-if-made-empty
> > option.  If enabled, it will look at cherry-picked commits, and if the origional
> > sha1 has the same tree as its parent, then the cherry-pick is comitted as an
> > empty commit, otherwise the commit is skipped (because it previously made
> > changes to the tree, but no longer does).
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> 
> > diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> > index c283d8c..bb7eb4a 100644
> > --- a/Documentation/git-cherry-pick.txt
> > +++ b/Documentation/git-cherry-pick.txt
> > @@ -103,7 +103,7 @@ effect to your index in a row.
> >  	cherry-pick'ed commit, then a fast forward to this commit will
> >  	be performed.
> >  
> > ---allow-empty:
> > +--allow-empty:::
> 
> A single colon is already buggy, but three colons is equally bad.  Please
> fix that in the original point this bug was introduced.  I guess it was
> 2/5 of this series?
> 
Crap, thanks, I missed that.  I'll square that away


> > @@ -112,6 +112,14 @@ effect to your index in a row.
> >  	commits that meet the "fast-forward" requirement will be kept
> >  	even without this option.
> >  
> > +--ignore-if-made-empty::
> > +	If the --allow-empty option is used, all empty commits are kept,
> 
> Literal strings the user may type are typically set in tt font
> (i.e. `--allow-empty`).
> 
Ack, ok.

> > +	including those which were made empty due to a previous change.
> > +	While this may be desireable, likely it is not.
> 
> Mental note.  Up to this point, the reader is told that "--allow-empty"
> alone is likely to do a wrong thing.
> 
> > +	This option
> > +	restricts the scope of --allow-empty to only those commits which
> > +	were created as empty commits ...
> 
> And the user is asked to give "--ignore-if-made-empty" in addition to
> "--allow-empty" to get a saner and more likely to be useful behaviour.
> Isn't that backwards?  This "the other option is insane, and please make
> it saner" option needs a lot more typing than the more insane option.
> 
> I would expect that "--allow-empty" would by default filter ones that are
> originally non-empty but are made unnecessary (we are allowing empty
> commits in the original history to be cherry-picked, but the general
> principle that unnecessary commits must not be picked still is in effect).
> If you want to give a user the other more insane mode of operation, it is
> OK to let the user give a different option *instead* *of* the saner
> "--allow-empty".
> 
> Perhaps name that "--keep-unnecessary-commit" (it is no longer about
> allowing empty commits in the original history to be picked; it is about
> keeping unnecessary and irrelevant commits in the resulting history).
> 
> And error out if both options are given.
> 
Yeah, ok.  I wasn't really thinking about the direct use case, as I had expected
the typical use to be in the rebase scripts, where this is already wired up, but
I see your point.  I'll reverse the logic.

> > +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
> > +{
> > +	struct argv_array array;
> > +	int rc;
> > +
> > +	argv_array_init(&array);
> > +	argv_array_push(&array, "commit");
> > +	argv_array_push(&array, "-n");
> > +
> > +	if ((!empty) && (opts->ignore_if_made_empty)) {
> 
> Style: lose the extra and unnecessary parentheses, especially when the
> expression inside them are so trivial, i.e.
> 
Ok

> 	if (!empty && opts->ignore_if_made_empty) {
> 
> although I suspect that redesign of the command line interface might make
> it a moot point to polish this part of the code without major rethinking.
> 
> > +		/* Note: This implies --dry-run */
> > +		argv_array_push(&array, "--porcelain");
> > +		if (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {
> 
> The only thing you want to check at this point is if the contents of the
> index being committed is the same as the tree of HEAD.  Why do we even
> want to incur this much overhead?
> 
> Isn't running "diff-index --cached HEAD" sufficient?
Well, I was looking at the git commit code to see what exactly --dry-run did,
and I thought that it was roughly equivalent to diff-index.  But if its lower
overhead to do a diff-index instead, I'll happily change it.

> 
> > +			/* The dry run exit code of 1 tells us this is
> > + 			 * an empty commit, just skip it.
> > + 			 */
> 
> 	/*
>          * Our multi-line comments are
>          * formatted this way.
>          */
> 
Ok.

> > +			argv_array_clear(&array);
> > +			return 0;
> > +		}
> > +		argv_array_pop(&array, 1);
> > +	}
> > +
> >  
> >  	if (opts->signoff)
> > +		argv_array_push(&array, "-s");
> >  	if (!opts->edit) {
> > +		argv_array_push(&array, "-F");
> > +		argv_array_push(&array, defmsg);
> >  	}
> > +	
> >  	if (opts->allow_empty)
> > +		argv_array_push(&array, "--allow-empty");
> > +
> > +
> > +	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
> > +	argv_array_clear(&array);
> > +	return rc;
> > +}
> > +
> > +static int is_origional_commit_empty(struct commit *commit)
> 
> What is origional?
> 
A spelling error :).   Thanks.

> Is there a reason why this series is not marked as WIP or RFC?
> 
Because its not.  It works perfectly well, and its fairly close to done.  So far
your review has turned up one significant operational change, which is easily
re-worked and a few stylistic nits.  Thats how review works, I don't see whats
wrong with that. 

> I am starting to wonder if it is worth spending time on careful reviewing,
> or it would be sufficient to give a cursory review quickly to give you
> more time to polish your re-roll.
> 
I'm not sure what you think is so egregious about this changeset, but if
you have a specific problem, please let me know.  We all make errors, thats why
we review work like this.  All your comment above does is toss a purposeless
insult into the conversation. 
 
> > +{
> > +	struct argv_array argv_array;
> > +	struct child_process cp;
> > +	char ptree[41], pptree[41];
> > +	int pipefd[2];
> > +	FILE *output;
> > +	int ret = 0;
> > +
> > +	if (pipe2(pipefd, 0) < 0)
> > +		return 0;
> > +
> > +	output = xfdopen(pipefd[0], "r");
> > +
> > +	argv_array_init(&argv_array);
> > +	memset(&cp, 0, sizeof(struct child_process));
> >  
> > -	args[i] = NULL;
> > +	argv_array_push(&argv_array, "rev-parse");
> > +	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));
> >  
> > -	return run_command_v_opt(args, RUN_GIT_CMD);
> > +	cp.git_cmd = 1;
> > +	cp.no_stdin = 1;
> > +	cp.no_stderr = 1;
> > +	cp.out = pipefd[1];
> > +	cp.argv = argv_array.argv;
> > +
> > +	if (start_command(&cp) < 0)
> > +		goto out;
> > +
> > +	if (fscanf(output, "%s\n", ptree) < 1)
> > +		goto out;
> > +
> > +	finish_command(&cp);
> > +
> > +	fclose(output);
> > +	close(pipefd[0]);
> > +	argv_array_clear(&argv_array);
> > +
> > +	if (pipe2(pipefd, 0) < 0)
> 
> Huh?  "man pipe2" and see if it is portable.
> 
Crud, I completely forgot that pipe2 was _GNU_SOURCE only.  I'll rework that,
thanks.

Regards
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 23:24       ` Neil Horman
@ 2012-04-06  0:12         ` Neil Horman
  2012-04-06  0:19         ` Jeff King
  2012-04-06  1:20         ` Junio C Hamano
  2 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-06  0:12 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:
> On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:
> > Neil Horman <nhorman@tuxdriver.com> writes:
> > 
> > > As a convienience, it would be nice if we could pop entries off the argv_array
> > > structs so that if they had multiple uses in a function, we wouldn't have to
> > > clear them and repopulate common entries.  This patch adds the argv_array_pop
> > > function to do just that.  Common entries can be added to an argv_array first,
> > > then useage specific ones can be added on the end and removed later on.
> > >
> > > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > 
> > 
> > > CC: Jeff King <peff@peff.net>
> > > CC: Phil Hord <phil.hord@gmail.com>
> > > CC: Junio C Hamano <gitster@pobox.com>
> > > ---
> > 
> > Please don't do "Cc:" here; they belong to your e-mail header.
> > 
> You mean place them below the snip line?  I can do that.
> 
Actually, I can't do that, git-send-email looks for CC: in the patch text, and
git-format-patch automatically inserts the snip line.  I can put the cc's on the
command line, but if git-send-email is parsing this out of the wrong place, that
seems like a bug.  FWIW, CC's in this location are standard practice for kernel
patch submissions.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 23:24       ` Neil Horman
  2012-04-06  0:12         ` Neil Horman
@ 2012-04-06  0:19         ` Jeff King
  2012-04-06  1:12           ` Neil Horman
  2012-04-06  1:20         ` Junio C Hamano
  2 siblings, 1 reply; 121+ messages in thread
From: Jeff King @ 2012-04-06  0:19 UTC (permalink / raw)
  To: Neil Horman; +Cc: Junio C Hamano, git, Phil Hord

On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:

> > > CC: Jeff King <peff@peff.net>
> > > CC: Phil Hord <phil.hord@gmail.com>
> > > CC: Junio C Hamano <gitster@pobox.com>
> > > ---
> > 
> > Please don't do "Cc:" here; they belong to your e-mail header.
> > 
> You mean place them below the snip line?  I can do that.

No, I think he means to drop them entirely; that information is already
in the list of people you have cc'd in the email.

> > > +int argv_array_pop(struct argv_array *array, unsigned int num)
> > > +{
> > > +	if (num > array->argc)
> > > +		return -1;
> > 
> > If your use case is "After using an argv_array for the first invocation,
> > truncate it while keeping the common ones that appear early, so that ones
> > that are specific to the second invocation can be pushed", it strikes me
> > somewhat odd why you would want to specify "how many to pop".
> > 
> Why?  It seems perfectly logical to me to be able to, as a convienience, specify
> how many items to pop, and the api call seems pleasantly symmetric to the
> push[f] calls.

I don't mind a "pop" call if there is a good use, but personally I find
your use case to be hard to read. Your patch 3/5 does this:

  /* make a partial argv */
  argv_array_init(&array);
  argv_array_push(&array, "commit");
  argv_array_push(&array, "-n");

  /* now do some speculative command */
  if (some_logic) {
          argv_array_push(&array, "--porcelain");
          if (run_command(array.argv)) {
              argv_array_clear(&array);
              return 0;
          }
          argv_array_pop(&array, 1);
  }

  /* and then possibly proceed to reuse part of the array */
  argv_array_push(&array, ...);
  argv_array_push(&array, ...);
  run_command(array.argv);

It saves you having to repeat "commit -n", but at the expense of making
the logic much harder to read. I think this is much easier to read:

  if (some_logic) {
          const char *argv[] = { "commit", "-n", "--porcelain", NULL };
          if (run_command(argv))
                  return 0;
  }

  argv_array_init(&array);
  argv_array_push(&array, "commit");
  argv_array_push(&array, "-n");
  argv_array_push(&array, /* other options */);
  run_command(array.argv);

You repeat "-n", but it is very clear what goes into the speculative
command and what goes into the final command (and there is no chance of
the "1" in your pop becoming stale and sending cruft to the real command).

That being said, I think Junio commented on 3/5 that "git commit
--porcelain" is not the right way of doing your speculative command
anyway, so the two commands would not end up sharing any argv anyway.

> > > +	for(num--; num>0; num--) {
> > 
> > Gaah.
> > 
> Eeek :).  If you want something else equally....equal here, please ask for it.
> I prefer for loops, but if you would rather have a while loop here, I'm fine
> with that.

I think he may have been responding to the style (lack of whitespace). I
also find a side-effecting initializer a little non-idiomatic. And
indeed, I think it causes a bug in this case. "num" is an unsigned int.
So what happens to the loop when num is 0 coming in?

I think a more traditional way of writing this would be:

  while (num--) {
          free((char **)array->argv[num);
          array->argv[num] = NULL;
  }

-Peff

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  0:19         ` Jeff King
@ 2012-04-06  1:12           ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-06  1:12 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, git, Phil Hord

On Thu, Apr 05, 2012 at 08:19:42PM -0400, Jeff King wrote:
> On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:
> 
> > > > CC: Jeff King <peff@peff.net>
> > > > CC: Phil Hord <phil.hord@gmail.com>
> > > > CC: Junio C Hamano <gitster@pobox.com>
> > > > ---
> > > 
> > > Please don't do "Cc:" here; they belong to your e-mail header.
> > > 
> > You mean place them below the snip line?  I can do that.
> 
> No, I think he means to drop them entirely; that information is already
> in the list of people you have cc'd in the email.
> 
No, its not, thats what I'm saying.  git send-email parses the above information
to build the CC list.  I can take it out and add the cc's to the command line of
git-send-email, but if parsing the above info is incorrect, that seems like a
bug that needs fixing, one which will get resistance, because its the standard
way alot of other lists use the CC: tag.

> > > > +int argv_array_pop(struct argv_array *array, unsigned int num)
> > > > +{
> > > > +	if (num > array->argc)
> > > > +		return -1;
> > > 
> > > If your use case is "After using an argv_array for the first invocation,
> > > truncate it while keeping the common ones that appear early, so that ones
> > > that are specific to the second invocation can be pushed", it strikes me
> > > somewhat odd why you would want to specify "how many to pop".
> > > 
> > Why?  It seems perfectly logical to me to be able to, as a convienience, specify
> > how many items to pop, and the api call seems pleasantly symmetric to the
> > push[f] calls.
> 
> I don't mind a "pop" call if there is a good use, but personally I find
> your use case to be hard to read. Your patch 3/5 does this:
> 
>   /* make a partial argv */
>   argv_array_init(&array);
>   argv_array_push(&array, "commit");
>   argv_array_push(&array, "-n");
> 
>   /* now do some speculative command */
>   if (some_logic) {
>           argv_array_push(&array, "--porcelain");
>           if (run_command(array.argv)) {
>               argv_array_clear(&array);
>               return 0;
>           }
>           argv_array_pop(&array, 1);
>   }
> 
>   /* and then possibly proceed to reuse part of the array */
>   argv_array_push(&array, ...);
>   argv_array_push(&array, ...);
>   run_command(array.argv);
> 
> It saves you having to repeat "commit -n", but at the expense of making
> the logic much harder to read. I think this is much easier to read:
> 
>   if (some_logic) {
>           const char *argv[] = { "commit", "-n", "--porcelain", NULL };
>           if (run_command(argv))
>                   return 0;
>   }
> 
>   argv_array_init(&array);
>   argv_array_push(&array, "commit");
>   argv_array_push(&array, "-n");
>   argv_array_push(&array, /* other options */);
>   run_command(array.argv);
> 
> You repeat "-n", but it is very clear what goes into the speculative
> command and what goes into the final command (and there is no chance of
> the "1" in your pop becoming stale and sending cruft to the real command).
> 
Ok, I can see the use of the argv array above being more readable, but (I think
your) comment from the first iteration of this patch, suggested re-doing this
logic to use struct argv_array.  I do like the above better.  I'll redo that.
 
> That being said, I think Junio commented on 3/5 that "git commit
> --porcelain" is not the right way of doing your speculative command
> anyway, so the two commands would not end up sharing any argv anyway.
>
I'm still not completely convinced about that, given that commit --porcelain
effectively does a git diff-index, but I'll defer to the experts on that,
diff-index works just as well for this.  And if I use your above static array
implementation instead, I can get rid of the pop api addition entirely.
 
> > > > +	for(num--; num>0; num--) {
> > > 
> > > Gaah.
> > > 
> > Eeek :).  If you want something else equally....equal here, please ask for it.
> > I prefer for loops, but if you would rather have a while loop here, I'm fine
> > with that.
> 
> I think he may have been responding to the style (lack of whitespace). I
That was really my problem with it.  I appreciate the direct comment.  A note
about lack of whitespace is something I can work with, Gaah is not :)

> also find a side-effecting initializer a little non-idiomatic. And
> indeed, I think it causes a bug in this case. "num" is an unsigned int.
> So what happens to the loop when num is 0 coming in?
> 
That should be caught by the case checking logic at the top of the function.
Although I think you're right, the 1 case I think has an OBO error.  Its moot
anyway, if I use your static array approach above, I'll remove all of this.

> I think a more traditional way of writing this would be:
> 
>   while (num--) {
>           free((char **)array->argv[num);
>           array->argv[num] = NULL;
>   }
> 
Thats certainly another way to do it, and I'm happy to do that if its the
consensus.  I just happen to prefer for loops (for no particular reason, its
just me).  But again, using your approach above, this will all get removed.

Thanks for the review.  I'll fix this up, and have a new version in a few days.


Best
Neil
> -Peff
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 23:45       ` Neil Horman
@ 2012-04-06  1:20         ` Junio C Hamano
  0 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-04-06  1:20 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:
>
>> I am starting to wonder if it is worth spending time on careful reviewing,
>> or it would be sufficient to give a cursory review quickly to give you
>> more time to polish your re-roll.
>> 
> I'm not sure what you think is so egregious about this changeset, but if
> you have a specific problem, please let me know.

There is no insult involved. I just didn't know where to start, because
the series was littered with many issues from high level design (e.g. does
the command line interface and API addition make sense?) to low level
styles (e.g. does the new code imitate the style of the existing code
around it?), and in between (e.g. pipe2() is never used in the codebase
without this patch. Is it portable enough?). It was clear that it needed a
lot more work to lose a WIP label (the quality standard in this project is
slightly higher than "the end result seems to compile--let's ship it").

In other words, I was simply being honest.

> We all make errors, thats why
> we review work like this.  All your comment above does is toss a purposeless
> insult into the conversation. 

Making mistakes is one thing.  Sending a series that is not sufficiently
proofread is a completely different matter.  The review process is not a
replacement for your own proofreading.  It comes after that.

If you did proofread the patch [3/5], you would have noticed that the fix
you made to the documentation is a fix for patch [2/5]. You are in much
better position than I or other reviewers to notice it---after all, it is
your addition. The same for the typo in the mysteriously named function.

How else do you expect me to react to such a series?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-05 23:24       ` Neil Horman
  2012-04-06  0:12         ` Neil Horman
  2012-04-06  0:19         ` Jeff King
@ 2012-04-06  1:20         ` Junio C Hamano
  2012-04-06  2:20           ` Jeff King
  2 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-06  1:20 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:
>> Neil Horman <nhorman@tuxdriver.com> writes:
>> 
>> > As a convienience, it would be nice if we could pop entries off the argv_array
>> > structs so that if they had multiple uses in a function, we wouldn't have to
>> > clear them and repopulate common entries.  This patch adds the argv_array_pop
>> > function to do just that.  Common entries can be added to an argv_array first,
>> > then useage specific ones can be added on the end and removed later on.
>> >
>> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
>> 
>> 
>> > CC: Jeff King <peff@peff.net>
>> > CC: Phil Hord <phil.hord@gmail.com>
>> > CC: Junio C Hamano <gitster@pobox.com>
>> > ---
>> 
>> Please don't do "Cc:" here; they belong to your e-mail header.
>> 
> You mean place them below the snip line?  I can do that.

No.  When you review and fix typo in format-patch output, you can add
these to the e-mail header part and git-send-email will pick them up just
fine.

>> If your use case is "After using an argv_array for the first invocation,
>> truncate it while keeping the common ones that appear early, so that ones
>> that are specific to the second invocation can be pushed", it strikes me
>> somewhat odd why you would want to specify "how many to pop".
>> 
> Why?

You know you have N common ones.  You push some more, perhaps with a
sequence of "if (condition) argv_push();" and use it.  Now it is time to
reprepare it for the second usage.  Wouldn't it be more natural to say

	argv_array_setlen(N);
        /* start pushing the specific ones for next invocation */
        argv_array_push();
        if (condition)
        	argv_array_push();

>> > +	for(num--; num>0; num--) {
>> 
>> Gaah.
>> 
> Eeek :).  If you want something else equally....equal here, please ask for it.
> I prefer for loops, but if you would rather have a while loop here, I'm fine
> with that.

Please look at the existing "for ()" loop in the same file, and then go
read the CodingGuidelines.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  1:20         ` Junio C Hamano
@ 2012-04-06  2:20           ` Jeff King
  2012-04-06  4:19             ` Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]) Jonathan Nieder
                               ` (2 more replies)
  0 siblings, 3 replies; 121+ messages in thread
From: Jeff King @ 2012-04-06  2:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Neil Horman, git, Phil Hord

On Thu, Apr 05, 2012 at 06:20:53PM -0700, Junio C Hamano wrote:

> >> > CC: Jeff King <peff@peff.net>
> >> > CC: Phil Hord <phil.hord@gmail.com>
> >> > CC: Junio C Hamano <gitster@pobox.com>
> >> > ---
> >> 
> >> Please don't do "Cc:" here; they belong to your e-mail header.
> >> 
> > You mean place them below the snip line?  I can do that.
> 
> No.  When you review and fix typo in format-patch output, you can add
> these to the e-mail header part and git-send-email will pick them up just
> fine.

I think there is a legitimate conflict of interest here.

It's not clear exactly what "cc" tags in a commit message mean, because
it is really a per-project thing. I don't work on the kernel, but I
always took their cc tag to mean "these are people interested in this
topic area". Send-email helpfully picks up that hint and cc's them on
the emailed patch. And when the patch is applied, those cc lines remain,
because people reading "git log" much later may find a bug in the patch,
and it is helpful to tell them the people interested in the area.

In git.git, though, we don't typically use such cc tags. Perhaps because
we are a much smaller project than the kernel, or perhaps for other
logistical reasons. And even if we did, the cc list above does not
really meet the guideline I gave. They are people who happened to review
your patch or comment on the list, not people who are interested forever
in a particular subsystem.

So from the maintainer's and the project's perspective, those cc lines
are useless noise.

But from the submitter's point of view, it may be convenient to tell git
"these are people who have reviewed _this_ patch series", and have it
automatically cc them on each iteration of the series without re-typing
their addresses.  And because of the send-email behavior I mentioned
above, the "cc" tags are a convenient place to put it.

So it is a piece of information that is useful to the submitter, but not
to the maintainer. Where can the submitter put it that will help
themselves, but not bother the maintainer?  I wonder if the right
solution would be an option for send-email to respect cc lines, but
strip them out of the body of the sent patch.

-Peff

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2])
  2012-04-06  2:20           ` Jeff King
@ 2012-04-06  4:19             ` Jonathan Nieder
  2012-04-06  6:55             ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Junio C Hamano
  2012-04-06 18:02             ` Neil Horman
  2 siblings, 0 replies; 121+ messages in thread
From: Jonathan Nieder @ 2012-04-06  4:19 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, Neil Horman, git, Phil Hord

Jeff King wrote:

> It's not clear exactly what "cc" tags in a commit message mean, because
> it is really a per-project thing. I don't work on the kernel, but I
> always took their cc tag to mean "these are people interested in this
> topic area".

Here's a link from a previous time it came up: [1]

:)
Jonathan

[1] http://thread.gmane.org/gmane.comp.version-control.git/157707/focus=157757

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  2:20           ` Jeff King
  2012-04-06  4:19             ` Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]) Jonathan Nieder
@ 2012-04-06  6:55             ` Junio C Hamano
  2012-04-06  7:33               ` Jeff King
  2012-04-06 18:02             ` Neil Horman
  2 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-06  6:55 UTC (permalink / raw)
  To: Jeff King; +Cc: Neil Horman, git, Phil Hord

Jeff King <peff@peff.net> writes:

> So from the maintainer's and the project's perspective, those cc lines
> are useless noise.
> ...
> So it is a piece of information that is useful to the submitter, but not
> to the maintainer.

... nor the user of the project history, as you said earlier.

I agree that submitters would benefit from an automated way to propagate
these addresses from reroll to reroll, and in a larger workflow "tweak and
record while amending a commit for reroll" would be a natural place to do
so, so I can see why it is tempting to abuse Cc: in the body of the
message, but not knowing other ways is not a good excuse for such an
abuse.  A workable solution is already available [*1*]: commit with a
"---" line followed by Cc: and whatever extra junk while amending.

Even if it did not work to write "---" before the extra Cc:, I do not
think it is such a big deal, though.  As the output file from format-patch
is meant to be read into an editor for final proof-reading, it shouldn't
be too much extra burden to move those Cc: at the end of the log message
to the header part of the message while doing so anyway.


[Footnote]

*1* Here is a trivial demonstration.

I amended the 1.7.10-rc4 on a throw-away branch to make "git show -s" show
this:

-- >8 --
commit aaac56582ce1820551d48bf2b2364cb00f0345cb
Author: Junio C Hamano <gitster@pobox.com>
Date:   Tue Apr 3 09:25:49 2012 -0700

    Git 1.7.10-rc4
    
    Signed-off-by: Junio C Hamano <gitster@pobox.com>
    ---
    Cc: Test user <junio@pobox.com>
    
    This is a cover letter for small one.
-- 8< --

Feeding output from "git format-patch -1 HEAD" for this patch to send-email
does add the "Test user" to the list of recipients, like so:

-- >8 --
0001-Git-1.7.10-rc4.txt
(body) Adding cc: Test user <junio@pobox.com> from line 'Cc: Test user <junio@pobox.com>'
Dry-OK. Log says:
Sendmail: /usr/bin/msmtp -f gitster@pobox.com -i git@vger.kernel.org junio@pobox.com
From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Cc: Test user <junio@pobox.com>
Subject: [PATCH] Git 1.7.10-rc4
Date: Thu,  5 Apr 2012 23:47:09 -0700
Message-Id: <1333694829-4295-1-git-send-email-gitster@pobox.com>
X-Mailer: git-send-email 1.7.10.rc4.54.g1d5dd3

Result: OK
-- 8< --

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  6:55             ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Junio C Hamano
@ 2012-04-06  7:33               ` Jeff King
  2012-04-06 16:49                 ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Jeff King @ 2012-04-06  7:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Neil Horman, git, Phil Hord

On Thu, Apr 05, 2012 at 11:55:18PM -0700, Junio C Hamano wrote:

> I agree that submitters would benefit from an automated way to propagate
> these addresses from reroll to reroll, and in a larger workflow "tweak and
> record while amending a commit for reroll" would be a natural place to do
> so, so I can see why it is tempting to abuse Cc: in the body of the
> message, but not knowing other ways is not a good excuse for such an
> abuse.  A workable solution is already available [*1*]: commit with a
> "---" line followed by Cc: and whatever extra junk while amending.

I've played with that workflow before. While it's a neat trick, note
that something like "format-patch -s" will put the signoff at the end,
like:

  commit subject

  commit body
  ---
  Cc: whomever
  Signed-off-by: you

which is not what you want. We could perhaps teach it to be smarter
about finding a "---", though I worry about hurting people who do not
use an email-based workflow, since they otherwise don't have to care
about "---".

About a year ago I had an RFC series to let "git commit" parse off the
"---" bit and turn it into a git-note (mostly for keeping track of
changes to the series between versions). It does solve that problem, and
response was reasonably positive. It does make things more complicated,
though, because IIRC you have to turn on note-rewriting manually to keep
the notes attached as you rebase.  Ultimately I didn't follow up because
I've found that I just don't end up keeping a lot of notes. I tend to do
the re-roll and then send it out pretty soon afterward, so I just write
any notes in the emails as they go out.

For complex "cc" lists and the like, I have a (fairly hacky) script that
takes an existing message as input and generates a format-patch series
with the to, cc, and in-reply-to fields filled in (and then I ship the
result out via my regular MUA after proof-reading and tweaking).
Potentially git-send-email could do the same thing.

-Peff

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  7:33               ` Jeff King
@ 2012-04-06 16:49                 ` Junio C Hamano
  0 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-04-06 16:49 UTC (permalink / raw)
  To: Jeff King; +Cc: Neil Horman, git, Phil Hord

Jeff King <peff@peff.net> writes:

> On Thu, Apr 05, 2012 at 11:55:18PM -0700, Junio C Hamano wrote:
> ...
> I've played with that workflow before. While it's a neat trick, note
> that something like "format-patch -s" will put the signoff at the end,
> like:
>
>   commit subject
>
>   commit body
>   ---
>   Cc: whomever
>   Signed-off-by: you
>
> which is not what you want.

Well, then "don't do it then".  The reason the Cc: was abused in this
thread originally is about recording the people who reviewed, so you are
doing an amend of an existing commit in an editor.  Why wouldn't the
commit that was already reviewed at least once didn't have S-o-b in the
first place?  In other words, isn't the "-s" option in "format-patch" a
useless feature creep that would only help those with broken workflows?

> About a year ago I had an RFC series to let "git commit" parse off the
> "---" bit and turn it into a git-note ...
> ... Ultimately I didn't follow up because
> I've found that I just don't end up keeping a lot of notes. I tend to do
> the re-roll and then send it out pretty soon afterward, so I just write
> any notes in the emails as they go out.
>
> For complex "cc" lists and the like, I have a (fairly hacky) script that
> takes an existing message as input and generates a format-patch series
> with the to, cc, and in-reply-to fields filled in (and then I ship the
> result out via my regular MUA after proof-reading and tweaking).
> Potentially git-send-email could do the same thing.

Perhaps.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]
  2012-04-06  2:20           ` Jeff King
  2012-04-06  4:19             ` Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]) Jonathan Nieder
  2012-04-06  6:55             ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Junio C Hamano
@ 2012-04-06 18:02             ` Neil Horman
  2 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-06 18:02 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, git, Phil Hord

On Thu, Apr 05, 2012 at 10:20:58PM -0400, Jeff King wrote:
> On Thu, Apr 05, 2012 at 06:20:53PM -0700, Junio C Hamano wrote:
> 
> > >> > CC: Jeff King <peff@peff.net>
> > >> > CC: Phil Hord <phil.hord@gmail.com>
> > >> > CC: Junio C Hamano <gitster@pobox.com>
> > >> > ---
> > >> 
> > >> Please don't do "Cc:" here; they belong to your e-mail header.
> > >> 
> > > You mean place them below the snip line?  I can do that.
> > 
> > No.  When you review and fix typo in format-patch output, you can add
> > these to the e-mail header part and git-send-email will pick them up just
> > fine.
> 
> I think there is a legitimate conflict of interest here.
> 
> It's not clear exactly what "cc" tags in a commit message mean, because
> it is really a per-project thing. I don't work on the kernel, but I
> always took their cc tag to mean "these are people interested in this
> topic area". Send-email helpfully picks up that hint and cc's them on
> the emailed patch. And when the patch is applied, those cc lines remain,
> because people reading "git log" much later may find a bug in the patch,
> and it is helpful to tell them the people interested in the area.
> 
Thats more or less what its for.  Mostly CC's on a patch on lkml are meant to
direct peoples attention to patches for subsystems their interested in.  teh
kernels get_maintainers script generates these typically.  With the volume of
traffic on lkml its often easy for patches to get misplaced by individual
maintainers.  Recording that info in the commit message, while possibly useful,
is most often seen as a harmless side effect.

The major advantage of CC's in the commit log is that it lets you skip the
format-patch stage. I.E. you can just git-send-email directly and have all the
right people CC-ed. Thats very handy when you have a large changeset and the CC
list differs for individual patches.

Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 21:01     ` Junio C Hamano
  2012-04-05 23:45       ` Neil Horman
@ 2012-04-06 18:06       ` Neil Horman
  1 sibling, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-06 18:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:
><snip>

> > +	including those which were made empty due to a previous change.
> > +	While this may be desireable, likely it is not.
> 
> Mental note.  Up to this point, the reader is told that "--allow-empty"
> alone is likely to do a wrong thing.
> 
> > +	This option
> > +	restricts the scope of --allow-empty to only those commits which
> > +	were created as empty commits ...
> 
> And the user is asked to give "--ignore-if-made-empty" in addition to
> "--allow-empty" to get a saner and more likely to be useful behaviour.
> Isn't that backwards?  This "the other option is insane, and please make
> it saner" option needs a lot more typing than the more insane option.
> 
> I would expect that "--allow-empty" would by default filter ones that are
> originally non-empty but are made unnecessary (we are allowing empty
> commits in the original history to be cherry-picked, but the general
> principle that unnecessary commits must not be picked still is in effect).
> If you want to give a user the other more insane mode of operation, it is
> OK to let the user give a different option *instead* *of* the saner
> "--allow-empty".
> 
> Perhaps name that "--keep-unnecessary-commit" (it is no longer about
> allowing empty commits in the original history to be picked; it is about
> keeping unnecessary and irrelevant commits in the resulting history).
> 
> And error out if both options are given.
> 
I'm working on this today, and in doing so, I don't think I like the one or the
other option approach.  I think it makes more sense to use an --option /
--option-harder model here.  Theres precident for this in a few other git
command (git format-patch has --find-copies and --find-copies harder).  I think
we can do an --allow-empty option and a --keep-redundant-commits option, where
the former explicitly keeps commits that were non-empty but are now because
their changes have already been applied.  the latter option then naturally
implies the former.

Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]
  2012-04-05 19:39   ` [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty " Neil Horman
  2012-04-05 21:01     ` Junio C Hamano
@ 2012-04-06 18:30     ` Johannes Sixt
  1 sibling, 0 replies; 121+ messages in thread
From: Johannes Sixt @ 2012-04-06 18:30 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

Am 05.04.2012 21:39, schrieb Neil Horman:
> +	if (pipe2(pipefd, 0) < 0)
> +		return 0;
> +	output = xfdopen(pipefd[0], "r");
> +	memset(&cp, 0, sizeof(struct child_process));
> +	... setup cp ...
> +	if (start_command(&cp) < 0)
> +		goto out;
> +	if (fscanf(output, "%s\n", ptree)<  1)
> +		goto out;
> +	finish_command(&cp);
> +	fclose(output);
> +	close(pipefd[0]);

Instead of this sequence (I quoted only the relevant pieces), use the 
following:

	memset(&cp, 0, sizeof(struct child_process));
	cp.out = -1;
	... set other pieces in cp ...
	if (start_command(&cp) < 0)
		goto out;
	read_in_full(cp.out, ptree, sizeof(ptree));
	/* add suitable error reporting above */
	close(cp.out);
	if (!finish_command(&cp))
		goto out;

i.e.,

1. let start_command create the pipe for you by setting cp.out = -1,
2. avoid fscanf() if read_in_full() is equally simple to use,
3. close the pipe before finish_command(),
4. check the return code of finish_command().

-- Hannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (5 preceding siblings ...)
  2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
@ 2012-04-10 15:47 ` Neil Horman
  2012-04-10 15:47   ` [PATCH v3 1/4] git-cherry-pick: add allow-empty option Neil Horman
                     ` (3 more replies)
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (3 subsequent siblings)
  10 siblings, 4 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-10 15:47 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --keep-redundant-commits, which allows the user to also keep
commits that were made empty via conflict resolution.  It also enhances
git-rebase to add a --keep-empty option which enables rebases to preserve empty
commits. 

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	
V3)
	* reversed the --ignore-if-empty-logic to by default only keep initially
	empty commits

	* replaced --ignore-if-empty with --keep-redundant-commits, to allow
	empty commits that are made empty via conflict resolution, in addition
	to commits that were created as empty

	* reworked is_original_commit_empty to be more efficient and portable

	* Misc sylistic and spelling cleanups


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-10 15:47   ` Neil Horman
  2012-04-10 16:45     ` Junio C Hamano
  2012-04-10 15:47   ` [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-10 15:47 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operation.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/commit.c                  |    6 +++---
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..730237a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/commit.c b/builtin/commit.c
index 3714582..0cd10ab 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -56,10 +56,10 @@ N_("You asked to amend the most recent commit, but doing so would make\n"
 "remove the commit entirely with \"git reset HEAD^\".\n");
 
 static const char empty_cherry_pick_advice[] =
-N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
-"If you wish to commit it anyway, use:\n"
+N_("The previous cherry-pick is empty.\n"
+"If the commit was created empty, please use:\n"
 "\n"
-"    git commit --allow-empty\n"
+"    git cherry-pick --allow-empty\n"
 "\n"
 "Otherwise, please use 'git reset'\n");
 
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-10 15:47   ` [PATCH v3 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-10 15:47   ` Neil Horman
  2012-04-10 17:04     ` Junio C Hamano
  2012-04-10 15:47   ` [PATCH v3 3/4] git-cherry-pick: Add test to validate new options Neil Horman
  2012-04-10 15:47   ` [PATCH v3 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-10 15:47 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

The git-cherry-pick --allow-empty command by default only preserves empty
commits that were originally empty, i.e only those commits for which
<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are
non-empty, but were made empty by the inclusion of a prior commit on the current
history are filtered out.  This option allows us to override that behavior and
include redundant commits as empty commits in the change history.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |   12 ++++-
 builtin/commit.c                  |    5 ++
 builtin/revert.c                  |    8 +++-
 sequencer.c                       |  106 ++++++++++++++++++++++++++++++++-----
 sequencer.h                       |    1 +
 5 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 730237a..f96b8c5 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -110,7 +110,17 @@ effect to your index in a row.
 	behavior, allowing empty commits to be preserved automatically
 	in a cherry-pick. Note that when "--ff" is in effect, empty
 	commits that meet the "fast-forward" requirement will be kept
-	even without this option.
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. where for commit C
+	C^{tree} and C^^{tree} are equal).  Commits which are made empty due to
+	a previous commit are ignored.  To force the inclusion of those commits
+	use `--keep-redundant-commits`
+
+--keep-redundant-commits::
+	If a commit being cherry picked duplicates a commit already in the
+	current history, it will result in an empty changeset.  By default these
+	redundant commits are ignored.  This option overrides that behavior and
+	creates an empty commit object.  Implies `--allow-empty`
 
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
diff --git a/builtin/commit.c b/builtin/commit.c
index 0cd10ab..c386189 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -61,6 +61,11 @@ N_("The previous cherry-pick is empty.\n"
 "\n"
 "    git cherry-pick --allow-empty\n"
 "\n"
+"If the commit was made empty via conflict resolution, and you wish\n"
+"to keep the now-empty commit anyway, use:\n"
+"\n"
+"    git cherry-pick --keep-redundant-commits\n"
+"\n"
 "Otherwise, please use 'git reset'\n");
 
 static const char *use_message_buffer;
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..4f0d979 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
+			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_if_made_empty, "keep redundant, empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
+	/* keep_if_made_empty implies allow_empty */
+	if (opts->keep_if_made_empty)
+		opts->allow_empty = 1;
+
 	/* Set the subcommand */
 	if (remove_state)
 		opts->subcommand = REPLAY_REMOVE_STATE;
diff --git a/sequencer.c b/sequencer.c
index 71929ba..5d033db 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  * If we are revert, or if our cherry-pick results in a hand merge,
  * we had better say that the current user is responsible for that.
  */
-static int run_git_commit(const char *defmsg, struct replay_opts *opts)
+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
 {
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+	struct argv_array array;
+	int rc;
+
+	if (!empty && !opts->keep_if_made_empty) {
+		const char *argv[] = { "diff-index", "--quiet", "--exit-code",
+					"--cached", "HEAD", NULL };
+
+		/*
+ 		 * If we run git diff-index with the above option and it returns
+ 		 * zero, then there have been no changes made to the index by
+ 		 * this patch, i.e. its empty.  Since our previous empty test
+ 		 * indicated that this patch was not created empty, its been made
+ 		 * redundant.  Since keep_if_made_empty is not set, we just skip
+ 		 * it
+ 		 */
+		if (run_command_v_opt(argv, RUN_GIT_CMD) == 0)
+			return 0;
+	}
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+	
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
 
-	args[i] = NULL;
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
+
+static int is_original_commit_empty(struct commit *commit)
+{
+	struct argv_array argv_array;
+	struct child_process cp;
+	char ptree[40], pptree[40];
+	int ret = 0;
+
+	argv_array_init(&argv_array);
+	memset(&cp, 0, sizeof(struct child_process));
+
+	argv_array_push(&argv_array, "rev-parse");
+	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));
+
+	cp.git_cmd = 1;
+	cp.no_stdin = 1;
+	cp.no_stderr = 1;
+	cp.out = -1;
+	cp.argv = argv_array.argv;
+
+	if (start_command(&cp) < 0)
+		goto out;
+
+	if (read_in_full(cp.out, ptree, sizeof(ptree)) < sizeof(ptree)) {
+		close(cp.out);
+		goto out;
+	}
+
+	close(cp.out);
+
+	finish_command(&cp);
+
+	argv_array_clear(&argv_array);
+
+	argv_array_push(&argv_array, "rev-parse");
+	argv_array_pushf(&argv_array, "%s^^{tree}", sha1_to_hex(commit->object.sha1));
+	cp.out = -1;
+	cp.argv = argv_array.argv;
+
+	if (start_command(&cp) < 0)
+		goto out;
+
+	if (read_in_full(cp.out, pptree, sizeof(pptree)) < sizeof(ptree)) {
+		close(cp.out);
+		goto out;
+	}
+
+	close(cp.out);
+
+	finish_command(&cp);
+
+	if (!strncmp(ptree, pptree, sizeof(ptree)))
+		ret = 1;
+out:
+	argv_array_clear(&argv_array);	
+	return ret;
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +366,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +492,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_original_commit_empty(commit);
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -435,7 +515,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		rerere(opts->allow_rerere_auto);
 	} else {
 		if (!opts->no_commit)
-			res = run_git_commit(defmsg, opts);
+			res = run_git_commit(defmsg, opts, empty_commit);
 	}
 
 	free_message(&msg);
diff --git a/sequencer.h b/sequencer.h
index e2cd725..862a79a 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int keep_if_made_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 3/4] git-cherry-pick: Add test to validate new options
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-10 15:47   ` [PATCH v3 1/4] git-cherry-pick: add allow-empty option Neil Horman
  2012-04-10 15:47   ` [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-10 15:47   ` Neil Horman
  2012-04-10 15:47   ` [PATCH v3 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-10 15:47 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

Since we've added the --allow-empty and --keep-redundant-commits
options to git cherry-pick we should also add a test to ensure that its working
properly

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 t/t3505-cherry-pick-empty.sh |   31 ++++++++++++++++++++++++++++++-
 1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..9d419ae 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,28 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fourth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" && {
+		git cherry-pick empty-branch2
+		test "$?" = 1 
+	}
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master && {
+		git cherry-pick --allow-empty empty-branch2
+		test "$?" = 0
+	}
+'
+
+test_expect_success 'cherry pick with --keep-redundant-commits' '
+	git checkout master && {
+		git cherry-pick --keep-redundant-commits HEAD^
+		test "$?" = 0
+	}
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v3 4/4] git-rebase: add keep_empty flag
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-10 15:47   ` [PATCH v3 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-10 15:47   ` Neil Horman
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-10 15:47 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   35 ++++++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..040289c 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if test -n "$keep_empty" 
+then
+	# we have to do this the hard way.  git format-patch completely squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..597d60a 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,12 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	ptree=$(git rev-parse "$1"^{tree})
+	pptree=$(git rev-parse "$1"^^{tree})
+	return $(test "$ptree" = "$pptree")
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +197,18 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
+	if is_empty_commit $@ 
+	then
+		empty_args="--allow-empty"
+	fi
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	then
+		comment_out="# pick"
+	else
+		comment_out="pick"
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +821,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +871,15 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	cat >> "$todo" << EOF
+	# Note that commits which are empty at the time of rebasing are 
+	# commented out. 
+EOF
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 15:47   ` [PATCH v3 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-10 16:45     ` Junio C Hamano
  2012-04-10 18:13       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-10 16:45 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> git cherry-pick fails when picking a non-ff commit that is empty.  The advice
> given with the failure is that a git-commit --allow-empty should be issued to
> explicitly add the empty commit during the cherry pick.  This option allows a
> user to specify before hand that they want to keep the empty commit.  This
> eliminates the need to issue both a cherry pick and a commit operation.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> ---
>  Documentation/git-cherry-pick.txt |    9 +++++++++
>  builtin/commit.c                  |    6 +++---
>  builtin/revert.c                  |    2 ++
>  sequencer.c                       |    7 +++++--
>  sequencer.h                       |    1 +
>  5 files changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index fed5097..730237a 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -103,6 +103,15 @@ effect to your index in a row.
>  	cherry-pick'ed commit, then a fast forward to this commit will
>  	be performed.
>  
> +--allow-empty::
> +	By default, cherry-picking an empty commit will fail,
> +	indicating that an explicit invocation of `git commit
> +	--allow-empty` is required. This option overrides that
> +	behavior, allowing empty commits to be preserved automatically
> +	in a cherry-pick. Note that when "--ff" is in effect, empty
> +	commits that meet the "fast-forward" requirement will be kept
> +	even without this option.
> +
>  --strategy=<strategy>::
>  	Use the given merge strategy.  Should only be used once.
>  	See the MERGE STRATEGIES section in linkgit:git-merge[1]
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 3714582..0cd10ab 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -56,10 +56,10 @@ N_("You asked to amend the most recent commit, but doing so would make\n"
>  "remove the commit entirely with \"git reset HEAD^\".\n");
>  
>  static const char empty_cherry_pick_advice[] =
> -N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
> -"If you wish to commit it anyway, use:\n"
> +N_("The previous cherry-pick is empty.\n"
> +"If the commit was created empty, please use:\n"

After reading this three times, I have to say that the updated wording do
not look like an improvement for two reasons.

 (1) After a failed cherry-pick, the index can match the current HEAD for
     two reasons.  Either the original cherry-pick was attempting to pick
     an empty commit (which is likely to be a mistake unless you are doing
     something unusual like creating an empty commit in the first place),
     or the change in the original commit was already found in the current
     version (may be result of a conflict resolution).  The message before
     your change used "possibly" to hint this, and if the reader gets it,
     it is understandable why the reader is seeing this advise.  Updated
     message loses this information by simply saying "is empty".

 (2) The message is given by the "git commit" command.  "If the commit was
     created empty" looks confusing.  Even though I can understand that
     "the commit" refers to the original commit the user tried to
     cherry-pick before running this command while reviewing this patch, I
     suspect that the reader who sees this message may not be able to tell
     if the "git commit" command created a possibly empty commit and then
     telling the user to do something further on _that_ commit, or if it
     is referring to the commit the user tried to pick with the previous
     "git cherry-pick" command.

That is, unless you are making "git cherry-pick --allow-empty" not to stop
and leave it to "git commit" to clean it up.  If that were the case (which
is not, after applying this patch alone), then this message will be issued
only when a conflict resolution resulted in an empty commit, so "If the
commit you were trying to cherry-pick was empty to begin with" would not
apply, either.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-10 15:47   ` [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-10 17:04     ` Junio C Hamano
  2012-04-10 18:25       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-10 17:04 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> +	/* keep_if_made_empty implies allow_empty */
> +	if (opts->keep_if_made_empty)
> +		opts->allow_empty = 1;
> +
 
OK.

> diff --git a/sequencer.c b/sequencer.c
> index 71929ba..5d033db 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -13,6 +13,7 @@
>  #include "rerere.h"
>  #include "merge-recursive.h"
>  #include "refs.h"
> +#include "argv-array.h"
>  
>  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
>  
> @@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
>   * If we are revert, or if our cherry-pick results in a hand merge,
>   * we had better say that the current user is responsible for that.
>   */
> -static int run_git_commit(const char *defmsg, struct replay_opts *opts)
> +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
>  {
> -	/* 7 is max possible length of our args array including NULL */
> -	const char *args[7];
> -	int i = 0;
> +	struct argv_array array;
> +	int rc;
> +
> +	if (!empty && !opts->keep_if_made_empty) {
> +		const char *argv[] = { "diff-index", "--quiet", "--exit-code",
> +					"--cached", "HEAD", NULL };
> +
> +		/*
> + 		 * If we run git diff-index with the above option and it returns
> + 		 * zero, then there have been no changes made to the index by
> + 		 * this patch, i.e. its empty.  Since our previous empty test
> + 		 * indicated that this patch was not created empty, its been made
> + 		 * redundant.  Since keep_if_made_empty is not set, we just skip
> + 		 * it
> + 		 */
> +		if (run_command_v_opt(argv, RUN_GIT_CMD) == 0)
> +			return 0;

Wouldn't it be far simpler to do this without forking diff-index?  I
haven't followed the codepath leading to this, but it should be very easy
to find a commit object that corresponds to the current HEAD and peek the
tree object in it to find out the current tree, and because the original
function is going to run an as-is "git commit", the tree you are going to
commit should be available by calling cache_tree_update() like write-tree
does.  If they match, you are trying to create an empty commit.  E.g. (error
checking elided):

	unsigned char head_sha1[20];
	struct commit *head_commit;

	resolve_ref_unsafe("HEAD", head_sha1, 1, NULL);
        head_commit = lookup_commit(head_sha1);
        parse_commit(head_commit);

        if (!cache_tree_fully_valid(active_cache_tree))
		cache_tree_update(active_cache_tree, active_cache,
				active_nr, 0);
	return hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);

> +static int is_original_commit_empty(struct commit *commit)
> +{
> +	struct argv_array argv_array;
> +	struct child_process cp;
> +	char ptree[40], pptree[40];
> +	int ret = 0;
> +
> +	argv_array_init(&argv_array);
> +	memset(&cp, 0, sizeof(struct child_process));
> +
> +	argv_array_push(&argv_array, "rev-parse");
> +	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));

Likewise.  You have the commit object, so just make sure it was parsed,
and peek its tree object.  Also do the same for its parent commit.  Now
you have two trees, so you can compare their object names.  E.g. (error
checking elided):

	const unsigned char *ptree_sha1;

	parse_commit(commit);
        if (commit->parents) {
		struct commit *parent = commit->parents->item;
                parse_commit(parent);
                ptree_sha1 = parent->tree->object.sha1;
	} else {
        	ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
        }
	return hashcmp(ptree_sha1, commit->tree->object.sha1);

The higher code structure of this patch looks good, but the lower level
implementation details are done way too inefficiently.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 16:45     ` Junio C Hamano
@ 2012-04-10 18:13       ` Neil Horman
  2012-04-10 19:32         ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-10 18:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > git cherry-pick fails when picking a non-ff commit that is empty.  The advice
> > given with the failure is that a git-commit --allow-empty should be issued to
> > explicitly add the empty commit during the cherry pick.  This option allows a
> > user to specify before hand that they want to keep the empty commit.  This
> > eliminates the need to issue both a cherry pick and a commit operation.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > ---
> >  Documentation/git-cherry-pick.txt |    9 +++++++++
> >  builtin/commit.c                  |    6 +++---
> >  builtin/revert.c                  |    2 ++
> >  sequencer.c                       |    7 +++++--
> >  sequencer.h                       |    1 +
> >  5 files changed, 20 insertions(+), 5 deletions(-)
> >
> > diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> > index fed5097..730237a 100644
> > --- a/Documentation/git-cherry-pick.txt
> > +++ b/Documentation/git-cherry-pick.txt
> > @@ -103,6 +103,15 @@ effect to your index in a row.
> >  	cherry-pick'ed commit, then a fast forward to this commit will
> >  	be performed.
> >  
> > +--allow-empty::
> > +	By default, cherry-picking an empty commit will fail,
> > +	indicating that an explicit invocation of `git commit
> > +	--allow-empty` is required. This option overrides that
> > +	behavior, allowing empty commits to be preserved automatically
> > +	in a cherry-pick. Note that when "--ff" is in effect, empty
> > +	commits that meet the "fast-forward" requirement will be kept
> > +	even without this option.
> > +
> >  --strategy=<strategy>::
> >  	Use the given merge strategy.  Should only be used once.
> >  	See the MERGE STRATEGIES section in linkgit:git-merge[1]
> > diff --git a/builtin/commit.c b/builtin/commit.c
> > index 3714582..0cd10ab 100644
> > --- a/builtin/commit.c
> > +++ b/builtin/commit.c
> > @@ -56,10 +56,10 @@ N_("You asked to amend the most recent commit, but doing so would make\n"
> >  "remove the commit entirely with \"git reset HEAD^\".\n");
> >  
> >  static const char empty_cherry_pick_advice[] =
> > -N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
> > -"If you wish to commit it anyway, use:\n"
> > +N_("The previous cherry-pick is empty.\n"
> > +"If the commit was created empty, please use:\n"
> 
> After reading this three times, I have to say that the updated wording do
> not look like an improvement for two reasons.
> 
>  (1) After a failed cherry-pick, the index can match the current HEAD for
>      two reasons.  Either the original cherry-pick was attempting to pick
>      an empty commit (which is likely to be a mistake unless you are doing
>      something unusual like creating an empty commit in the first place),
>      or the change in the original commit was already found in the current
>      version (may be result of a conflict resolution).  The message before
>      your change used "possibly" to hint this, and if the reader gets it,
>      it is understandable why the reader is seeing this advise.  Updated
>      message loses this information by simply saying "is empty".
> 
I can re-instate the possible language if you like, I don't have a problem with
that.

>  (2) The message is given by the "git commit" command.  "If the commit was
>      created empty" looks confusing.  Even though I can understand that
Its coded within the git commit command code, but is only ever displayed if
whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,
this will only be seen if they type git cherry-pick on the command line.

>      "the commit" refers to the original commit the user tried to
>      cherry-pick before running this command while reviewing this patch, I
>      suspect that the reader who sees this message may not be able to tell
>      if the "git commit" command created a possibly empty commit and then
>      telling the user to do something further on _that_ commit, or if it
>      is referring to the commit the user tried to pick with the previous
>      "git cherry-pick" command.
> 
Given that this message is displayed because the index and HEAD have no changes
leading to what would be an empty commit, which is by default no allowed unless
expressly enabled, I don't think its that confusing at all.  "The commit" can
only refer to the commit being cherry picked, since there is no other.

> That is, unless you are making "git cherry-pick --allow-empty" not to stop
> and leave it to "git commit" to clean it up.  If that were the case (which
> is not, after applying this patch alone), then this message will be issued
> only when a conflict resolution resulted in an empty commit, so "If the
> commit you were trying to cherry-pick was empty to begin with" would not
> apply, either.

Ok, I see what you're saying.  This advice makes sense if you issue git
cherry-pick, but not if you issue git cherry-pick --allow-empty.  I think the
additional advice provided when you add in the keep-redundant-commits patch
though, assuming I re-add the possibly language above, yes?
Neil


> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-10 17:04     ` Junio C Hamano
@ 2012-04-10 18:25       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-10 18:25 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Tue, Apr 10, 2012 at 10:04:32AM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > +	/* keep_if_made_empty implies allow_empty */
> > +	if (opts->keep_if_made_empty)
> > +		opts->allow_empty = 1;
> > +
>  
> OK.
> 
> > diff --git a/sequencer.c b/sequencer.c
> > index 71929ba..5d033db 100644
> > --- a/sequencer.c
> > +++ b/sequencer.c
> > @@ -13,6 +13,7 @@
> >  #include "rerere.h"
> >  #include "merge-recursive.h"
> >  #include "refs.h"
> > +#include "argv-array.h"
> >  
> >  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
> >  
> > @@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
> >   * If we are revert, or if our cherry-pick results in a hand merge,
> >   * we had better say that the current user is responsible for that.
> >   */
> > -static int run_git_commit(const char *defmsg, struct replay_opts *opts)
> > +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
> >  {
> > -	/* 7 is max possible length of our args array including NULL */
> > -	const char *args[7];
> > -	int i = 0;
> > +	struct argv_array array;
> > +	int rc;
> > +
> > +	if (!empty && !opts->keep_if_made_empty) {
> > +		const char *argv[] = { "diff-index", "--quiet", "--exit-code",
> > +					"--cached", "HEAD", NULL };
> > +
> > +		/*
> > + 		 * If we run git diff-index with the above option and it returns
> > + 		 * zero, then there have been no changes made to the index by
> > + 		 * this patch, i.e. its empty.  Since our previous empty test
> > + 		 * indicated that this patch was not created empty, its been made
> > + 		 * redundant.  Since keep_if_made_empty is not set, we just skip
> > + 		 * it
> > + 		 */
> > +		if (run_command_v_opt(argv, RUN_GIT_CMD) == 0)
> > +			return 0;
> 
> Wouldn't it be far simpler to do this without forking diff-index?  I
> haven't followed the codepath leading to this, but it should be very easy
> to find a commit object that corresponds to the current HEAD and peek the
> tree object in it to find out the current tree, and because the original
> function is going to run an as-is "git commit", the tree you are going to
> commit should be available by calling cache_tree_update() like write-tree
> does.  If they match, you are trying to create an empty commit.  E.g. (error
> checking elided):
> 
> 	unsigned char head_sha1[20];
> 	struct commit *head_commit;
> 
> 	resolve_ref_unsafe("HEAD", head_sha1, 1, NULL);
>         head_commit = lookup_commit(head_sha1);
>         parse_commit(head_commit);
> 
>         if (!cache_tree_fully_valid(active_cache_tree))
> 		cache_tree_update(active_cache_tree, active_cache,
> 				active_nr, 0);
> 	return hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
> 
> > +static int is_original_commit_empty(struct commit *commit)
> > +{
> > +	struct argv_array argv_array;
> > +	struct child_process cp;
> > +	char ptree[40], pptree[40];
> > +	int ret = 0;
> > +
> > +	argv_array_init(&argv_array);
> > +	memset(&cp, 0, sizeof(struct child_process));
> > +
> > +	argv_array_push(&argv_array, "rev-parse");
> > +	argv_array_pushf(&argv_array, "%s^{tree}", sha1_to_hex(commit->object.sha1));
> 
> Likewise.  You have the commit object, so just make sure it was parsed,
> and peek its tree object.  Also do the same for its parent commit.  Now
> you have two trees, so you can compare their object names.  E.g. (error
> checking elided):
> 
Honestly, I wasn't aware there was a faster way.  In my last version you
suggested using git diff-index and git rev-parse (allbeit the latter was for use
in the git-rebase script, and I just reused it).  Regardless, I was going with
your previous suggestions.  I can re-do these to use these new suggestions.

Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 18:13       ` Neil Horman
@ 2012-04-10 19:32         ` Junio C Hamano
  2012-04-10 20:00           ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-10 19:32 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:
> ...
>>  (2) The message is given by the "git commit" command.  "If the commit was
>>      created empty" looks confusing.  Even though I can understand that
> Its coded within the git commit command code, but is only ever displayed if
> whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,
> this will only be seen if they type git cherry-pick on the command line.

Here is what I tried, and I think you are wrong.

	$ git cherry-pick $some_commit
        ... conflicts ...
        $ edit so that the working tree matches HEAD
        $ git commit -a
        ... message from status ...
        THE ADVICE IN QUEWSTION COMES HERE!!!

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 19:32         ` Junio C Hamano
@ 2012-04-10 20:00           ` Neil Horman
  2012-04-10 20:32             ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-10 20:00 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:
> > ...
> >>  (2) The message is given by the "git commit" command.  "If the commit was
> >>      created empty" looks confusing.  Even though I can understand that
> > Its coded within the git commit command code, but is only ever displayed if
> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,
> > this will only be seen if they type git cherry-pick on the command line.
> 
> Here is what I tried, and I think you are wrong.
> 
> 	$ git cherry-pick $some_commit
>         ... conflicts ...
>         $ edit so that the working tree matches HEAD
>         $ git commit -a
>         ... message from status ...
>         THE ADVICE IN QUEWSTION COMES HERE!!!
> 
> 
Ok, I admit I didn't really think of that case, but that seems to me to be the
trivial case, which is unlikely to be encountered.  If you do a git cherry-pick and
have conflicts, you by definition don't have a commit that is resolved to empty
(at least not without manual intervention), nor do you have a commit which was
initially empty.  You really have to go out of your way to take a commit that
conflicts, make it empty, and then commit it without realizing that its empty.

I agree that seeing advice regarding git cherry-pick when you run git commit is
awkward, but its no worse than seeing advice indicating you should run git
commit when you run git cherry-pick (i.e. the case in which you run git
cherry-pick <C>, where <C> is empty an not fast-forward-able.

Perhaps whats called for here is and advice differentiator?  I.e if git commit
is run directly from the command line, issue advice relating to using git commit
--allow-empty, otherwise issue advice relating to git cherry-pick.

I think we could do that by looking at the parent process at run time, unless
theres a good way to differentiate by the sate information in .git

Thoughts?
Neil
 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 20:00           ` Neil Horman
@ 2012-04-10 20:32             ` Junio C Hamano
  2012-04-10 20:39               ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-10 20:32 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:
>> Neil Horman <nhorman@tuxdriver.com> writes:
>> 
>> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:
>> > ...
>> >>  (2) The message is given by the "git commit" command.  "If the commit was
>> >>      created empty" looks confusing.  Even though I can understand that
>> > Its coded within the git commit command code, but is only ever displayed if
>> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,
>> > this will only be seen if they type git cherry-pick on the command line.
>> 
>> Here is what I tried, and I think you are wrong.
>> 
>> 	$ git cherry-pick $some_commit
>>         ... conflicts ...
>>         $ edit so that the working tree matches HEAD
>>         $ git commit -a
>>         ... message from status ...
>>         THE ADVICE IN QUEWSTION COMES HERE!!!
>> 
>> 
> Ok, I admit I didn't really think of that case, but that seems to me to be the
> trivial case, which is unlikely to be encountered.  If you do a git cherry-pick and
> have conflicts, you by definition don't have a commit that is resolved to empty...

Not at all unlikely, especially in a distributed world.

You may have seen two patches but they make sense as one so that you apply
to one branch as one change, while the branch you are cherry-picking from
may have these two changes as individual commits.  Neither of them will
apply cleanly to your tree, and your resolution will be "keep mine---I
already have this".

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 20:32             ` Junio C Hamano
@ 2012-04-10 20:39               ` Neil Horman
  2012-04-10 21:09                 ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-10 20:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Tue, Apr 10, 2012 at 01:32:44PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:
> >> Neil Horman <nhorman@tuxdriver.com> writes:
> >> 
> >> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:
> >> > ...
> >> >>  (2) The message is given by the "git commit" command.  "If the commit was
> >> >>      created empty" looks confusing.  Even though I can understand that
> >> > Its coded within the git commit command code, but is only ever displayed if
> >> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,
> >> > this will only be seen if they type git cherry-pick on the command line.
> >> 
> >> Here is what I tried, and I think you are wrong.
> >> 
> >> 	$ git cherry-pick $some_commit
> >>         ... conflicts ...
> >>         $ edit so that the working tree matches HEAD
> >>         $ git commit -a
> >>         ... message from status ...
> >>         THE ADVICE IN QUEWSTION COMES HERE!!!
> >> 
> >> 
> > Ok, I admit I didn't really think of that case, but that seems to me to be the
> > trivial case, which is unlikely to be encountered.  If you do a git cherry-pick and
> > have conflicts, you by definition don't have a commit that is resolved to empty...
> 
> Not at all unlikely, especially in a distributed world.
> 
> You may have seen two patches but they make sense as one so that you apply
> to one branch as one change, while the branch you are cherry-picking from
> may have these two changes as individual commits.  Neither of them will
> apply cleanly to your tree, and your resolution will be "keep mine---I
> already have this".
> 

Ok, fine.  What do you say to my proposal regarding the splitting of the device
dependent on how we were executed?  It seems we can't use a single advice string
in this case, as no matter which we choose there is a use case in which it fails
to make sense.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 20:39               ` Neil Horman
@ 2012-04-10 21:09                 ` Junio C Hamano
  2012-04-11  0:44                   ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-10 21:09 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> ...  What do you say to my proposal regarding the splitting of the device
> dependent on how we were executed?  It seems we can't use a single advice string
> in this case, as no matter which we choose there is a use case in which it fails
> to make sense.

When your cherry-pick got --allow-empty, it should pass --allow-empty to
its inner invocation of commit if it is picking an originally empty
commit, and this advice will not trigger because commit will happily
commit the no-change change.

When your cherry-pick got --allow-empty but not --keep-unnecessary-commit,
its inner invocation of commit must not pass --allow-empty if it is _not_
picking an originally empty commit.  Then the inner commit will fail if it
auto resolves to no change, and the user sees the advice.  The current
advice text is appropriate for this case.

When your cherry-pick did not get either of these flags, its inner
invocation of commit must not pass --allow-empty.  The user sees the
advice when the auto resolved result matches HEAD from the commit invoked
by cherry-pick.  The current advice text is fine for this case, as we say
"possibly", not "we definitely know it was due to conflict resolution".

Or your cherry-pick may have failed due to a conflict, regardless of the
options like --allow-empty or --keep-unnecessary-commit given to it, and
the user may have run commit after resolving the conflict.  The current
advice text is fine for this case, too, as we say "possibly", and it
indeed is what just happened.

So I do not think you need to change anything with respect to the advice
message.

Am I missing some other cases?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-10 21:09                 ` Junio C Hamano
@ 2012-04-11  0:44                   ` Neil Horman
  2012-04-11 16:52                     ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-11  0:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Tue, Apr 10, 2012 at 02:09:17PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > ...  What do you say to my proposal regarding the splitting of the device
> > dependent on how we were executed?  It seems we can't use a single advice string
> > in this case, as no matter which we choose there is a use case in which it fails
> > to make sense.
> 
> When your cherry-pick got --allow-empty, it should pass --allow-empty to
> its inner invocation of commit if it is picking an originally empty
> commit, and this advice will not trigger because commit will happily
> commit the no-change change.
> 
> When your cherry-pick got --allow-empty but not --keep-unnecessary-commit,
> its inner invocation of commit must not pass --allow-empty if it is _not_
> picking an originally empty commit.  Then the inner commit will fail if it
> auto resolves to no change, and the user sees the advice.  The current
> advice text is appropriate for this case.
> 
> When your cherry-pick did not get either of these flags, its inner
> invocation of commit must not pass --allow-empty.  The user sees the
> advice when the auto resolved result matches HEAD from the commit invoked
> by cherry-pick.  The current advice text is fine for this case, as we say
> "possibly", not "we definitely know it was due to conflict resolution".
> 
> Or your cherry-pick may have failed due to a conflict, regardless of the
> options like --allow-empty or --keep-unnecessary-commit given to it, and
> the user may have run commit after resolving the conflict.  The current
> advice text is fine for this case, too, as we say "possibly", and it
> indeed is what just happened.
> 
> So I do not think you need to change anything with respect to the advice
> message.
> 
> Am I missing some other cases?
> 
No, you covered all the cases, but I disagree with your assertion that the advice
is correct (or at least optimal) in any of these cases. If a cherry-pick without
any options is preformed and the commit is empty (regardless of the reason), the
advice given is that git commit --allow-empty should be used.  With the addition
of these new options, thats not true any longer.  Instead of using git commit
--allow-empty, you can use git cherry-pick --allow-empty.

Given your description above though, I'm ok rolling this back.  Regardless of my
disagreement, git commit --allow-empty still works just as well after the
addition of these options, so while I still think its awkward to give git commit
advice on the result of a git cherry-pick operation,  its not any more
problematic than the issues you've pointed out with my change.  I'll roll this
back in my next version and will look for a way to provide better advice in the
future.

Regards
Neil

> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-11  0:44                   ` Neil Horman
@ 2012-04-11 16:52                     ` Junio C Hamano
  2012-04-11 18:29                       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-11 16:52 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> No, you covered all the cases, but I disagree with your assertion that the advice
> is correct (or at least optimal) in any of these cases. If a cherry-pick without
> any options is preformed and the commit is empty (regardless of the reason), the
> advice given is that git commit --allow-empty should be used.  With the addition
> of these new options, thats not true any longer.  Instead of using git commit
> --allow-empty, you can use git cherry-pick --allow-empty.

Sorry, I am confused.  Do you mean that the sequence goes like this (with
concrete examples of command line args)?

	$ git cherry-pick nh/empty-rebase
        ... stops because "git show nh/empty-rebase" is empty
        $ git cherry-pick --allow-empty

But that cannot be correct, without --continue [*1*], i.e.

	$ git cherry-pick --allow-empty --continue

no?  I didn't check, but if the command without --continue in the above
sequence does not error out, I think it is a bug.

I am actually OK with suggesting "git cherry-pick --continue", but then
"cherry-pick --allow-empty" (or "--keep-unnecessary-commits") that punts
and gives the control back to the user should leave enough clue for a
later invocation of itself so that it can realize that the original
invocation was made with "--allow-empty".  In other words, I am OK if the
interaction goes like this:

	$ git cherry-pick --keep-unnecessary-commits nh/empty-rebase
        ... stops due to a conflict
        $ edit builtin/revert.c
        ... the result ends up being empty
        $ git add -u ;# resolved
        $ git cherry-pick --continue


[Side note]

*1* It was an original UI mistake to make the users conclude a "git merge"
that asked the user to help resolving the conflict with "git commit",
which was inherited by "git cherry-pick" and "git revert", especially when
these three commands are merely a special "possibly zero or one stoppage"
case of more general sequencing commands like "am" and "rebase" that can
stop zero or more times to ask the user for help and the way to resume
them is to re-run the same command with "--continue" option (and without
any other arguments), e.g.

	$ git am -3 ./+nh.mbox
        ... stops due to conflict and asks to resolve them
        $ edit builtin/revert.c
        $ git add builtin/revert.c
        $ git am --continue

and also discussed that in the longer-term it would be nice to teach the
oddball commands to honor "--continue".  "am" originally took "--resolved"
(and it still does, and it will do so in the future) for the same purpose,
and we taught it and "cherry-pick" and "revert" to honor "--continue".
Probably we should start teaching "merge" to honor it as well to complete
the vision.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-11 16:52                     ` Junio C Hamano
@ 2012-04-11 18:29                       ` Neil Horman
  2012-04-11 18:50                         ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-11 18:29 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Wed, Apr 11, 2012 at 09:52:21AM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > No, you covered all the cases, but I disagree with your assertion that the advice
> > is correct (or at least optimal) in any of these cases. If a cherry-pick without
> > any options is preformed and the commit is empty (regardless of the reason), the
> > advice given is that git commit --allow-empty should be used.  With the addition
> > of these new options, thats not true any longer.  Instead of using git commit
> > --allow-empty, you can use git cherry-pick --allow-empty.
> 
> Sorry, I am confused.  Do you mean that the sequence goes like this (with
> concrete examples of command line args)?
> 
> 	$ git cherry-pick nh/empty-rebase
>         ... stops because "git show nh/empty-rebase" is empty
>         $ git cherry-pick --allow-empty
> 

No, currently what happens is the following:
$ git cherry-pick nh/empty-rebase
       ... either gets accepted as empty if the cherry-pick qualifies for
fast-forward, or stops if it doesn not, indicating the empty_cherry_pick advice
that git commit --allow-empty should be used.

While that advice is accurate, in that a git commit --allow-empty will accept
the empty commit, it would seem (at least to me) preferable to offer guidance
that git cherry-pick should be used instead in this case, because that is the
command the user was issuing.

> But that cannot be correct, without --continue [*1*], i.e.
> 
> 	$ git cherry-pick --allow-empty --continue
> 
> no?  I didn't check, but if the command without --continue in the above
> sequence does not error out, I think it is a bug.
> 
No, it errors out.  I'm sorry to have confused you.  The only point that I was
trying to make here is that, when running git cherry-pick, its seems awkward to
a user to get advice indicating that git commit --allow-empty should be run.  My
change was intended to resolve that so that advice no how to use cherry-pick
options to avoid the error was  issued instead.  Thats all.  I hadn't considered
the fact that manual resolution of a cherry-pick (where getting advice about git
commit makes more sense) was also a factor here

> I am actually OK with suggesting "git cherry-pick --continue", but then
> "cherry-pick --allow-empty" (or "--keep-unnecessary-commits") that punts
> and gives the control back to the user should leave enough clue for a
> later invocation of itself so that it can realize that the original
> invocation was made with "--allow-empty".  In other words, I am OK if the
> interaction goes like this:
> 
> 	$ git cherry-pick --keep-unnecessary-commits nh/empty-rebase
>         ... stops due to a conflict
>         $ edit builtin/revert.c
>         ... the result ends up being empty
>         $ git add -u ;# resolved
>         $ git cherry-pick --continue
> 
No, Id rather not do that thanks.  The intent of these options we really to
automate the rebase process, so rebasing doesn't stop on empty commits.  Using
the model above seems to disagree with that.

> 
> [Side note]
> 
> *1* It was an original UI mistake to make the users conclude a "git merge"
> that asked the user to help resolving the conflict with "git commit",
> which was inherited by "git cherry-pick" and "git revert", especially when
> these three commands are merely a special "possibly zero or one stoppage"
> case of more general sequencing commands like "am" and "rebase" that can
> stop zero or more times to ask the user for help and the way to resume
> them is to re-run the same command with "--continue" option (and without
> any other arguments), e.g.
> 
> 	$ git am -3 ./+nh.mbox
>         ... stops due to conflict and asks to resolve them
>         $ edit builtin/revert.c
>         $ git add builtin/revert.c
>         $ git am --continue
> 
> and also discussed that in the longer-term it would be nice to teach the
> oddball commands to honor "--continue".  "am" originally took "--resolved"
> (and it still does, and it will do so in the future) for the same purpose,
> and we taught it and "cherry-pick" and "revert" to honor "--continue".
> Probably we should start teaching "merge" to honor it as well to complete
> the vision.
> 
I won't pretend to fully understand the implications of what you said on your
side note here, but yes, from the ways I've used merge in the past, allowing it
to continue would be very nice I think.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-11 18:29                       ` Neil Horman
@ 2012-04-11 18:50                         ` Junio C Hamano
  2012-04-11 18:56                           ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-11 18:50 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

>> But that cannot be correct, without --continue [*1*], i.e.
>> 
>> 	$ git cherry-pick --allow-empty --continue
>> 
>> no?  I didn't check, but if the command without --continue in the above
>> sequence does not error out, I think it is a bug.
>> 
> No, it errors out.  I'm sorry to have confused you.  The only point that I was
> trying to make here is that, when running git cherry-pick, its seems awkward to
> a user to get advice indicating that git commit --allow-empty should be run.

I was only saying that "git cherry-pick --allow-empty" is a *bad*
suggestion because it does *not* work and errors out, and you seem to
agree with me on that point.  I also said I am OK if the suggestion for
this case were to run "git cherry-pick --continue".

But you sound like you are disagreeing with me; I am not sure where you
found what I said not agreeable.  So I am not sure what to say at this
point.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option
  2012-04-11 18:50                         ` Junio C Hamano
@ 2012-04-11 18:56                           ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-11 18:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Phil Hord

On Wed, Apr 11, 2012 at 11:50:29AM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> >> But that cannot be correct, without --continue [*1*], i.e.
> >> 
> >> 	$ git cherry-pick --allow-empty --continue
> >> 
> >> no?  I didn't check, but if the command without --continue in the above
> >> sequence does not error out, I think it is a bug.
> >> 
> > No, it errors out.  I'm sorry to have confused you.  The only point that I was
> > trying to make here is that, when running git cherry-pick, its seems awkward to
> > a user to get advice indicating that git commit --allow-empty should be run.
> 
> I was only saying that "git cherry-pick --allow-empty" is a *bad*
> suggestion because it does *not* work and errors out, and you seem to
> agree with me on that point.  I also said I am OK if the suggestion for
> this case were to run "git cherry-pick --continue".
> 
> But you sound like you are disagreeing with me; I am not sure where you
> found what I said not agreeable.  So I am not sure what to say at this
> point.
> 
I'm sorry, I think I see where our mutual confusion is.  git cherry-pick
--allow-empty _does_ error out on its own.  The advice that I rewrote was meant
to imply that the cherry-pick command should have been rerun with the
--allow-empty option, i.e.:
git cherry-pick --allow-empty <commit>

I can see however, looking at from what I think was your point of view, how the
advice would have been bad, because taken strictly as given, it would fail.

Its all moot however, I've reverted the advice in my tree here.  As soon as I
complete testing of the optimization/rewites to git_run_commit and
is_original_commit_empty, I'll have another set for review.

Regards
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (6 preceding siblings ...)
  2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-13 18:45 ` Neil Horman
  2012-04-13 18:45   ` [PATCH v5 1/4] git-cherry-pick: add allow-empty option Neil Horman
                     ` (3 more replies)
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (2 subsequent siblings)
  10 siblings, 4 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-13 18:45 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --keep-redundant-commits, which allows the user to also keep
commits that were made empty via conflict resolution.  It also enhances
git-rebase to add a --keep-empty option which enables rebases to preserve empty
commits. 

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	
V3)
	* reversed the --ignore-if-empty-logic to by default only keep initially
	empty commits

	* replaced --ignore-if-empty with --keep-redundant-commits, to allow
	empty commits that are made empty via conflict resolution, in addition
	to commits that were created as empty

	* reworked is_original_commit_empty to be more efficient and portable

	* Misc sylistic and spelling cleanups

V4)
	* Reverted the cherry-pick advice changes in V3 based on in-thread
	discussion

	* Rewrote my changes to is_original_commit_empty and run_git_commit to
	not have to fork, making them more efficient.

v5)
	* Additional help text clean up
	* Additional error checking added to run_git_commit code
	* Whitespace cleanup
	* Removed needed cache_tree freeing
	* Test case cleanup
	* Fixed regression in t3404 and t3416 - this turned out to be 
        a problem with the note that git rebase -i adds at the bottom
	of the rebase text.  It was inadvertently indented and caused the
	test fake editor to misread the commit template.  The indentation 
	has been corrected, and these two tests, as well as all the other
	expected tests pass now

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v5 1/4] git-cherry-pick: add allow-empty option
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-13 18:45   ` Neil Horman
  2012-04-13 18:45   ` [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-13 18:45 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operation.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..730237a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-13 18:45   ` [PATCH v5 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-13 18:45   ` Neil Horman
  2012-04-15 10:42     ` Clemens Buchacher
  2012-04-13 18:45   ` [PATCH v5 3/4] git-cherry-pick: Add test to validate new options Neil Horman
  2012-04-13 18:45   ` [PATCH v5 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-13 18:45 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

The git-cherry-pick --allow-empty command by default only preserves empty
commits that were originally empty, i.e only those commits for which
<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are
non-empty, but were made empty by the inclusion of a prior commit on the current
history are filtered out.  This option allows us to override that behavior and
include redundant commits as empty commits in the change history.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |   12 +++++-
 builtin/revert.c                  |    8 +++-
 sequencer.c                       |   90 +++++++++++++++++++++++++++++++------
 sequencer.h                       |    1 +
 4 files changed, 95 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 730237a..0c004e9 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -110,7 +110,17 @@ effect to your index in a row.
 	behavior, allowing empty commits to be preserved automatically
 	in a cherry-pick. Note that when "--ff" is in effect, empty
 	commits that meet the "fast-forward" requirement will be kept
-	even without this option.
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. the commit recorded the
+	same tree as its parent).  Commits which are made empty due to a
+	previous commit are ignored.  To force the inclusion of those commits
+	use `--keep-redundant-commits`.
+
+--keep-redundant-commits::
+	If a commit being cherry picked duplicates a commit already in the
+	current history, it will result in an empty changeset.  By default these
+	redundant commits are ignored.  This option overrides that behavior and
+	creates an empty commit object.  Implies `--allow-empty`.
 
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..4f0d979 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
+			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_if_made_empty, "keep redundant, empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
+	/* keep_if_made_empty implies allow_empty */
+	if (opts->keep_if_made_empty)
+		opts->allow_empty = 1;
+
 	/* Set the subcommand */
 	if (remove_state)
 		opts->subcommand = REPLAY_REMOVE_STATE;
diff --git a/sequencer.c b/sequencer.c
index 71929ba..aefea66 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -258,26 +259,82 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  * If we are revert, or if our cherry-pick results in a hand merge,
  * we had better say that the current user is responsible for that.
  */
-static int run_git_commit(const char *defmsg, struct replay_opts *opts)
-{
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
+{
+	struct argv_array array;
+	int rc;
+
+	if (!empty && !opts->keep_if_made_empty) {
+		unsigned char head_sha1[20];
+		struct commit *head_commit;
+
+		if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+			return error(_("Could not resolve HEAD commit\n"));
+
+		head_commit = lookup_commit(head_sha1);
+		if (!head_commit || parse_commit(head_commit))
+			return error(_("could not parse commit %s\n"),
+				     sha1_to_hex(head_commit->object.sha1));
+
+		if (!active_cache_tree)
+			active_cache_tree = cache_tree();
+
+		if (!cache_tree_fully_valid(active_cache_tree))
+			if (cache_tree_update(active_cache_tree, active_cache,
+					  active_nr, 0))
+				return error(_("Unable to update cache tree\n"));
+
+		rc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
+
+		if (rc)
+			/*
+			 * The head tree and the parent tree match
+			 * meaning the commit is empty.  Since it wasn't created
+			 * empty (based on the previous test), we can conclude
+			 * the commit has been made redundant.  Since we don't
+			 * want to keep redundant commits, just skip this one
+			 */
+			return 0;
+	}
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
+
+
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
+
+static int is_original_commit_empty(struct commit *commit)
+{
+	const unsigned char *ptree_sha1;
 
-	args[i] = NULL;
+	if (parse_commit(commit))
+		return error(_("Could not parse commit %s\n"),
+			     sha1_to_hex(commit->object.sha1));
+	if (commit->parents) {
+		struct commit *parent = commit->parents->item;
+		if (parse_commit(parent))
+			return error(_("Could not parse parent commit %s\n"),
+				sha1_to_hex(parent->object.sha1));
+		ptree_sha1 = parent->tree->object.sha1;
+	} else {
+		ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+	}
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	return !hashcmp(ptree_sha1, commit->tree->object.sha1);
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +346,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +472,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_original_commit_empty(commit);
+	if (empty_commit < 0)
+		return empty_commit;
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -435,7 +497,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		rerere(opts->allow_rerere_auto);
 	} else {
 		if (!opts->no_commit)
-			res = run_git_commit(defmsg, opts);
+			res = run_git_commit(defmsg, opts, empty_commit);
 	}
 
 	free_message(&msg);
diff --git a/sequencer.h b/sequencer.h
index e2cd725..862a79a 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int keep_if_made_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-13 18:45   ` [PATCH v5 1/4] git-cherry-pick: add allow-empty option Neil Horman
  2012-04-13 18:45   ` [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-13 18:45   ` Neil Horman
  2012-04-15  9:39     ` Clemens Buchacher
  2012-04-13 18:45   ` [PATCH v5 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-13 18:45 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

Since we've added the --allow-empty and --keep-redundant-commits
options to git cherry-pick we should also add a test to ensure that its working
properly.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 t/t3505-cherry-pick-empty.sh |   28 +++++++++++++++++++++++++++-
 1 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..5e3ad65 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,25 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fourth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" && {
+		test_must_fail git cherry-pick empty-branch2
+	}
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master && {
+		git cherry-pick --allow-empty empty-branch2
+	}
+'
+
+test_expect_success 'cherry pick with --keep-redundant-commits' '
+	git checkout master && {
+		git cherry-pick --keep-redundant-commits HEAD^
+	}
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v5 4/4] git-rebase: add keep_empty flag
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-13 18:45   ` [PATCH v5 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-13 18:45   ` Neil Horman
  2012-04-15  9:33     ` Clemens Buchacher
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-13 18:45 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Phil Hord, Junio C Hamano, Neil Horman

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   32 +++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..04d8941 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if test -n "$keep_empty"
+then
+	# we have to do this the hard way.  git format-patch completely squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..e3940be 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,12 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	ptree=$(git rev-parse "$1"^{tree})
+	pptree=$(git rev-parse "$1"^^{tree})
+	return $(test "$ptree" = "$pptree")
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +197,18 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
+	if is_empty_commit $@
+	then
+		empty_args="--allow-empty"
+	fi
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	then
+		comment_out="# pick"
+	else
+		comment_out="pick"
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +821,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +871,12 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	echo "# Note that empty commits are commented out" >> "$todo"
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 4/4] git-rebase: add keep_empty flag
  2012-04-13 18:45   ` [PATCH v5 4/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-04-15  9:33     ` Clemens Buchacher
  2012-04-16 16:46       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-15  9:33 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Fri, Apr 13, 2012 at 02:45:07PM -0400, Neil Horman wrote:
>
> Add a command line switch to git-rebase to allow a user the ability to specify
> that they want to keep any commits in a series that are empty.

Thanks. That should be useful.

> +is_empty_commit() {
> +     ptree=$(git rev-parse "$1"^{tree})
> +     pptree=$(git rev-parse "$1"^^{tree})
> +     return $(test "$ptree" = "$pptree")
> +}
> +

What's the extra leading 'p' for? Any reason not to use 'tree' and
'ptree'?

>  pick_one () {
>  	ff=--ff
> +
> +	if is_empty_commit $@
> +	then
> +		empty_args="--allow-empty"
> +	fi
> +
>  	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac

You do not handle the case where pick_one is called with -n. I think you
need to move the case statement in front and then call is_empty_commit
$sha1.

Not that it matters after this change, but in general using $@ without
quotes looks wrong to my eyes.

> @@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
>  	sed -n "s/^>//p" |
>  while read -r shortsha1 rest
>  do
> +
> +	if test -z "$keep_empty" && is_empty_commit $shortsha1
> +	then
> +		comment_out="# pick"
> +	else
> +		comment_out="pick"
> +	fi
> +
>  	if test t != "$preserve_merges"
>  	then
> -		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
> +		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"

How about setting comment_out="# " or comment_out="" instead and then

 printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"

That would read more natural to me.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-13 18:45   ` [PATCH v5 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-15  9:39     ` Clemens Buchacher
  2012-04-16 11:04       ` Neil Horman
  2012-04-16 16:14       ` Neil Horman
  0 siblings, 2 replies; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-15  9:39 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:
>  
> +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
> +	git checkout master &&
> +	echo fourth >> file2 &&
> +	git add file2 &&
> +	git commit -m "fourth" && {
> +		test_must_fail git cherry-pick empty-branch2
> +	}
> +'

You don't need the braces. The same below.

> +
> +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> +	git checkout master && {
> +		git cherry-pick --allow-empty empty-branch2
> +	}
> +'
> +
> +test_expect_success 'cherry pick with --keep-redundant-commits' '
> +	git checkout master && {
> +		git cherry-pick --keep-redundant-commits HEAD^
> +	}
> +'

And the expected result is that the HEAD commit is not removed, right?
You should check for that as well.

Also, please checkout empty-branch2^0 first, in order to make the test
independent of its predecessor.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-13 18:45   ` [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-15 10:42     ` Clemens Buchacher
  2012-04-16 15:38       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-15 10:42 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Fri, Apr 13, 2012 at 02:45:05PM -0400, Neil Horman wrote:
>
> +                     OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_if_made_empty, "keep redundant, empty commits"),

For consistency, I'd prefer if the variable name were the same as the
option. Then I wouldn't have to keep the option<->variable translation
in mind.

>
> +     if (!empty && !opts->keep_if_made_empty) {
[...]
> +                     return 0;
[...]
>       if (opts->allow_empty)
> +             argv_array_push(&array, "--allow-empty");
> +
> +     rc = run_command_v_opt(array.argv, RUN_GIT_CMD);

I find it a bit strange, that if we cherry-pick a commit that was
already empty, we _do_ call git commit (and error out), but if we find a
commit that is made empty, we do _not_ call git commit and quietly
succeed (in not doing anything). But I suppose that is the legacy
behavior?

> +
> +		rc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
> +
> +		if (rc)

rc is short for run_command, for which it stores the return value, no?
Let's not abuse the variable like this and instead use the result
directly:

 if (!hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1))

If you make the entire paragraph leading up to this a separate function,
say index_is_empty(), then the above would read more naturally like
this:

 if (!opts->keep_if_made_empty && !empty && index_is_empty())

> +			/*
> +			 * The head tree and the parent tree match
> +			 * meaning the commit is empty.  Since it wasn't created

Don't you mean the head tree and the index?

> +			 * empty (based on the previous test), we can conclude
> +			 * the commit has been made redundant.  Since we don't
> +			 * want to keep redundant commits, just skip this one
> +			 */
> +			return 0;
> +	}
> +
> +	argv_array_init(&array);
> +	argv_array_push(&array, "commit");
> +	argv_array_push(&array, "-n");
>  
> -	args[i++] = "commit";
> -	args[i++] = "-n";
>  	if (opts->signoff)
> -		args[i++] = "-s";
> +		argv_array_push(&array, "-s");
>  	if (!opts->edit) {
> -		args[i++] = "-F";
> -		args[i++] = defmsg;
> +		argv_array_push(&array, "-F");
> +		argv_array_push(&array, defmsg);
>  	}
> +
>  	if (opts->allow_empty)
> -		args[i++] = "--allow-empty";
> +		argv_array_push(&array, "--allow-empty");
> +
> +

Why two newlines?

> +	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
> +	argv_array_clear(&array);
> +	return rc;
> +}

Looks good to me otherwise.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-15  9:39     ` Clemens Buchacher
@ 2012-04-16 11:04       ` Neil Horman
  2012-04-16 16:14       ` Neil Horman
  1 sibling, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-16 11:04 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:
> >  
> > +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
> > +	git checkout master &&
> > +	echo fourth >> file2 &&
> > +	git add file2 &&
> > +	git commit -m "fourth" && {
> > +		test_must_fail git cherry-pick empty-branch2
> > +	}
> > +'
> 
> You don't need the braces. The same below.
> 
> > +
> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> > +	git checkout master && {
> > +		git cherry-pick --allow-empty empty-branch2
> > +	}
> > +'
> > +
> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
> > +	git checkout master && {
> > +		git cherry-pick --keep-redundant-commits HEAD^
> > +	}
> > +'
> 
> And the expected result is that the HEAD commit is not removed, right?
> You should check for that as well.
> 
> Also, please checkout empty-branch2^0 first, in order to make the test
> independent of its predecessor.
> 

ACK, I'll fix these up, thanks
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-15 10:42     ` Clemens Buchacher
@ 2012-04-16 15:38       ` Neil Horman
  2012-04-16 22:10         ` Clemens Buchacher
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-16 15:38 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Sun, Apr 15, 2012 at 12:42:12PM +0200, Clemens Buchacher wrote:
> On Fri, Apr 13, 2012 at 02:45:05PM -0400, Neil Horman wrote:
> >
> > +                     OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_if_made_empty, "keep redundant, empty commits"),
> 
> For consistency, I'd prefer if the variable name were the same as the
> option. Then I wouldn't have to keep the option<->variable translation
> in mind.
> 
Ok

> >
> > +     if (!empty && !opts->keep_if_made_empty) {
> [...]
> > +                     return 0;
> [...]
> >       if (opts->allow_empty)
> > +             argv_array_push(&array, "--allow-empty");
> > +
> > +     rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
> 
> I find it a bit strange, that if we cherry-pick a commit that was
> already empty, we _do_ call git commit (and error out), but if we find a
> commit that is made empty, we do _not_ call git commit and quietly
> succeed (in not doing anything). But I suppose that is the legacy
> behavior?
> 
Correct, more or less.  The legacy behavior is to call git commit unilaterally.
With this change, we still do that, but we pass --allow-empty to the commit
command, allowing it to preserve the empty commit.  If we specify
keep-redundant-commits, we skip the check to see if the new commit is empty and
create the new (now empty) commit.  The only change is that if we do not specify
keep-redundant-commits, we check to see if the commit is made empty in
git-cherry-pick and skip it if it is.  We could, instead of returning prior to
calling git-commit, use that test to override the keep_empty option below, so
that we don't pass --allow-empty to git-commit instead.  That would preserve the
prior code path, but for no real advatage, as the outcome is the same, and this
way saves us having to fork the git-commit command, which I think is
adventageous.

> > +
> > +		rc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
> > +
> > +		if (rc)
> 
> rc is short for run_command, for which it stores the return value, no?
> Let's not abuse the variable like this and instead use the result
> directly:
> 
No.  rc is short for return code, generically used to represent the value
to be returned from a function. Its used in this fashion in any number of
places, both in git and any other project. 

>  if (!hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1))
> 
> If you make the entire paragraph leading up to this a separate function,
> say index_is_empty(), then the above would read more naturally like
> this:
> 
>  if (!opts->keep_if_made_empty && !empty && index_is_empty())
> 
> > +			/*
> > +			 * The head tree and the parent tree match
> > +			 * meaning the commit is empty.  Since it wasn't created
> 
> Don't you mean the head tree and the index?
> 
yeah.

> > +			 * empty (based on the previous test), we can conclude
> > +			 * the commit has been made redundant.  Since we don't
> > +			 * want to keep redundant commits, just skip this one
> > +			 */
> > +			return 0;
> > +	}
> > +
> > +	argv_array_init(&array);
> > +	argv_array_push(&array, "commit");
> > +	argv_array_push(&array, "-n");
> >  
> > -	args[i++] = "commit";
> > -	args[i++] = "-n";
> >  	if (opts->signoff)
> > -		args[i++] = "-s";
> > +		argv_array_push(&array, "-s");
> >  	if (!opts->edit) {
> > -		args[i++] = "-F";
> > -		args[i++] = defmsg;
> > +		argv_array_push(&array, "-F");
> > +		argv_array_push(&array, defmsg);
> >  	}
> > +
> >  	if (opts->allow_empty)
> > -		args[i++] = "--allow-empty";
> > +		argv_array_push(&array, "--allow-empty");
> > +
> > +
> 
> Why two newlines?
> 
> > +	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
> > +	argv_array_clear(&array);
> > +	return rc;
> > +}
> 
> Looks good to me otherwise.
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-15  9:39     ` Clemens Buchacher
  2012-04-16 11:04       ` Neil Horman
@ 2012-04-16 16:14       ` Neil Horman
  2012-04-16 16:35         ` Junio C Hamano
  1 sibling, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-16 16:14 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:
> >  
> > +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
> > +	git checkout master &&
> > +	echo fourth >> file2 &&
> > +	git add file2 &&
> > +	git commit -m "fourth" && {
> > +		test_must_fail git cherry-pick empty-branch2
> > +	}
> > +'
> 
> You don't need the braces. The same below.
> 
Ack

> > +
> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> > +	git checkout master && {
> > +		git cherry-pick --allow-empty empty-branch2
> > +	}
> > +'
> > +
> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
> > +	git checkout master && {
> > +		git cherry-pick --keep-redundant-commits HEAD^
> > +	}
> > +'
> 
> And the expected result is that the HEAD commit is not removed, right?
> You should check for that as well.
> 
> Also, please checkout empty-branch2^0 first, in order to make the test
> independent of its predecessor.
> 

Not sure I follow what your saying here.  The expected result with both of these
tests is that a new commit is created, referencing the current HEAD as the new
HEAD's parent.  We could check that the current HEAD is note removed (ostensibly
by recoding the value of the current head and comparing it to HEAD^ after the
cherry pick, but that seems like expected behavior for any command that creates
a new commit, yet we don't check that anywhere else.  Why is here different?  Or
do you mean something else?

As for the checkout of empty-branch2^0, whats the purpose?  I'm just going to
checkout master right after that, making it moot.  The purpose of the test is to
apply a commit that is already in the working tree's history, ensuring that it
resolves to an empty commit.  Theres nothing really dependent on the prior test
there.  If we edit the tests significantly, the contents of what that commit is
may change, but thats not overly relevant, as the result will still be the same
(an empty commit).

Neil
 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-16 16:14       ` Neil Horman
@ 2012-04-16 16:35         ` Junio C Hamano
  2012-04-16 16:50           ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-16 16:35 UTC (permalink / raw)
  To: Neil Horman; +Cc: Clemens Buchacher, git, Jeff King, Phil Hord, Junio C Hamano

Neil Horman <nhorman@tuxdriver.com> writes:

> On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> ...
>> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
>> > +	git checkout master && {
>> > +		git cherry-pick --allow-empty empty-branch2
>> > +	}
>> > +'
>> > +
>> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
>> > +	git checkout master && {
>> > +		git cherry-pick --keep-redundant-commits HEAD^
>> > +	}
>> > +'
>> 
>> And the expected result is that the HEAD commit is not removed, right?
>> You should check for that as well.
>> 
>> Also, please checkout empty-branch2^0 first, in order to make the test
>> independent of its predecessor.
>
> Not sure I follow what your saying here.  The expected result with both of these
> tests is that a new commit is created, referencing the current HEAD as the new
> HEAD's parent.

If the request were "checkout master^0 first" I would understand.  The
precondition for the second test will be different depending on the first
one succeeds or not.  Perhaps that is what Clemens meant?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 4/4] git-rebase: add keep_empty flag
  2012-04-15  9:33     ` Clemens Buchacher
@ 2012-04-16 16:46       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-16 16:46 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Sun, Apr 15, 2012 at 11:33:03AM +0200, Clemens Buchacher wrote:
> On Fri, Apr 13, 2012 at 02:45:07PM -0400, Neil Horman wrote:
> >
> > Add a command line switch to git-rebase to allow a user the ability to specify
> > that they want to keep any commits in a series that are empty.
> 
> Thanks. That should be useful.
> 
> > +is_empty_commit() {
> > +     ptree=$(git rev-parse "$1"^{tree})
> > +     pptree=$(git rev-parse "$1"^^{tree})
> > +     return $(test "$ptree" = "$pptree")
> > +}
> > +
> 
> What's the extra leading 'p' for? Any reason not to use 'tree' and
> 'ptree'?
> 
Hold-over from when I did this in C (pointer to tree vs. pointer to parent
tree).  I can remove the p though, as you right, it makes less sense in a shell

> >  pick_one () {
> >  	ff=--ff
> > +
> > +	if is_empty_commit $@
> > +	then
> > +		empty_args="--allow-empty"
> > +	fi
> > +
> >  	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
> 
> You do not handle the case where pick_one is called with -n. I think you
> need to move the case statement in front and then call is_empty_commit
> $sha1.
> 
> Not that it matters after this change, but in general using $@ without
> quotes looks wrong to my eyes.
> 
Ack, to both points.

> > @@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
> >  	sed -n "s/^>//p" |
> >  while read -r shortsha1 rest
> >  do
> > +
> > +	if test -z "$keep_empty" && is_empty_commit $shortsha1
> > +	then
> > +		comment_out="# pick"
> > +	else
> > +		comment_out="pick"
> > +	fi
> > +
> >  	if test t != "$preserve_merges"
> >  	then
> > -		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
> > +		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
> 
> How about setting comment_out="# " or comment_out="" instead and then
> 
>  printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"
> 
> That would read more natural to me.
Yeah, I can do that
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-16 16:35         ` Junio C Hamano
@ 2012-04-16 16:50           ` Neil Horman
  2012-04-16 21:42             ` Clemens Buchacher
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-16 16:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Clemens Buchacher, git, Jeff King, Phil Hord

On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> > ...
> >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> >> > +	git checkout master && {
> >> > +		git cherry-pick --allow-empty empty-branch2
> >> > +	}
> >> > +'
> >> > +
> >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
> >> > +	git checkout master && {
> >> > +		git cherry-pick --keep-redundant-commits HEAD^
> >> > +	}
> >> > +'
> >> 
> >> And the expected result is that the HEAD commit is not removed, right?
> >> You should check for that as well.
> >> 
> >> Also, please checkout empty-branch2^0 first, in order to make the test
> >> independent of its predecessor.
> >
> > Not sure I follow what your saying here.  The expected result with both of these
> > tests is that a new commit is created, referencing the current HEAD as the new
> > HEAD's parent.
> 
> If the request were "checkout master^0 first" I would understand.  The
> precondition for the second test will be different depending on the first
> one succeeds or not.  Perhaps that is what Clemens meant?
> 
Perhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects
these tests at all, nor do I grok the relevance to ensuring that the HEAD commit
wasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you
clarify your thoughts here please?
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-16 16:50           ` Neil Horman
@ 2012-04-16 21:42             ` Clemens Buchacher
  2012-04-17 10:56               ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-16 21:42 UTC (permalink / raw)
  To: Neil Horman; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Mon, Apr 16, 2012 at 12:50:24PM -0400, Neil Horman wrote:
> On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:
> > Neil Horman <nhorman@tuxdriver.com> writes:
> > 
> > > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> > > ...
> > >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> > >> > +	git checkout master && {
> > >> > +		git cherry-pick --allow-empty empty-branch2
> > >> > +	}
> > >> > +'
> > >> > +
> > >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
> > >> > +	git checkout master && {
> > >> > +		git cherry-pick --keep-redundant-commits HEAD^
> > >> > +	}
> > >> > +'
> > >> 
> > >> And the expected result is that the HEAD commit is not removed, right?
> > >> You should check for that as well.
> > >> 
> > >> Also, please checkout empty-branch2^0 first, in order to make the test
> > >> independent of its predecessor.
> > >
> > > Not sure I follow what your saying here.  The expected result with both of these
> > > tests is that a new commit is created, referencing the current HEAD as the new
> > > HEAD's parent.
> > 
> > If the request were "checkout master^0 first" I would understand.  The
> > precondition for the second test will be different depending on the first
> > one succeeds or not.  Perhaps that is what Clemens meant?
> > 
> Perhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects
> these tests at all, nor do I grok the relevance to ensuring that the HEAD commit
> wasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you
> clarify your thoughts here please?

It seems that I was implying a lot more than I realized. What I meant
was that master and empty-branch2 are equivalent for the purposes of
that test (empty-branch2^ also is a non-empty commit [*1*]), but while
master is a moving target, empty-branch2 is untouched. 

However, I just notice that empty-branch2 is also the root commit, so
maybe this will not work after all. But that should be easy to fix.

And now I am also wondering why we have two tests for cherry picking an
empty commit without --allow-empty (the one that you added and the one
that was there before). Is the non-ff part significant and if so, how?
And why don't we need to test fast-forward cherry-pick with
--allow-empty?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-16 15:38       ` Neil Horman
@ 2012-04-16 22:10         ` Clemens Buchacher
  2012-04-17 10:43           ` Neil Horman
  2012-04-17 15:42           ` Junio C Hamano
  0 siblings, 2 replies; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-16 22:10 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:
> > 
> > I find it a bit strange, that if we cherry-pick a commit that was
> > already empty, we _do_ call git commit (and error out), but if we find a
> > commit that is made empty, we do _not_ call git commit and quietly
> > succeed (in not doing anything). But I suppose that is the legacy
> > behavior?
>
> Correct, more or less.  The legacy behavior is to call git commit unilaterally.
> [...] The only change is that if we do not specify
> keep-redundant-commits, we check to see if the commit is made empty in
> git-cherry-pick and skip it if it is.  We could, instead of returning prior to
> calling git-commit, use that test to override the keep_empty option below, so
> that we don't pass --allow-empty to git-commit instead.  That would preserve the
> prior code path, but for no real advatage, as the outcome is the same, and this
> way saves us having to fork the git-commit command, which I think is
> adventageous.

Except that the outcome is not the same. With and without your changes,
git cherry-pick <empty-commit> fails. But with your changes, git
cherry-pick <commit-will-become-empty> will succeed and do nothing,
while before it would have failed exactly like git cherry-pick
<empty-commit>.

So I am not arguing whether failing or skipping is the better default
behavior. But the legacy behavior is consistent between the empty-commit
and commit-will-become-empty cases.  And if we change the behavior for
one, why not also for the other?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-16 22:10         ` Clemens Buchacher
@ 2012-04-17 10:43           ` Neil Horman
  2012-04-17 15:42           ` Junio C Hamano
  1 sibling, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-17 10:43 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Jeff King, Phil Hord, Junio C Hamano

On Tue, Apr 17, 2012 at 12:10:18AM +0200, Clemens Buchacher wrote:
> On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:
> > > 
> > > I find it a bit strange, that if we cherry-pick a commit that was
> > > already empty, we _do_ call git commit (and error out), but if we find a
> > > commit that is made empty, we do _not_ call git commit and quietly
> > > succeed (in not doing anything). But I suppose that is the legacy
> > > behavior?
> >
> > Correct, more or less.  The legacy behavior is to call git commit unilaterally.
> > [...] The only change is that if we do not specify
> > keep-redundant-commits, we check to see if the commit is made empty in
> > git-cherry-pick and skip it if it is.  We could, instead of returning prior to
> > calling git-commit, use that test to override the keep_empty option below, so
> > that we don't pass --allow-empty to git-commit instead.  That would preserve the
> > prior code path, but for no real advatage, as the outcome is the same, and this
> > way saves us having to fork the git-commit command, which I think is
> > adventageous.
> 
> Except that the outcome is not the same. With and without your changes,
> git cherry-pick <empty-commit> fails. But with your changes, git
> cherry-pick <commit-will-become-empty> will succeed and do nothing,
> while before it would have failed exactly like git cherry-pick
> <empty-commit>.
> 
> So I am not arguing whether failing or skipping is the better default
> behavior. But the legacy behavior is consistent between the empty-commit
> and commit-will-become-empty cases.  And if we change the behavior for
> one, why not also for the other?
> 

Ah, I see what you're saying.  Yes, hadn't thought of that, Ok, I'll change the
logic to just toggle the addition of the --allow-empty flag to git commit.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-16 21:42             ` Clemens Buchacher
@ 2012-04-17 10:56               ` Neil Horman
  2012-04-17 21:38                 ` Clemens Buchacher
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-17 10:56 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:
> On Mon, Apr 16, 2012 at 12:50:24PM -0400, Neil Horman wrote:
> > On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:
> > > Neil Horman <nhorman@tuxdriver.com> writes:
> > > 
> > > > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:
> > > > ...
> > > >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
> > > >> > +	git checkout master && {
> > > >> > +		git cherry-pick --allow-empty empty-branch2
> > > >> > +	}
> > > >> > +'
> > > >> > +
> > > >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '
> > > >> > +	git checkout master && {
> > > >> > +		git cherry-pick --keep-redundant-commits HEAD^
> > > >> > +	}
> > > >> > +'
> > > >> 
> > > >> And the expected result is that the HEAD commit is not removed, right?
> > > >> You should check for that as well.
> > > >> 
> > > >> Also, please checkout empty-branch2^0 first, in order to make the test
> > > >> independent of its predecessor.
> > > >
> > > > Not sure I follow what your saying here.  The expected result with both of these
> > > > tests is that a new commit is created, referencing the current HEAD as the new
> > > > HEAD's parent.
> > > 
> > > If the request were "checkout master^0 first" I would understand.  The
> > > precondition for the second test will be different depending on the first
> > > one succeeds or not.  Perhaps that is what Clemens meant?
> > > 
> > Perhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects
> > these tests at all, nor do I grok the relevance to ensuring that the HEAD commit
> > wasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you
> > clarify your thoughts here please?
> 
> It seems that I was implying a lot more than I realized. What I meant
> was that master and empty-branch2 are equivalent for the purposes of
> that test (empty-branch2^ also is a non-empty commit [*1*]), but while
> master is a moving target, empty-branch2 is untouched. 
> 
for the purposes of the --keep-redundant-commits however, the target is
irrelevant.  The only requirement is that we cherry-pick a commit that is
guaranteed to become empty when applied.  We certainly could do that on empty
branch2, but theres no advantage to doing so, and given that every other test
attempts to cherry-pick to master, I rather like the consistency.

> However, I just notice that empty-branch2 is also the root commit, so
> maybe this will not work after all. But that should be easy to fix.
It is easy to fix, given your clarified description above, its just that IMO,
its not broken.

> 
> And now I am also wondering why we have two tests for cherry picking an
> empty commit without --allow-empty (the one that you added and the one
> that was there before). Is the non-ff part significant and if so, how?
> And why don't we need to test fast-forward cherry-pick with
> --allow-empty?
the difference is that the initial empty-branch doesn't just hold an empty
commit, but also contains no commit log entry on that empty commit, which
git-cherry-pick errors out on in the 'cherry-pick a commit with an empty
message' test, and the 'cherry-pick an empty commit' test.
I could modify the --allow-empty switch to include commits with
no log message, but I didn't want to open that can of worms.

The test separation beyond that is the difference between a failing and a
successful test with an empty commit that still has a changelog entry.

As far as the ff logic goes.  If a cherry pick qualifies for fast forwarding,
then empty commits are automatically are allowed already.  Its only if a cherry
pick cannot be fast forwarded that its empty status is considered, hence the
creation of the 'fourth' commit in the new tests to ensure that the cherry pick
doesn't qualify as a fast forward.

Neil
 
> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-16 22:10         ` Clemens Buchacher
  2012-04-17 10:43           ` Neil Horman
@ 2012-04-17 15:42           ` Junio C Hamano
  2012-04-17 21:37             ` Clemens Buchacher
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-17 15:42 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: Neil Horman, git, Jeff King, Phil Hord

Clemens Buchacher <drizzd@aon.at> writes:

> On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:
> ...
> Except that the outcome is not the same. With and without your changes,
> git cherry-pick <empty-commit> fails. But with your changes, git
> cherry-pick <commit-will-become-empty> will succeed and do nothing,
> while before it would have failed exactly like git cherry-pick
> <empty-commit>.
>
> So I am not arguing whether failing or skipping is the better default
> behavior. But the legacy behavior is consistent between the empty-commit
> and commit-will-become-empty cases.

Is that particular "consistency" a good one, though?  If you had an empty
commit in the original range, it is a lot more likely that it was an error
that you would want to know about.  You may be the kind of person who
value an empty commit in your history, using it as some kind of a mark in
the history, and in that case you would want to know that it is being
discarded.  On the other hand, if a commit that did something in the
original context turns out to be unnecessary in the replayed context, that
is not something you would ever want to keep in the replayed context, and
erroring out and forcing you to say "yeah, I admit I do not want it" would
just be annoying.

So "consistency" between the two would actually be a mistake that we may
want to "break", I would think.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (7 preceding siblings ...)
  2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-17 18:20 ` Neil Horman
  2012-04-17 18:20   ` [PATCH v6 1/4] git-cherry-pick: add allow-empty option Neil Horman
                     ` (3 more replies)
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  10 siblings, 4 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-17 18:20 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --keep-redundant-commits, which allows the user to also keep
commits that were made empty via conflict resolution.  It also enhances
git-rebase to add a --keep-empty option which enables rebases to preserve empty
commits. 

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	
V3)
	* reversed the --ignore-if-empty-logic to by default only keep initially
	empty commits

	* replaced --ignore-if-empty with --keep-redundant-commits, to allow
	empty commits that are made empty via conflict resolution, in addition
	to commits that were created as empty

	* reworked is_original_commit_empty to be more efficient and portable

	* Misc sylistic and spelling cleanups

V4)
	* Reverted the cherry-pick advice changes in V3 based on in-thread
	discussion

	* Rewrote my changes to is_original_commit_empty and run_git_commit to
	not have to fork, making them more efficient.

v5)
	* Additional help text clean up
	* Additional error checking added to run_git_commit code
	* Whitespace cleanup
	* Removed needed cache_tree freeing
	* Test case cleanup
	* Fixed regression in t3404 and t3416 - this turned out to be 
        a problem with the note that git rebase -i adds at the bottom
	of the rebase text.  It was inadvertently indented and caused the
	test fake editor to misread the commit template.  The indentation 
	has been corrected, and these two tests, as well as all the other
	expected tests pass now

v6)
	* synced keeep-redundant-commits option and variable name
	* fixed up some comment terminology
	* minor newline cleanup
	* Removed some unneeded braces from test code
	* minor syntatic cleanup in rebase scripts

	* Refactored empty index checking to make run_git_commit more readable
	I was also going to change the logic so that it operated more like git
	cherry-pick did before the patchset, but Junio's comments made me think
	the new logic was preferable.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v6 1/4] git-cherry-pick: add allow-empty option
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-17 18:20   ` Neil Horman
  2012-04-17 18:20   ` [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-17 18:20 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operation.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..730237a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-17 18:20   ` [PATCH v6 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-17 18:20   ` Neil Horman
  2012-04-17 21:45     ` Clemens Buchacher
  2012-04-17 18:20   ` [PATCH v6 3/4] git-cherry-pick: Add test to validate new options Neil Horman
  2012-04-17 18:20   ` [PATCH v6 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-17 18:20 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

The git-cherry-pick --allow-empty command by default only preserves empty
commits that were originally empty, i.e only those commits for which
<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are
non-empty, but were made empty by the inclusion of a prior commit on the current
history are filtered out.  This option allows us to override that behavior and
include redundant commits as empty commits in the change history.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |   12 ++++-
 builtin/revert.c                  |    8 +++-
 sequencer.c                       |   97 ++++++++++++++++++++++++++++++++-----
 sequencer.h                       |    1 +
 4 files changed, 103 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 730237a..0c004e9 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -110,7 +110,17 @@ effect to your index in a row.
 	behavior, allowing empty commits to be preserved automatically
 	in a cherry-pick. Note that when "--ff" is in effect, empty
 	commits that meet the "fast-forward" requirement will be kept
-	even without this option.
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. the commit recorded the
+	same tree as its parent).  Commits which are made empty due to a
+	previous commit are ignored.  To force the inclusion of those commits
+	use `--keep-redundant-commits`.
+
+--keep-redundant-commits::
+	If a commit being cherry picked duplicates a commit already in the
+	current history, it will result in an empty changeset.  By default these
+	redundant commits are ignored.  This option overrides that behavior and
+	creates an empty commit object.  Implies `--allow-empty`.
 
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..f135502 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
+			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
+	/* keep_if_made_empty implies allow_empty */
+	if (opts->keep_redundant_commits)
+		opts->allow_empty = 1;
+
 	/* Set the subcommand */
 	if (remove_state)
 		opts->subcommand = REPLAY_REMOVE_STATE;
diff --git a/sequencer.c b/sequencer.c
index 71929ba..acc9c6d 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
 	return !clean;
 }
 
+static int is_index_unchanged()
+{
+	unsigned char head_sha1[20];
+	struct commit *head_commit;
+
+	if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+		return error(_("Could not resolve HEAD commit\n"));
+
+	head_commit = lookup_commit(head_sha1);
+	if (!head_commit || parse_commit(head_commit))
+		return error(_("could not parse commit %s\n"),
+			     sha1_to_hex(head_commit->object.sha1));
+
+	if (!active_cache_tree)
+		active_cache_tree = cache_tree();
+
+	if (!cache_tree_fully_valid(active_cache_tree))
+		if (cache_tree_update(active_cache_tree, active_cache,
+				  active_nr, 0))
+			return error(_("Unable to update cache tree\n"));
+
+	return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
+}
+
 /*
  * If we are cherry-pick, and if the merge did not result in
  * hand-editing, we will hit this commit and inherit the original
@@ -258,26 +283,67 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  * If we are revert, or if our cherry-pick results in a hand merge,
  * we had better say that the current user is responsible for that.
  */
-static int run_git_commit(const char *defmsg, struct replay_opts *opts)
+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)
 {
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+	struct argv_array array;
+	int rc;
+	int index_unchanged = is_index_unchanged();
+
+	/*
+	 * if index_unchanged is < 0, then we encountered an error
+	 * trying to parse HEAD or the active_cache_tree, so bail out
+	 */
+	if (index_unchanged < 0)
+		return index_unchanged;
+
+	if (!empty && !opts->keep_redundant_commits && index_unchanged)
+			/*
+			 * The head tree and the index match
+			 * meaning the commit is empty.  Since it wasn't created
+			 * empty (based on the previous test), we can conclude
+			 * the commit has been made redundant.  Since we don't
+			 * want to keep redundant commits, we can just return
+			 * here, skipping this commit
+			 */
+			return 0;
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
+
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
 
-	args[i] = NULL;
+static int is_original_commit_empty(struct commit *commit)
+{
+	const unsigned char *ptree_sha1;
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	if (parse_commit(commit))
+		return error(_("Could not parse commit %s\n"),
+			     sha1_to_hex(commit->object.sha1));
+	if (commit->parents) {
+		struct commit *parent = commit->parents->item;
+		if (parse_commit(parent))
+			return error(_("Could not parse parent commit %s\n"),
+				sha1_to_hex(parent->object.sha1));
+		ptree_sha1 = parent->tree->object.sha1;
+	} else {
+		ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+	}
+
+	return !hashcmp(ptree_sha1, commit->tree->object.sha1);
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +355,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +481,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_original_commit_empty(commit);
+	if (empty_commit < 0)
+		return empty_commit;
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -435,7 +506,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		rerere(opts->allow_rerere_auto);
 	} else {
 		if (!opts->no_commit)
-			res = run_git_commit(defmsg, opts);
+			res = run_git_commit(defmsg, opts, empty_commit);
 	}
 
 	free_message(&msg);
diff --git a/sequencer.h b/sequencer.h
index e2cd725..aa5f17c 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int keep_redundant_commits;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v6 3/4] git-cherry-pick: Add test to validate new options
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-17 18:20   ` [PATCH v6 1/4] git-cherry-pick: add allow-empty option Neil Horman
  2012-04-17 18:20   ` [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-17 18:20   ` Neil Horman
  2012-04-17 18:20   ` [PATCH v6 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-17 18:20 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

Since we've added the --allow-empty and --keep-redundant-commits
options to git cherry-pick we should also add a test to ensure that its working
properly.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-
 1 files changed, 24 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..d513127 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fourth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" &&
+	test_must_fail git cherry-pick empty-branch2
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master &&
+	git cherry-pick --allow-empty empty-branch2
+'
+
+test_expect_success 'cherry pick with --keep-redundant-commits' '
+	git checkout master &&
+	git cherry-pick --keep-redundant-commits HEAD^
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-17 18:20   ` [PATCH v6 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-17 18:20   ` Neil Horman
  2012-04-17 21:47     ` Clemens Buchacher
  2012-04-18 22:58     ` Junio C Hamano
  3 siblings, 2 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-17 18:20 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   33 ++++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..04d8941 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if test -n "$keep_empty"
+then
+	# we have to do this the hard way.  git format-patch completely squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..cef290b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,12 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	tree=$(git rev-parse "$1"^{tree})
+	ptree=$(git rev-parse "$1"^^{tree})
+	return $(test "$tree" = "$ptree")
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +197,19 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+
+	if is_empty_commit "$sha1"
+	then
+		empty_args="--allow-empty"
+	fi
+
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	then
+		comment_out="# pick"
+	else
+		comment_out="pick"
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +822,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s\n' "$comment_out $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +872,12 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	echo "# Note that empty commits are commented out" >> "$todo"
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-17 15:42           ` Junio C Hamano
@ 2012-04-17 21:37             ` Clemens Buchacher
  2012-04-18 10:41               ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-17 21:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Neil Horman, git, Jeff King, Phil Hord

On Tue, Apr 17, 2012 at 08:42:52AM -0700, Junio C Hamano wrote:
> Clemens Buchacher <drizzd@aon.at> writes:
> 
> > On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:
> > ...
> > Except that the outcome is not the same. With and without your changes,
> > git cherry-pick <empty-commit> fails. But with your changes, git
> > cherry-pick <commit-will-become-empty> will succeed and do nothing,
> > while before it would have failed exactly like git cherry-pick
> > <empty-commit>.
> >
> > So I am not arguing whether failing or skipping is the better default
> > behavior. But the legacy behavior is consistent between the empty-commit
> > and commit-will-become-empty cases.
> 
> Is that particular "consistency" a good one, though?  If you had an empty
> commit in the original range, it is a lot more likely that it was an error
> that you would want to know about.  You may be the kind of person who
> value an empty commit in your history, using it as some kind of a mark in
> the history, and in that case you would want to know that it is being
> discarded.  On the other hand, if a commit that did something in the
> original context turns out to be unnecessary in the replayed context, that
> is not something you would ever want to keep in the replayed context, and
> erroring out and forcing you to say "yeah, I admit I do not want it" would
> just be annoying.

Yeah, that makes sense.

> So "consistency" between the two would actually be a mistake that we may
> want to "break", I would think.

Agreed. But we should document the change in the commit message and
maybe add a comment, because it is really strange to read

 if (!empty && index_empty)
 	return "it's all good"

 if (empty)
 	return "oh noes!"

without an explanation as to why empty and index_empty are so different.
Neil, what do you think?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-17 10:56               ` Neil Horman
@ 2012-04-17 21:38                 ` Clemens Buchacher
  2012-04-18 10:48                   ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-17 21:38 UTC (permalink / raw)
  To: Neil Horman; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Tue, Apr 17, 2012 at 06:56:04AM -0400, Neil Horman wrote:
> On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:
> > 
> > It seems that I was implying a lot more than I realized. What I meant
> > was that master and empty-branch2 are equivalent for the purposes of
> > that test (empty-branch2^ also is a non-empty commit [*1*]), but while
> > master is a moving target, empty-branch2 is untouched. 
> > 
> for the purposes of the --keep-redundant-commits however, the target is
> irrelevant.  The only requirement is that we cherry-pick a commit that is
> guaranteed to become empty when applied.

That we agree on.

> We certainly could do that on empty branch2, but theres no advantage
> to doing so,

The advantage is that I do not have to read the other tests in order to
understand what this test does, because contrary to the master branch,
they do not modify empty-branch2.

> and given that every other test attempts to cherry-pick to master, I
> rather like the consistency.

We could also consistently not use the master branch.

> > However, I just notice that empty-branch2 is also the root commit, so
> > maybe this will not work after all. But that should be easy to fix.
>
> It is easy to fix, given your clarified description above, its just that IMO,
> its not broken.

Well, I don't mind too badly if this doesn't go may way. But I hope that
I managed at least to explain my point.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-17 18:20   ` [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-17 21:45     ` Clemens Buchacher
  2012-04-18 10:49       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-17 21:45 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Phil Hord, Junio C Hamano

On Tue, Apr 17, 2012 at 02:20:07PM -0400, Neil Horman wrote:
>
> +	if (!empty && !opts->keep_redundant_commits && index_unchanged)
> +			/*
> +			 * The head tree and the index match
> +			 * meaning the commit is empty.  Since it wasn't created
> +			 * empty (based on the previous test), we can conclude
> +			 * the commit has been made redundant.  Since we don't
> +			 * want to keep redundant commits, we can just return
> +			 * here, skipping this commit
> +			 */
> +			return 0;

You can remove one level of indentation (yay!).

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-17 18:20   ` [PATCH v6 4/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-04-17 21:47     ` Clemens Buchacher
  2012-04-18 10:50       ` Neil Horman
  2012-04-18 22:58     ` Junio C Hamano
  1 sibling, 1 reply; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-17 21:47 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Phil Hord, Junio C Hamano

On Tue, Apr 17, 2012 at 02:20:09PM -0400, Neil Horman wrote:
>
> @@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
>  	sed -n "s/^>//p" |
>  while read -r shortsha1 rest
>  do
> +
> +	if test -z "$keep_empty" && is_empty_commit $shortsha1
> +	then
> +		comment_out="# pick"
> +	else
> +		comment_out="pick"
> +	fi

You forgot to change this to comment_out="# " and comment_out="".

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-17 21:37             ` Clemens Buchacher
@ 2012-04-18 10:41               ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 10:41 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Tue, Apr 17, 2012 at 11:37:23PM +0200, Clemens Buchacher wrote:
> On Tue, Apr 17, 2012 at 08:42:52AM -0700, Junio C Hamano wrote:
> > Clemens Buchacher <drizzd@aon.at> writes:
> > 
> > > On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:
> > > ...
> > > Except that the outcome is not the same. With and without your changes,
> > > git cherry-pick <empty-commit> fails. But with your changes, git
> > > cherry-pick <commit-will-become-empty> will succeed and do nothing,
> > > while before it would have failed exactly like git cherry-pick
> > > <empty-commit>.
> > >
> > > So I am not arguing whether failing or skipping is the better default
> > > behavior. But the legacy behavior is consistent between the empty-commit
> > > and commit-will-become-empty cases.
> > 
> > Is that particular "consistency" a good one, though?  If you had an empty
> > commit in the original range, it is a lot more likely that it was an error
> > that you would want to know about.  You may be the kind of person who
> > value an empty commit in your history, using it as some kind of a mark in
> > the history, and in that case you would want to know that it is being
> > discarded.  On the other hand, if a commit that did something in the
> > original context turns out to be unnecessary in the replayed context, that
> > is not something you would ever want to keep in the replayed context, and
> > erroring out and forcing you to say "yeah, I admit I do not want it" would
> > just be annoying.
> 
> Yeah, that makes sense.
> 
> > So "consistency" between the two would actually be a mistake that we may
> > want to "break", I would think.
> 
> Agreed. But we should document the change in the commit message and
> maybe add a comment, because it is really strange to read
> 
>  if (!empty && index_empty)
>  	return "it's all good"
> 
>  if (empty)
>  	return "oh noes!"
> 
> without an explanation as to why empty and index_empty are so different.
> Neil, what do you think?
> 
Well, I've got the comment in the code indicating what were doing, but sure,
I can be more vebose in the commit message about whats going on.  I can probably
rename the empty variable to indicate its meaning a bit more clearly and make
that code more readable.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-17 21:38                 ` Clemens Buchacher
@ 2012-04-18 10:48                   ` Neil Horman
  2012-04-18 18:34                     ` Clemens Buchacher
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-18 10:48 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Tue, Apr 17, 2012 at 11:38:52PM +0200, Clemens Buchacher wrote:
> On Tue, Apr 17, 2012 at 06:56:04AM -0400, Neil Horman wrote:
> > On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:
> > > 
> > > It seems that I was implying a lot more than I realized. What I meant
> > > was that master and empty-branch2 are equivalent for the purposes of
> > > that test (empty-branch2^ also is a non-empty commit [*1*]), but while
> > > master is a moving target, empty-branch2 is untouched. 
> > > 
> > for the purposes of the --keep-redundant-commits however, the target is
> > irrelevant.  The only requirement is that we cherry-pick a commit that is
> > guaranteed to become empty when applied.
> 
> That we agree on.
> 
> > We certainly could do that on empty branch2, but theres no advantage
> > to doing so,
> 
> The advantage is that I do not have to read the other tests in order to
> understand what this test does, because contrary to the master branch,
> they do not modify empty-branch2.
> 
But empty-branch2, as the name implies, doesn't have a non-empty commit on it
yet, and so theres nothing to cherry-pick on that branch that would 'become'
empty.  We could fix that of course, but I'd worry that that would look odd
against the other tests.

> > and given that every other test attempts to cherry-pick to master, I
> > rather like the consistency.
> 
> We could also consistently not use the master branch.
> 
Yes, This would be my perferred solution I think.  That way we clarify the test
to your satisfaction and keep the consistency of the test methodology.

> > > However, I just notice that empty-branch2 is also the root commit, so
> > > maybe this will not work after all. But that should be easy to fix.
> >
> > It is easy to fix, given your clarified description above, its just that IMO,
> > its not broken.
> 
> Well, I don't mind too badly if this doesn't go may way. But I hope that
> I managed at least to explain my point.
> 
Yes, absolutely.  How about this:  Given that we agree on our ability to
consistently not use master above, what if we table this discussion for now,
leave the tests as they are, and fix them all up in a separate patch set?  I
don't mind making the change your requesting at all, but I'd rather do it as
part of modifying all the tests not to use master, and doing it in a separate
changeset, so we don't convolute what this series is doing.  Does that sound
reasonable?
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-17 21:45     ` Clemens Buchacher
@ 2012-04-18 10:49       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 10:49 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Phil Hord, Junio C Hamano

On Tue, Apr 17, 2012 at 11:45:22PM +0200, Clemens Buchacher wrote:
> On Tue, Apr 17, 2012 at 02:20:07PM -0400, Neil Horman wrote:
> >
> > +	if (!empty && !opts->keep_redundant_commits && index_unchanged)
> > +			/*
> > +			 * The head tree and the index match
> > +			 * meaning the commit is empty.  Since it wasn't created
> > +			 * empty (based on the previous test), we can conclude
> > +			 * the commit has been made redundant.  Since we don't
> > +			 * want to keep redundant commits, we can just return
> > +			 * here, skipping this commit
> > +			 */
> > +			return 0;
> 
> You can remove one level of indentation (yay!).
>
Doh!  Thanks.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-17 21:47     ` Clemens Buchacher
@ 2012-04-18 10:50       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 10:50 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git, Phil Hord, Junio C Hamano

On Tue, Apr 17, 2012 at 11:47:01PM +0200, Clemens Buchacher wrote:
> On Tue, Apr 17, 2012 at 02:20:09PM -0400, Neil Horman wrote:
> >
> > @@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
> >  	sed -n "s/^>//p" |
> >  while read -r shortsha1 rest
> >  do
> > +
> > +	if test -z "$keep_empty" && is_empty_commit $shortsha1
> > +	then
> > +		comment_out="# pick"
> > +	else
> > +		comment_out="pick"
> > +	fi
> 
> You forgot to change this to comment_out="# " and comment_out="".
> 

Thanks, I'll fix that up when I modify the keep-redundant-commits commit message
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options
  2012-04-18 10:48                   ` Neil Horman
@ 2012-04-18 18:34                     ` Clemens Buchacher
  0 siblings, 0 replies; 121+ messages in thread
From: Clemens Buchacher @ 2012-04-18 18:34 UTC (permalink / raw)
  To: Neil Horman; +Cc: Junio C Hamano, git, Jeff King, Phil Hord

On Wed, Apr 18, 2012 at 06:48:59AM -0400, Neil Horman wrote:
>
> Given that we agree on our ability to consistently not use master
> above, what if we table this discussion for now, leave the tests as
> they are, and fix them all up in a separate patch set? Does that sound
> reasonable?

Absolutely.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (8 preceding siblings ...)
  2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-18 19:17 ` Neil Horman
  2012-04-18 19:17   ` [PATCH v7 1/4] git-cherry-pick: add allow-empty option Neil Horman
                     ` (3 more replies)
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  10 siblings, 4 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 19:17 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman


git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --keep-redundant-commits, which allows the user to also keep
commits that were made empty via conflict resolution.  It also enhances
git-rebase to add a --keep-empty option which enables rebases to preserve empty
commits. 

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	
V3)
	* reversed the --ignore-if-empty-logic to by default only keep initially
	empty commits

	* replaced --ignore-if-empty with --keep-redundant-commits, to allow
	empty commits that are made empty via conflict resolution, in addition
	to commits that were created as empty

	* reworked is_original_commit_empty to be more efficient and portable

	* Misc sylistic and spelling cleanups

V4)
	* Reverted the cherry-pick advice changes in V3 based on in-thread
	discussion

	* Rewrote my changes to is_original_commit_empty and run_git_commit to
	not have to fork, making them more efficient.

v5)
	* Additional help text clean up
	* Additional error checking added to run_git_commit code
	* Whitespace cleanup
	* Removed needed cache_tree freeing
	* Test case cleanup
	* Fixed regression in t3404 and t3416 - this turned out to be 
        a problem with the note that git rebase -i adds at the bottom
	of the rebase text.  It was inadvertently indented and caused the
	test fake editor to misread the commit template.  The indentation 
	has been corrected, and these two tests, as well as all the other
	expected tests pass now

v6)
	* synced keeep-redundant-commits option and variable name
	* fixed up some comment terminology
	* minor newline cleanup
	* Removed some unneeded braces from test code
	* minor syntatic cleanup in rebase scripts

	* Refactored empty index checking to make run_git_commit more readable
	I was also going to change the logic so that it operated more like git
	cherry-pick did before the patchset, but Junio's comments made me think
	the new logic was preferable.

v7)
	* Fixed up forgotten comment_out changes requested in
	git-rebase--interactive

	* Made changelog comment for keep-redundant-commits patch more verbose
	so that it was clear that default behavior was changing

	* further refinement of detection of redundant commits, making
	do_pick_commit and run_git_commit more readable

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v7 1/4] git-cherry-pick: add allow-empty option
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-18 19:17   ` Neil Horman
  2012-04-18 19:17   ` [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 19:17 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operation.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..730237a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-18 19:17   ` [PATCH v7 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-18 19:17   ` Neil Horman
  2012-04-18 22:59     ` Junio C Hamano
  2012-04-18 19:17   ` [PATCH v7 3/4] git-cherry-pick: Add test to validate new options Neil Horman
  2012-04-18 19:18   ` [PATCH v7 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-18 19:17 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

The git-cherry-pick --allow-empty command by default only preserves empty
commits that were originally empty, i.e only those commits for which
<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are
non-empty, but were made empty by the inclusion of a prior commit on the current
history are filtered out.  This option allows us to override that behavior and
include redundant commits as empty commits in the change history.

Note that this patch changes the default behavior of git cherry-pick slightly.
Prior to this patch all commits in a cherry-pick sequence were applied and git
commit was run.  The implication here was that, if a commit was redundant, and
the commit did not trigger the fast forward logic, the git commit operation, and
therefore the git cherry-pick operation would fail, displaying the cherry pick
advice (i.e. run git commit --allow-empty).  With this patch however, such
redundant commits are automatically skipped without stopping, unless
--keep-redundant-commits is specified, in which case, they are automatically
applied as empty commits.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |   12 ++++-
 builtin/revert.c                  |    8 +++-
 sequencer.c                       |   94 ++++++++++++++++++++++++++++++++----
 sequencer.h                       |    1 +
 4 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 730237a..0c004e9 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -110,7 +110,17 @@ effect to your index in a row.
 	behavior, allowing empty commits to be preserved automatically
 	in a cherry-pick. Note that when "--ff" is in effect, empty
 	commits that meet the "fast-forward" requirement will be kept
-	even without this option.
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. the commit recorded the
+	same tree as its parent).  Commits which are made empty due to a
+	previous commit are ignored.  To force the inclusion of those commits
+	use `--keep-redundant-commits`.
+
+--keep-redundant-commits::
+	If a commit being cherry picked duplicates a commit already in the
+	current history, it will result in an empty changeset.  By default these
+	redundant commits are ignored.  This option overrides that behavior and
+	creates an empty commit object.  Implies `--allow-empty`.
 
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..f135502 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
+			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
+	/* keep_if_made_empty implies allow_empty */
+	if (opts->keep_redundant_commits)
+		opts->allow_empty = 1;
+
 	/* Set the subcommand */
 	if (remove_state)
 		opts->subcommand = REPLAY_REMOVE_STATE;
diff --git a/sequencer.c b/sequencer.c
index 71929ba..e33dfbb 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
 	return !clean;
 }
 
+static int is_index_unchanged()
+{
+	unsigned char head_sha1[20];
+	struct commit *head_commit;
+
+	if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+		return error(_("Could not resolve HEAD commit\n"));
+
+	head_commit = lookup_commit(head_sha1);
+	if (!head_commit || parse_commit(head_commit))
+		return error(_("could not parse commit %s\n"),
+			     sha1_to_hex(head_commit->object.sha1));
+
+	if (!active_cache_tree)
+		active_cache_tree = cache_tree();
+
+	if (!cache_tree_fully_valid(active_cache_tree))
+		if (cache_tree_update(active_cache_tree, active_cache,
+				  active_nr, 0))
+			return error(_("Unable to update cache tree\n"));
+
+	return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
+}
+
 /*
  * If we are cherry-pick, and if the merge did not result in
  * hand-editing, we will hit this commit and inherit the original
@@ -260,24 +285,46 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+	struct argv_array array;
+	int rc;
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
 
-	args[i] = NULL;
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
+
+static int is_original_commit_empty(struct commit *commit)
+{
+	const unsigned char *ptree_sha1;
+
+	if (parse_commit(commit))
+		return error(_("Could not parse commit %s\n"),
+			     sha1_to_hex(commit->object.sha1));
+	if (commit->parents) {
+		struct commit *parent = commit->parents->item;
+		if (parse_commit(parent))
+			return error(_("Could not parse parent commit %s\n"),
+				sha1_to_hex(parent->object.sha1));
+		ptree_sha1 = parent->tree->object.sha1;
+	} else {
+		ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+	}
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	return !hashcmp(ptree_sha1, commit->tree->object.sha1);
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +336,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
+	int index_unchanged;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +463,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_original_commit_empty(commit);
+	if (empty_commit < 0)
+		return empty_commit;
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -434,6 +487,25 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		print_advice(res == 1, opts);
 		rerere(opts->allow_rerere_auto);
 	} else {
+		index_unchanged = is_index_unchanged();
+		/*
+		 * If index_unchanged is less than 0, that indicates we either
+		 * couldn't parse HEAD or the index, so error out here.
+		 */
+		if (index_unchanged < 0)
+			return index_unchanged;
+
+		if (!empty_commit && !opts->keep_redundant_commits && index_unchanged)
+			/*
+			 * The head tree and the index match
+			 * meaning the commit is empty.  Since it wasn't created
+			 * empty (based on the previous test), we can conclude
+			 * the commit has been made redundant.  Since we don't
+			 * want to keep redundant commits, we can just return
+			 * here, skipping this commit
+			 */
+			return 0;
+
 		if (!opts->no_commit)
 			res = run_git_commit(defmsg, opts);
 	}
diff --git a/sequencer.h b/sequencer.h
index e2cd725..aa5f17c 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int keep_redundant_commits;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v7 3/4] git-cherry-pick: Add test to validate new options
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-18 19:17   ` [PATCH v7 1/4] git-cherry-pick: add allow-empty option Neil Horman
  2012-04-18 19:17   ` [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-18 19:17   ` Neil Horman
  2012-04-18 19:18   ` [PATCH v7 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-18 19:17 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

Since we've added the --allow-empty and --keep-redundant-commits
options to git cherry-pick we should also add a test to ensure that its working
properly.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-
 1 files changed, 24 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..d513127 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fourth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" &&
+	test_must_fail git cherry-pick empty-branch2
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master &&
+	git cherry-pick --allow-empty empty-branch2
+'
+
+test_expect_success 'cherry pick with --keep-redundant-commits' '
+	git checkout master &&
+	git cherry-pick --keep-redundant-commits HEAD^
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-18 19:17   ` [PATCH v7 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-18 19:18   ` Neil Horman
  2012-04-19 10:02     ` Zbigniew Jędrzejewski-Szmek
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-18 19:18 UTC (permalink / raw)
  To: git; +Cc: Clemens Buchacher, Phil Hord, Junio C Hamano, Neil Horman

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   33 ++++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..04d8941 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if test -n "$keep_empty"
+then
+	# we have to do this the hard way.  git format-patch completely squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..b7abe1e 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,12 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	tree=$(git rev-parse "$1"^{tree})
+	ptree=$(git rev-parse "$1"^^{tree})
+	return $(test "$tree" = "$ptree")
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +197,19 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+
+	if is_empty_commit "$sha1"
+	then
+		empty_args="--allow-empty"
+	fi
+
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	then
+		comment_out="#"
+	else
+		comment_out=""
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +822,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +872,12 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	echo "# Note that empty commits are commented out" >> "$todo"
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-17 18:20   ` [PATCH v6 4/4] git-rebase: add keep_empty flag Neil Horman
  2012-04-17 21:47     ` Clemens Buchacher
@ 2012-04-18 22:58     ` Junio C Hamano
  2012-04-19 13:08       ` Neil Horman
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-18 22:58 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Clemens Buchacher, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> Add a command line switch to git-rebase to allow a user the ability to specify
> that they want to keep any commits in a series that are empty.
>
> When git-rebase's type is am, then this option will automatically keep any
> commit that has a tree object identical to its parent.
>
> This patch changes the default behavior of interactive rebases as well.  With
> this patch, git-rebase -i will produce a revision set passed to
> git-revision-editor, in which empty commits are commented out.  Empty commits
> may be kept manually by uncommenting them.  If the new --keep-empty option is
> used in an interactive rebase the empty commits will automatically all be
> uncommented in the editor.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> ---

The earlier one in the series seem to be getting solid enough.  Nice.

> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> index 5812222..cef290b 100644
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -167,6 +167,12 @@ has_action () {
>  	sane_grep '^[^#]' "$1" >/dev/null
>  }
>  
> +is_empty_commit() {
> +	tree=$(git rev-parse "$1"^{tree})
> +	ptree=$(git rev-parse "$1"^^{tree})
> +	return $(test "$tree" = "$ptree")
> +}

Could "$1" ever be a root commit without a parent?

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-18 19:17   ` [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-18 22:59     ` Junio C Hamano
  0 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-04-18 22:59 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Clemens Buchacher, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> diff --git a/sequencer.c b/sequencer.c
> index 71929ba..e33dfbb 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -13,6 +13,7 @@
>  #include "rerere.h"
>  #include "merge-recursive.h"
>  #include "refs.h"
> +#include "argv-array.h"
>  
>  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
>  
> @@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
>  	return !clean;
>  }
>  
> +static int is_index_unchanged()
> +{

Hmm... I am reasonably sure I fixed this when I queued the previous one to
'pu'.

	static int is_index_unchanged(void)
        {

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-18 19:18   ` [PATCH v7 4/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-04-19 10:02     ` Zbigniew Jędrzejewski-Szmek
  2012-04-19 11:49       ` Thomas Rast
  0 siblings, 1 reply; 121+ messages in thread
From: Zbigniew Jędrzejewski-Szmek @ 2012-04-19 10:02 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Clemens Buchacher, Phil Hord, Junio C Hamano

On 04/18/2012 09:18 PM, Neil Horman wrote:
> Add a command line switch to git-rebase to allow a user the ability to specify
> that they want to keep any commits in a series that are empty.
>
> When git-rebase's type is am, then this option will automatically keep any
> commit that has a tree object identical to its parent.
>
> This patch changes the default behavior of interactive rebases as well.  With
> this patch, git-rebase -i will produce a revision set passed to
> git-revision-editor, in which empty commits are commented out.  Empty commits
> may be kept manually by uncommenting them.  If the new --keep-empty option is
> used in an interactive rebase the empty commits will automatically all be
> uncommented in the editor.
>
> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>

Hi,
this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu 
and this v7).

E.g. ./t3404-rebase-interactive.sh:

ok 1 - setup
not ok - 2 rebase -i with the exec command
not ok - 3 rebase -i with the exec command runs from tree root
not ok - 4 rebase -i with the exec command checks tree cleanness
not ok - 5 no changes are a nop
not ok - 6 test the [branch] option
not ok - 7 test --onto <branch>
not ok - 8 rebase on top of a non-conflicting commit
not ok - 9 reflog for the branch shows state before rebase
not ok - 10 exchange two commits
not ok - 11 stop on conflicting pick
not ok - 12 abort
not ok - 13 abort with error when new base cannot be checked out
not ok - 14 retain authorship
not ok - 15 squash
not ok - 16 retain authorship when squashing
not ok - 17 -p handles "no changes" gracefully
not ok 18 - exchange two commits with -p # TODO known breakage
not ok - 19 preserve merges with -p
not ok - 20 edit ancestor with -p
not ok - 21 --continue tries to commit
not ok - 22 verbose flag is heeded, even after --continue
not ok - 23 multi-squash only fires up editor once
not ok - 24 multi-fixup does not fire up editor
not ok - 25 commit message used after conflict
not ok - 26 commit message retained after conflict
not ok - 27 squash and fixup generate correct log messages
not ok - 28 squash ignores comments
not ok - 29 squash ignores blank lines
not ok - 30 squash works as expected
not ok - 31 interrupted squash works as expected
not ok - 32 interrupted squash works as expected (case 2)
not ok - 33 ignore patch if in upstream
not ok - 34 --continue tries to commit, even for "edit"
not ok - 35 aborted --continue does not squash commits after "edit"
not ok - 36 auto-amend only edited commits after "edit"
not ok - 37 clean error after failed "exec"
not ok - 38 rebase a detached HEAD
not ok - 39 rebase a commit violating pre-commit
not ok - 40 rebase with a file named HEAD in worktree
ok 41 - do "noop" when there is nothing to cherry-pick
ok 42 - submodule rebase setup
not ok - 43 submodule rebase -i
ok 44 - submodule conflict setup
not ok - 45 rebase -i continue with only submodule staged
not ok - 46 rebase -i continue with unstaged submodule
not ok - 47 avoid unnecessary reset
not ok - 48 reword
ok 49 - rebase -i can copy notes
not ok - 50 rebase -i can copy notes over a fixup
not ok - 51 rebase while detaching HEAD
not ok - 52 always cherry-pick with --no-ff
ok 53 - set up commits with funny messages
not ok - 54 rebase-i history with funny messages

The problem seems to be that git-rebase says "Nothing to do" and returns 1.

-
Zbyszek

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 10:02     ` Zbigniew Jędrzejewski-Szmek
@ 2012-04-19 11:49       ` Thomas Rast
  2012-04-19 12:19         ` Zbigniew Jędrzejewski-Szmek
  2012-04-19 18:59         ` Junio C Hamano
  0 siblings, 2 replies; 121+ messages in thread
From: Thomas Rast @ 2012-04-19 11:49 UTC (permalink / raw)
  To: Zbigniew Jędrzejewski-Szmek
  Cc: Neil Horman, git, Clemens Buchacher, Phil Hord, Junio C Hamano

Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> writes:

> On 04/18/2012 09:18 PM, Neil Horman wrote:
>> Add a command line switch to git-rebase to allow a user the ability to specify
>> that they want to keep any commits in a series that are empty.
>>
>> When git-rebase's type is am, then this option will automatically keep any
>> commit that has a tree object identical to its parent.
>>
>> This patch changes the default behavior of interactive rebases as well.  With
>> this patch, git-rebase -i will produce a revision set passed to
>> git-revision-editor, in which empty commits are commented out.  Empty commits
>> may be kept manually by uncommenting them.  If the new --keep-empty option is
>> used in an interactive rebase the empty commits will automatically all be
>> uncommented in the editor.
>>
>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
>
> Hi,
> this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu
> and this v7).

Probably because of the strange return in this function:

>> is_empty_commit() {
>> 	tree=$(git rev-parse "$1"^{tree})
>> 	ptree=$(git rev-parse "$1"^^{tree})
>> 	return $(test "$tree" = "$ptree")
>> }

bash seems to pass on the exit status from $() to the caller, while dash
doesn't.  It seems bash is actually more correct here, because POSIX
says about 'return [n]': 

    EXIT STATUS
       The value of the special parameter '?' shall be set to n, an
       unsigned decimal integer, or to the exit status of the last
       command executed if n is not specified.

Either way, it should simply be spelled as

is_empty_commit() {
	tree=$(git rev-parse "$1"^{tree})
	ptree=$(git rev-parse "$1"^^{tree})
	test "$tree" = "$ptree"
}

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 11:49       ` Thomas Rast
@ 2012-04-19 12:19         ` Zbigniew Jędrzejewski-Szmek
  2012-04-19 13:12           ` Neil Horman
  2012-04-19 18:59         ` Junio C Hamano
  1 sibling, 1 reply; 121+ messages in thread
From: Zbigniew Jędrzejewski-Szmek @ 2012-04-19 12:19 UTC (permalink / raw)
  To: Thomas Rast
  Cc: Neil Horman, git, Clemens Buchacher, Phil Hord, Junio C Hamano

On 04/19/2012 01:49 PM, Thomas Rast wrote:
> Zbigniew Jędrzejewski-Szmek<zbyszek@in.waw.pl>  writes:
>
>> On 04/18/2012 09:18 PM, Neil Horman wrote:
>>> Add a command line switch to git-rebase to allow a user the ability to specify
>>> that they want to keep any commits in a series that are empty.
>>>
>>> When git-rebase's type is am, then this option will automatically keep any
>>> commit that has a tree object identical to its parent.
>>>
>>> This patch changes the default behavior of interactive rebases as well.  With
>>> this patch, git-rebase -i will produce a revision set passed to
>>> git-revision-editor, in which empty commits are commented out.  Empty commits
>>> may be kept manually by uncommenting them.  If the new --keep-empty option is
>>> used in an interactive rebase the empty commits will automatically all be
>>> uncommented in the editor.
>>>
>>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
>>
>> Hi,
>> this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu
>> and this v7).
>
> Probably because of the strange return in this function:
>
>>> is_empty_commit() {
>>> 	tree=$(git rev-parse "$1"^{tree})
>>> 	ptree=$(git rev-parse "$1"^^{tree})
>>> 	return $(test "$tree" = "$ptree")
>>> }
>
> bash seems to pass on the exit status from $() to the caller, while dash
> doesn't.  It seems bash is actually more correct here, because POSIX
> says about 'return [n]':
>
>      EXIT STATUS
>         The value of the special parameter '?' shall be set to n, an
>         unsigned decimal integer, or to the exit status of the last
>         command executed if n is not specified.
>
> Either way, it should simply be spelled as
>
> is_empty_commit() {
> 	tree=$(git rev-parse "$1"^{tree})
> 	ptree=$(git rev-parse "$1"^^{tree})
> 	test "$tree" = "$ptree"
> }
Yes, this change fixes the problem (all tests pass).

Thanks!

Zbyszek

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-18 22:58     ` Junio C Hamano
@ 2012-04-19 13:08       ` Neil Horman
  2012-04-19 17:53         ` Junio C Hamano
  0 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-19 13:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Clemens Buchacher, Phil Hord

On Wed, Apr 18, 2012 at 03:58:53PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Add a command line switch to git-rebase to allow a user the ability to specify
> > that they want to keep any commits in a series that are empty.
> >
> > When git-rebase's type is am, then this option will automatically keep any
> > commit that has a tree object identical to its parent.
> >
> > This patch changes the default behavior of interactive rebases as well.  With
> > this patch, git-rebase -i will produce a revision set passed to
> > git-revision-editor, in which empty commits are commented out.  Empty commits
> > may be kept manually by uncommenting them.  If the new --keep-empty option is
> > used in an interactive rebase the empty commits will automatically all be
> > uncommented in the editor.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > ---
> 
> The earlier one in the series seem to be getting solid enough.  Nice.
> 
Thanks!

> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> > index 5812222..cef290b 100644
> > --- a/git-rebase--interactive.sh
> > +++ b/git-rebase--interactive.sh
> > @@ -167,6 +167,12 @@ has_action () {
> >  	sane_grep '^[^#]' "$1" >/dev/null
> >  }
> >  
> > +is_empty_commit() {
> > +	tree=$(git rev-parse "$1"^{tree})
> > +	ptree=$(git rev-parse "$1"^^{tree})
> > +	return $(test "$tree" = "$ptree")
> > +}
> 
> Could "$1" ever be a root commit without a parent?
> 
Strictly speaking, yes.  If that happens, however, the output of git rev-parse
will be an error message that includes the passed in revision.  since tree
passes '^' while ptree passes '^^' the two revisions will always differ, and as
a result is_empty_commit will return false, and the existing behavior of git
will be followed.  So, yes, rebasing an empty tree would cause odd output in the
rev-parse calls in is_empty_comit, but the behavior of git overall would be
unaffected (which is not to say that rebasing an empty tree won't show odd
corner-case behavior, only that this changeset won't introduce any new odd
corner case behavior :) ).

If you like we can add additional checking to ensure that we explicitly catch
rev-parse errors and abort the rebase imediately, but I don't think thats
strictly necessecary.  Would you prefer that?

Regards
Neil
 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 12:19         ` Zbigniew Jędrzejewski-Szmek
@ 2012-04-19 13:12           ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-19 13:12 UTC (permalink / raw)
  To: Zbigniew Jędrzejewski-Szmek
  Cc: Thomas Rast, git, Clemens Buchacher, Phil Hord, Junio C Hamano

On Thu, Apr 19, 2012 at 02:19:22PM +0200, Zbigniew Jędrzejewski-Szmek wrote:
> On 04/19/2012 01:49 PM, Thomas Rast wrote:
> >Zbigniew Jędrzejewski-Szmek<zbyszek@in.waw.pl>  writes:
> >
> >>On 04/18/2012 09:18 PM, Neil Horman wrote:
> >>>Add a command line switch to git-rebase to allow a user the ability to specify
> >>>that they want to keep any commits in a series that are empty.
> >>>
> >>>When git-rebase's type is am, then this option will automatically keep any
> >>>commit that has a tree object identical to its parent.
> >>>
> >>>This patch changes the default behavior of interactive rebases as well.  With
> >>>this patch, git-rebase -i will produce a revision set passed to
> >>>git-revision-editor, in which empty commits are commented out.  Empty commits
> >>>may be kept manually by uncommenting them.  If the new --keep-empty option is
> >>>used in an interactive rebase the empty commits will automatically all be
> >>>uncommented in the editor.
> >>>
> >>>Signed-off-by: Neil Horman<nhorman@tuxdriver.com>
> >>
> >>Hi,
> >>this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu
> >>and this v7).
> >
> >Probably because of the strange return in this function:
> >
> >>>is_empty_commit() {
> >>>	tree=$(git rev-parse "$1"^{tree})
> >>>	ptree=$(git rev-parse "$1"^^{tree})
> >>>	return $(test "$tree" = "$ptree")
> >>>}
> >
> >bash seems to pass on the exit status from $() to the caller, while dash
> >doesn't.  It seems bash is actually more correct here, because POSIX
> >says about 'return [n]':
> >
> >     EXIT STATUS
> >        The value of the special parameter '?' shall be set to n, an
> >        unsigned decimal integer, or to the exit status of the last
> >        command executed if n is not specified.
> >
> >Either way, it should simply be spelled as
> >
> >is_empty_commit() {
> >	tree=$(git rev-parse "$1"^{tree})
> >	ptree=$(git rev-parse "$1"^^{tree})
> >	test "$tree" = "$ptree"
> >}
> Yes, this change fixes the problem (all tests pass).
> 
> Thanks!
> 
> Zbyszek
> 
Ok, I'll update it.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v6 4/4] git-rebase: add keep_empty flag
  2012-04-19 13:08       ` Neil Horman
@ 2012-04-19 17:53         ` Junio C Hamano
  0 siblings, 0 replies; 121+ messages in thread
From: Junio C Hamano @ 2012-04-19 17:53 UTC (permalink / raw)
  To: Neil Horman; +Cc: git, Clemens Buchacher, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

>> > +is_empty_commit() {
>> > +	tree=$(git rev-parse "$1"^{tree})
>> > +	ptree=$(git rev-parse "$1"^^{tree})
>> > +	return $(test "$tree" = "$ptree")
>> > +}
>> 
>> Could "$1" ever be a root commit without a parent?
>> 
> Strictly speaking, yes.  If that happens, however, the output of git rev-parse

You do not have to speak strictly to see that bug that surfaces internal
error message leaking to the end user.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 11:49       ` Thomas Rast
  2012-04-19 12:19         ` Zbigniew Jędrzejewski-Szmek
@ 2012-04-19 18:59         ` Junio C Hamano
  2012-04-19 19:05           ` Junio C Hamano
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-19 18:59 UTC (permalink / raw)
  To: Thomas Rast
  Cc: Zbigniew Jędrzejewski-Szmek, Neil Horman, git,
	Clemens Buchacher, Phil Hord, Junio C Hamano

Thomas Rast <trast@student.ethz.ch> writes:

> Either way, it should simply be spelled as
>
> is_empty_commit() {
> 	tree=$(git rev-parse "$1"^{tree})
> 	ptree=$(git rev-parse "$1"^^{tree})
> 	test "$tree" = "$ptree"
> }

Thanks; will squash in something like this:

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 82042b1..8fe304f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -168,9 +168,10 @@ has_action () {
 }
 
 is_empty_commit() {
-	tree=$(git rev-parse "$1"^{tree})
-	ptree=$(git rev-parse "$1"^^{tree})
-	return $(test "$tree" = "$ptree")
+	tree=$(git rev-parse "$1"^{tree} 2>/dev/null) &&
+	ptree=$(git rev-parse "$1"^^{tree} 2>/dev/null) ||
+		die "$1: not a commit that can be picked"
+	test "$tree" = "$ptree"
 }
 
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 18:59         ` Junio C Hamano
@ 2012-04-19 19:05           ` Junio C Hamano
  2012-04-20 10:35             ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-19 19:05 UTC (permalink / raw)
  To: Thomas Rast
  Cc: Zbigniew Jędrzejewski-Szmek, Neil Horman, git,
	Clemens Buchacher, Phil Hord, Junio C Hamano

Junio C Hamano <jch@google.com> writes:

> Thomas Rast <trast@student.ethz.ch> writes:
>
>> Either way, it should simply be spelled as
>>
>> is_empty_commit() {
>> 	tree=$(git rev-parse "$1"^{tree})
>> 	ptree=$(git rev-parse "$1"^^{tree})
>> 	test "$tree" = "$ptree"
>> }
>
> Thanks; will squash in something like this:
> ...

Ehh, not like that.  But something like this, as we need to be able to
pick "root" (t3412 insists on it).

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 82042b1..de71543 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -168,9 +168,11 @@ has_action () {
 }
 
 is_empty_commit() {
-	tree=$(git rev-parse "$1"^{tree})
-	ptree=$(git rev-parse "$1"^^{tree})
-	return $(test "$tree" = "$ptree")
+	tree=$(git rev-parse "$1"^{tree} 2>/dev/null) ||
+		die "$1: not a commit that can be picked"
+	ptree=$(git rev-parse "$1"^^{tree} 2>/dev/null) ||
+		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+	test "$tree" = "$ptree"
 }
 
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v7 4/4] git-rebase: add keep_empty flag
  2012-04-19 19:05           ` Junio C Hamano
@ 2012-04-20 10:35             ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 10:35 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Thomas Rast, Zbigniew Jędrzejewski-Szmek, git,
	Clemens Buchacher, Phil Hord, Junio C Hamano

On Thu, Apr 19, 2012 at 12:05:56PM -0700, Junio C Hamano wrote:
> Junio C Hamano <jch@google.com> writes:
> 
> > Thomas Rast <trast@student.ethz.ch> writes:
> >
> >> Either way, it should simply be spelled as
> >>
> >> is_empty_commit() {
> >> 	tree=$(git rev-parse "$1"^{tree})
> >> 	ptree=$(git rev-parse "$1"^^{tree})
> >> 	test "$tree" = "$ptree"
> >> }
> >
> > Thanks; will squash in something like this:
> > ...
> 
> Ehh, not like that.  But something like this, as we need to be able to
> pick "root" (t3412 insists on it).
> 
> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> index 82042b1..de71543 100644
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -168,9 +168,11 @@ has_action () {
>  }
>  
>  is_empty_commit() {
> -	tree=$(git rev-parse "$1"^{tree})
> -	ptree=$(git rev-parse "$1"^^{tree})
> -	return $(test "$tree" = "$ptree")
> +	tree=$(git rev-parse "$1"^{tree} 2>/dev/null) ||
> +		die "$1: not a commit that can be picked"
> +	ptree=$(git rev-parse "$1"^^{tree} 2>/dev/null) ||
> +		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
> +	test "$tree" = "$ptree"
>  }
>  
>  # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
> 

What about this?
is_empty_commit() {
        tree=$(git rev-parse -q --verify "$1"^{tree})
        ptree=$(git rev-parse -q --verify "$1"^^{tree})

        # Note that if either rev-parse commands fail, the output 
        # of that command will be an empty string.  If that happens
        # We should just return 0, to indicate the commit is non-empty
        # and let the rest of the git rebase logic handle it.
        if test  -z "$tree"  -o  -z "$ptree"
        then
                return 0
        fi

        return test "$tree" = "$ptree"
}

^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits
  2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                   ` (9 preceding siblings ...)
  2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-20 14:36 ` Neil Horman
  2012-04-20 14:36   ` [PATCH v8 1/4] git-cherry-pick: add allow-empty option Neil Horman
                     ` (3 more replies)
  10 siblings, 4 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 14:36 UTC (permalink / raw)
  To: git
  Cc: Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord,
	Junio C Hamano, Neil Horman

git's ability to handle empty commits is somewhat lacking, especially when
preforming a rebase.  Nominally empty commits are undesireable entries, the 
result of commits that are made empty by prior commits covering the same changs.
But occasionally, empty commits are useful to developers (e.g. inserting notes 
into the development history without changing any code along the way).  In these
cases its desireable to easily preserve empty commits during operations like 
rebases.

This patch series enhances git to do just that.  It adds two options to the 
git-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve
an empty commit, even if the fast forward logic isn't applicable during the 
operation, and --keep-redundant-commits, which allows the user to also keep
commits that were made empty via conflict resolution.  It also enhances
git-rebase to add a --keep-empty option which enables rebases to preserve empty
commits. 

I've tested these operations out myself here and they work well for me

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

---
Change notes:

Based on version 1 feedback from this list, the following changes have been made

V2)
	* Changed --keep-empty to --allow-empty in the git cherry-pick command

	* Converted run_git_commit to use argv_array

	* Updated cherry-pick --allow-empty description in man page
	
	* added ignore-if-made-empty option to git-cherry-pick

	* Added test to test suite to validate the new cherry-pick options

	* Updated git-rebase man page to be less verbose and more accurate in the
	description of the keep-empty option

	* squashed the addition of the keep-empty flag in git-rebase down to one
	commit from 3

	* fixed up coding style in git-rebase script

	* Optimized detection of empty commits

	* Only augmented git-rebase-editor message if empty commits are
	possible
	
V3)
	* reversed the --ignore-if-empty-logic to by default only keep initially
	empty commits

	* replaced --ignore-if-empty with --keep-redundant-commits, to allow
	empty commits that are made empty via conflict resolution, in addition
	to commits that were created as empty

	* reworked is_original_commit_empty to be more efficient and portable

	* Misc sylistic and spelling cleanups

V4)
	* Reverted the cherry-pick advice changes in V3 based on in-thread
	discussion

	* Rewrote my changes to is_original_commit_empty and run_git_commit to
	not have to fork, making them more efficient.

v5)
	* Additional help text clean up
	* Additional error checking added to run_git_commit code
	* Whitespace cleanup
	* Removed needed cache_tree freeing
	* Test case cleanup
	* Fixed regression in t3404 and t3416 - this turned out to be 
        a problem with the note that git rebase -i adds at the bottom
	of the rebase text.  It was inadvertently indented and caused the
	test fake editor to misread the commit template.  The indentation 
	has been corrected, and these two tests, as well as all the other
	expected tests pass now

v6)
	* synced keeep-redundant-commits option and variable name
	* fixed up some comment terminology
	* minor newline cleanup
	* Removed some unneeded braces from test code
	* minor syntatic cleanup in rebase scripts

	* Refactored empty index checking to make run_git_commit more readable
	I was also going to change the logic so that it operated more like git
	cherry-pick did before the patchset, but Junio's comments made me think
	the new logic was preferable.

v7)
	* Fixed up forgotten comment_out changes requested in
	git-rebase--interactive

	* Made changelog comment for keep-redundant-commits patch more verbose
	so that it was clear that default behavior was changing

	* further refinement of detection of redundant commits, making
	do_pick_commit and run_git_commit more readable

v8)
	* Fixed git-rebase--interactive so that is_empty_commit doesn't choke on
	root commit

	* Minor stylistic change to is_index_unchanged

	* Fixed is_empty_commit to test tree and ptree such that it works with
	shells other than bash
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 121+ messages in thread

* [PATCH v8 1/4] git-cherry-pick: add allow-empty option
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
@ 2012-04-20 14:36   ` Neil Horman
  2012-04-20 14:36   ` [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 14:36 UTC (permalink / raw)
  To: git
  Cc: Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord,
	Junio C Hamano, Neil Horman

git cherry-pick fails when picking a non-ff commit that is empty.  The advice
given with the failure is that a git-commit --allow-empty should be issued to
explicitly add the empty commit during the cherry pick.  This option allows a
user to specify before hand that they want to keep the empty commit.  This
eliminates the need to issue both a cherry pick and a commit operation.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |    9 +++++++++
 builtin/revert.c                  |    2 ++
 sequencer.c                       |    7 +++++--
 sequencer.h                       |    1 +
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fed5097..730237a 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -103,6 +103,15 @@ effect to your index in a row.
 	cherry-pick'ed commit, then a fast forward to this commit will
 	be performed.
 
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.
+
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
 	See the MERGE STRATEGIES section in linkgit:git-merge[1]
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..06b00e6 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
diff --git a/sequencer.c b/sequencer.c
index a37846a..71929ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 6 is max possible length of our args array including NULL */
-	const char *args[6];
+	/* 7 is max possible length of our args array including NULL */
+	const char *args[7];
 	int i = 0;
 
 	args[i++] = "commit";
@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 		args[i++] = "-F";
 		args[i++] = defmsg;
 	}
+	if (opts->allow_empty)
+		args[i++] = "--allow-empty";
+
 	args[i] = NULL;
 
 	return run_command_v_opt(args, RUN_GIT_CMD);
diff --git a/sequencer.h b/sequencer.h
index bb4b138..e2cd725 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -29,6 +29,7 @@ struct replay_opts {
 	int signoff;
 	int allow_ff;
 	int allow_rerere_auto;
+	int allow_empty;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-20 14:36   ` [PATCH v8 1/4] git-cherry-pick: add allow-empty option Neil Horman
@ 2012-04-20 14:36   ` Neil Horman
  2012-04-20 19:21     ` Junio C Hamano
  2012-04-20 14:36   ` [PATCH v8 3/4] git-cherry-pick: Add test to validate new options Neil Horman
  2012-04-20 14:36   ` [PATCH v8 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 1 reply; 121+ messages in thread
From: Neil Horman @ 2012-04-20 14:36 UTC (permalink / raw)
  To: git
  Cc: Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord,
	Junio C Hamano, Neil Horman

The git-cherry-pick --allow-empty command by default only preserves empty
commits that were originally empty, i.e only those commits for which
<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are
non-empty, but were made empty by the inclusion of a prior commit on the current
history are filtered out.  This option allows us to override that behavior and
include redundant commits as empty commits in the change history.

Note that this patch changes the default behavior of git cherry-pick slightly.
Prior to this patch all commits in a cherry-pick sequence were applied and git
commit was run.  The implication here was that, if a commit was redundant, and
the commit did not trigger the fast forward logic, the git commit operation, and
therefore the git cherry-pick operation would fail, displaying the cherry pick
advice (i.e. run git commit --allow-empty).  With this patch however, such
redundant commits are automatically skipped without stopping, unless
--keep-redundant-commits is specified, in which case, they are automatically
applied as empty commits.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-cherry-pick.txt |   12 ++++-
 builtin/revert.c                  |    8 +++-
 sequencer.c                       |   94 ++++++++++++++++++++++++++++++++----
 sequencer.h                       |    1 +
 4 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 730237a..0c004e9 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -110,7 +110,17 @@ effect to your index in a row.
 	behavior, allowing empty commits to be preserved automatically
 	in a cherry-pick. Note that when "--ff" is in effect, empty
 	commits that meet the "fast-forward" requirement will be kept
-	even without this option.
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. the commit recorded the
+	same tree as its parent).  Commits which are made empty due to a
+	previous commit are ignored.  To force the inclusion of those commits
+	use `--keep-redundant-commits`.
+
+--keep-redundant-commits::
+	If a commit being cherry picked duplicates a commit already in the
+	current history, it will result in an empty changeset.  By default these
+	redundant commits are ignored.  This option overrides that behavior and
+	creates an empty commit object.  Implies `--allow-empty`.
 
 --strategy=<strategy>::
 	Use the given merge strategy.  Should only be used once.
diff --git a/builtin/revert.c b/builtin/revert.c
index 06b00e6..f135502 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 		OPT_END(),
 		OPT_END(),
 		OPT_END(),
+		OPT_END(),
 	};
 
 	if (opts->action == REPLAY_PICK) {
 		struct option cp_extra[] = {
 			OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
 			OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
-			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve empty commits"),
+			OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
+			OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
 			OPT_END(),
 		};
 		if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
+	/* keep_if_made_empty implies allow_empty */
+	if (opts->keep_redundant_commits)
+		opts->allow_empty = 1;
+
 	/* Set the subcommand */
 	if (remove_state)
 		opts->subcommand = REPLAY_REMOVE_STATE;
diff --git a/sequencer.c b/sequencer.c
index 71929ba..4e3af82 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "argv-array.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
 	return !clean;
 }
 
+static int is_index_unchanged(void)
+{
+	unsigned char head_sha1[20];
+	struct commit *head_commit;
+
+	if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+		return error(_("Could not resolve HEAD commit\n"));
+
+	head_commit = lookup_commit(head_sha1);
+	if (!head_commit || parse_commit(head_commit))
+		return error(_("could not parse commit %s\n"),
+			     sha1_to_hex(head_commit->object.sha1));
+
+	if (!active_cache_tree)
+		active_cache_tree = cache_tree();
+
+	if (!cache_tree_fully_valid(active_cache_tree))
+		if (cache_tree_update(active_cache_tree, active_cache,
+				  active_nr, 0))
+			return error(_("Unable to update cache tree\n"));
+
+	return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);
+}
+
 /*
  * If we are cherry-pick, and if the merge did not result in
  * hand-editing, we will hit this commit and inherit the original
@@ -260,24 +285,46 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts)
 {
-	/* 7 is max possible length of our args array including NULL */
-	const char *args[7];
-	int i = 0;
+	struct argv_array array;
+	int rc;
+
+	argv_array_init(&array);
+	argv_array_push(&array, "commit");
+	argv_array_push(&array, "-n");
 
-	args[i++] = "commit";
-	args[i++] = "-n";
 	if (opts->signoff)
-		args[i++] = "-s";
+		argv_array_push(&array, "-s");
 	if (!opts->edit) {
-		args[i++] = "-F";
-		args[i++] = defmsg;
+		argv_array_push(&array, "-F");
+		argv_array_push(&array, defmsg);
 	}
+
 	if (opts->allow_empty)
-		args[i++] = "--allow-empty";
+		argv_array_push(&array, "--allow-empty");
 
-	args[i] = NULL;
+	rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
+	argv_array_clear(&array);
+	return rc;
+}
+
+static int is_original_commit_empty(struct commit *commit)
+{
+	const unsigned char *ptree_sha1;
+
+	if (parse_commit(commit))
+		return error(_("Could not parse commit %s\n"),
+			     sha1_to_hex(commit->object.sha1));
+	if (commit->parents) {
+		struct commit *parent = commit->parents->item;
+		if (parse_commit(parent))
+			return error(_("Could not parse parent commit %s\n"),
+				sha1_to_hex(parent->object.sha1));
+		ptree_sha1 = parent->tree->object.sha1;
+	} else {
+		ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+	}
 
-	return run_command_v_opt(args, RUN_GIT_CMD);
+	return !hashcmp(ptree_sha1, commit->tree->object.sha1);
 }
 
 static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
@@ -289,6 +336,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 	char *defmsg = NULL;
 	struct strbuf msgbuf = STRBUF_INIT;
 	int res;
+	int empty_commit;
+	int index_unchanged;
 
 	if (opts->no_commit) {
 		/*
@@ -414,6 +463,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		free_commit_list(remotes);
 	}
 
+	empty_commit = is_original_commit_empty(commit);
+	if (empty_commit < 0)
+		return empty_commit;
+
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
 	 * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -434,6 +487,25 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 		print_advice(res == 1, opts);
 		rerere(opts->allow_rerere_auto);
 	} else {
+		index_unchanged = is_index_unchanged();
+		/*
+		 * If index_unchanged is less than 0, that indicates we either
+		 * couldn't parse HEAD or the index, so error out here.
+		 */
+		if (index_unchanged < 0)
+			return index_unchanged;
+
+		if (!empty_commit && !opts->keep_redundant_commits && index_unchanged)
+			/*
+			 * The head tree and the index match
+			 * meaning the commit is empty.  Since it wasn't created
+			 * empty (based on the previous test), we can conclude
+			 * the commit has been made redundant.  Since we don't
+			 * want to keep redundant commits, we can just return
+			 * here, skipping this commit
+			 */
+			return 0;
+
 		if (!opts->no_commit)
 			res = run_git_commit(defmsg, opts);
 	}
diff --git a/sequencer.h b/sequencer.h
index e2cd725..aa5f17c 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -30,6 +30,7 @@ struct replay_opts {
 	int allow_ff;
 	int allow_rerere_auto;
 	int allow_empty;
+	int keep_redundant_commits;
 
 	int mainline;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v8 3/4] git-cherry-pick: Add test to validate new options
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
  2012-04-20 14:36   ` [PATCH v8 1/4] git-cherry-pick: add allow-empty option Neil Horman
  2012-04-20 14:36   ` [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-20 14:36   ` Neil Horman
  2012-04-20 14:36   ` [PATCH v8 4/4] git-rebase: add keep_empty flag Neil Horman
  3 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 14:36 UTC (permalink / raw)
  To: git
  Cc: Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord,
	Junio C Hamano, Neil Horman

Since we've added the --allow-empty and --keep-redundant-commits
options to git cherry-pick we should also add a test to ensure that its working
properly.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-
 1 files changed, 24 insertions(+), 1 deletions(-)

diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh
index c10b28c..d513127 100755
--- a/t/t3505-cherry-pick-empty.sh
+++ b/t/t3505-cherry-pick-empty.sh
@@ -18,7 +18,12 @@ test_expect_success setup '
 	echo third >> file1 &&
 	git add file1 &&
 	test_tick &&
-	git commit --allow-empty-message -m ""
+	git commit --allow-empty-message -m "" &&
+
+	git checkout master &&
+	git checkout -b empty-branch2 &&
+	test_tick &&
+	git commit --allow-empty -m "empty"
 
 '
 
@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '
 
 '
 
+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
+	git checkout master &&
+	echo fourth >> file2 &&
+	git add file2 &&
+	git commit -m "fourth" &&
+	test_must_fail git cherry-pick empty-branch2
+'
+
+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
+	git checkout master &&
+	git cherry-pick --allow-empty empty-branch2
+'
+
+test_expect_success 'cherry pick with --keep-redundant-commits' '
+	git checkout master &&
+	git cherry-pick --keep-redundant-commits HEAD^
+'
+
 test_done
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
                     ` (2 preceding siblings ...)
  2012-04-20 14:36   ` [PATCH v8 3/4] git-cherry-pick: Add test to validate new options Neil Horman
@ 2012-04-20 14:36   ` Neil Horman
  2012-04-25  1:50     ` Junio C Hamano
  2012-07-18  6:20     ` Martin von Zweigbergk
  3 siblings, 2 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 14:36 UTC (permalink / raw)
  To: git
  Cc: Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord,
	Junio C Hamano, Neil Horman

Add a command line switch to git-rebase to allow a user the ability to specify
that they want to keep any commits in a series that are empty.

When git-rebase's type is am, then this option will automatically keep any
commit that has a tree object identical to its parent.

This patch changes the default behavior of interactive rebases as well.  With
this patch, git-rebase -i will produce a revision set passed to
git-revision-editor, in which empty commits are commented out.  Empty commits
may be kept manually by uncommenting them.  If the new --keep-empty option is
used in an interactive rebase the empty commits will automatically all be
uncommented in the editor.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
---
 Documentation/git-rebase.txt |    4 ++++
 git-rebase--am.sh            |   19 ++++++++++++++-----
 git-rebase--interactive.sh   |   36 +++++++++++++++++++++++++++++++++---
 git-rebase.sh                |    5 +++++
 4 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 504945c..131c35d 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 	will be reset to where it was when the rebase operation was
 	started.
 
+--keep-empty::
+	Keep the commits that do not change anything from its
+	parents in the result.
+
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index c815a24..04d8941 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -20,11 +20,20 @@ esac
 
 test -n "$rebase_root" && root_flag=--root
 
-git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-	--src-prefix=a/ --dst-prefix=b/ \
-	--no-renames $root_flag "$revisions" |
-git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
-move_to_original_branch
+if test -n "$keep_empty"
+then
+	# we have to do this the hard way.  git format-patch completely squashes
+	# empty commits and even if it didn't the format doesn't really lend
+	# itself well to recording empty patches.  fortunately, cherry-pick
+	# makes this easy
+	git cherry-pick --allow-empty "$revisions"
+else
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		--src-prefix=a/ --dst-prefix=b/ \
+		--no-renames $root_flag "$revisions" |
+	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
+fi && move_to_original_branch
+
 ret=$?
 test 0 != $ret -a -d "$state_dir" && write_basic_state
 exit $ret
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5812222..ef263e0 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -167,6 +167,15 @@ has_action () {
 	sane_grep '^[^#]' "$1" >/dev/null
 }
 
+is_empty_commit() {
+	tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null ||
+		die "$1: not a commit that can be picked")
+	ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null ||
+		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)
+
+	return test "$tree" = "$ptree"
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -191,12 +200,19 @@ git_sequence_editor () {
 
 pick_one () {
 	ff=--ff
+
 	case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
 	case "$force_rebase" in '') ;; ?*) ff= ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+
+	if is_empty_commit "$sha1"
+	then
+		empty_args="--allow-empty"
+	fi
+
 	test -d "$rewritten" &&
 		pick_one_preserving_merges "$@" && return
-	output git cherry-pick $ff "$@"
+	output git cherry-pick $empty_args $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -780,9 +796,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 	sed -n "s/^>//p" |
 while read -r shortsha1 rest
 do
+
+	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	then
+		comment_out="#"
+	else
+		comment_out=""
+	fi
+
 	if test t != "$preserve_merges"
 	then
-		printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+		printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"
 	else
 		sha1=$(git rev-parse $shortsha1)
 		if test -z "$rebase_root"
@@ -801,7 +825,7 @@ do
 		if test f = "$preserve"
 		then
 			touch "$rewritten"/$sha1
-			printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+			printf '%s%s\n' "$comment_out" "pick $shortsha1 $rest" >> "$todo"
 		fi
 	fi
 done
@@ -851,6 +875,12 @@ cat >> "$todo" << EOF
 #
 EOF
 
+if test -z "$keep_empty"
+then
+	echo "# Note that empty commits are commented out" >> "$todo"
+fi
+
+
 has_action "$todo" ||
 	die_abort "Nothing to do"
 
diff --git a/git-rebase.sh b/git-rebase.sh
index 69c1374..24a2840 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy
 no-ff!             cherry-pick all commits, even if unchanged
 m,merge!           use merging strategies to rebase
 i,interactive!     let the user edit the list of commits to rebase
+k,keep-empty	   preserve empty commits during rebase
 f,force-rebase!    force rebase even if branch is up to date
 X,strategy-option=! pass the argument through to the merge strategy
 stat!              display a diffstat of what changed upstream
@@ -97,6 +98,7 @@ state_dir=
 action=
 preserve_merges=
 autosquash=
+keep_empty=
 test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
 
 read_basic_state () {
@@ -220,6 +222,9 @@ do
 	-i)
 		interactive_rebase=explicit
 		;;
+	-k)
+		keep_empty=yes
+		;;
 	-p)
 		preserve_merges=t
 		test -z "$interactive_rebase" && interactive_rebase=implied
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-20 14:36   ` [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
@ 2012-04-20 19:21     ` Junio C Hamano
  2012-04-20 19:56       ` Neil Horman
  0 siblings, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-20 19:21 UTC (permalink / raw)
  To: Neil Horman
  Cc: git, Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord

Looks good, modulo perhaps these fixes on top.

 - It would be better to say "dropped" to stress that we inspect and
   actively discard, instead of saying "ignored".

 - There is no need to use "changeset", the term glossary even
   discourages, to make sense of the sentence.

 - There was still a stray keep_if_made_empty.

 - s/Add keep/add keep/ on the title as well.

No need to resend, unless you have fixes other than the following does.

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 0c004e9..3d25a20 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -113,12 +113,12 @@ effect to your index in a row.
 	even without this option.  Note also, that use of this option only
 	keeps commits that were initially empty (i.e. the commit recorded the
 	same tree as its parent).  Commits which are made empty due to a
-	previous commit are ignored.  To force the inclusion of those commits
+	previous commit are dropped.  To force the inclusion of those commits
 	use `--keep-redundant-commits`.
 
 --keep-redundant-commits::
 	If a commit being cherry picked duplicates a commit already in the
-	current history, it will result in an empty changeset.  By default these
+	current history, it will become empty.  By default these
 	redundant commits are ignored.  This option overrides that behavior and
 	creates an empty commit object.  Implies `--allow-empty`.
 
diff --git a/builtin/revert.c b/builtin/revert.c
index f135502..b0b9b1a 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -141,7 +141,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 				"--abort", rollback,
 				NULL);
 
-	/* keep_if_made_empty implies allow_empty */
+	/* implies allow_empty */
 	if (opts->keep_redundant_commits)
 		opts->allow_empty = 1;
 

^ permalink raw reply related	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option
  2012-04-20 19:21     ` Junio C Hamano
@ 2012-04-20 19:56       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-20 19:56 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord

On Fri, Apr 20, 2012 at 12:21:41PM -0700, Junio C Hamano wrote:
> Looks good, modulo perhaps these fixes on top.
> 
>  - It would be better to say "dropped" to stress that we inspect and
>    actively discard, instead of saying "ignored".
> 
>  - There is no need to use "changeset", the term glossary even
>    discourages, to make sense of the sentence.
> 
>  - There was still a stray keep_if_made_empty.
> 
>  - s/Add keep/add keep/ on the title as well.
> 
> No need to resend, unless you have fixes other than the following does.
> 
Nope I'm good, if you can work those changes in.  Thanks!
Neil

> 

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-04-20 14:36   ` [PATCH v8 4/4] git-rebase: add keep_empty flag Neil Horman
@ 2012-04-25  1:50     ` Junio C Hamano
  2012-04-25 10:38       ` Neil Horman
  2012-07-18  6:20     ` Martin von Zweigbergk
  1 sibling, 1 reply; 121+ messages in thread
From: Junio C Hamano @ 2012-04-25  1:50 UTC (permalink / raw)
  To: Neil Horman
  Cc: git, Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord

Neil Horman <nhorman@tuxdriver.com> writes:

> Add a command line switch to git-rebase to allow a user the ability to specify
> that they want to keep any commits in a series that are empty.
> ...
> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> index 5812222..ef263e0 100644
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -167,6 +167,15 @@ has_action () {
>  	sane_grep '^[^#]' "$1" >/dev/null
>  }
>  
> +is_empty_commit() {
> +	tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null ||
> +		die "$1: not a commit that can be picked")
> +	ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null ||
> +		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)
> +
> +	return test "$tree" = "$ptree"
> +}

I've amended the above and removed "return " from the last line.

The series is now in 'next', so if we need further enhancement or fixup,
they need to come as incremental updates, not as replacements.

Thanks.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-04-25  1:50     ` Junio C Hamano
@ 2012-04-25 10:38       ` Neil Horman
  0 siblings, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-04-25 10:38 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Zbigniew Jędrzejewski-Szmek, Clemens Buchacher, Phil Hord

On Tue, Apr 24, 2012 at 06:50:26PM -0700, Junio C Hamano wrote:
> Neil Horman <nhorman@tuxdriver.com> writes:
> 
> > Add a command line switch to git-rebase to allow a user the ability to specify
> > that they want to keep any commits in a series that are empty.
> > ...
> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> > index 5812222..ef263e0 100644
> > --- a/git-rebase--interactive.sh
> > +++ b/git-rebase--interactive.sh
> > @@ -167,6 +167,15 @@ has_action () {
> >  	sane_grep '^[^#]' "$1" >/dev/null
> >  }
> >  
> > +is_empty_commit() {
> > +	tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null ||
> > +		die "$1: not a commit that can be picked")
> > +	ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null ||
> > +		ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)
> > +
> > +	return test "$tree" = "$ptree"
> > +}
> 
> I've amended the above and removed "return " from the last line.
> 
> The series is now in 'next', so if we need further enhancement or fixup,
> they need to come as incremental updates, not as replacements.
> 
> Thanks.
> 
Fastastic, thank you!
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-04-20 14:36   ` [PATCH v8 4/4] git-rebase: add keep_empty flag Neil Horman
  2012-04-25  1:50     ` Junio C Hamano
@ 2012-07-18  6:20     ` Martin von Zweigbergk
  2012-07-18  7:10       ` Johannes Sixt
  1 sibling, 1 reply; 121+ messages in thread
From: Martin von Zweigbergk @ 2012-07-18  6:20 UTC (permalink / raw)
  To: Neil Horman
  Cc: git, Zbigniew Jędrzejewski-Szmek, Clemens Buchacher,
	Phil Hord, Junio C Hamano

On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:
>  pick_one () {
>         ff=--ff
> +
>         case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
>         case "$force_rebase" in '') ;; ?*) ff= ;; esac
>         output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
> +
> +       if is_empty_commit "$sha1"
> +       then
> +               empty_args="--allow-empty"
> +       fi
> +
>         test -d "$rewritten" &&
>                 pick_one_preserving_merges "$@" && return
> -       output git cherry-pick $ff "$@"
> +       output git cherry-pick $empty_args $ff "$@"

The is_empty_commit check seems to mean that if $sha1 is an "empty"
commit, we pass the --allow-empty option to cherry-pick. If it's not
empty, we don't. The word "allow" in "allow-empty" suggests that even
if the commit is not empty, cherry-pick would not mind. So, can we
always pass "allow-empty" to cherry-pick (i.e. even if the commit to
pick is not empty)?

Sorry I'm commenting so late; I didn't have time to look at your
patches when you sent them, but I'm currently working on the code
touched by this patch.

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-07-18  6:20     ` Martin von Zweigbergk
@ 2012-07-18  7:10       ` Johannes Sixt
  2012-07-18  7:16         ` Martin von Zweigbergk
  2012-07-18 12:17         ` Neil Horman
  0 siblings, 2 replies; 121+ messages in thread
From: Johannes Sixt @ 2012-07-18  7:10 UTC (permalink / raw)
  To: Martin von Zweigbergk
  Cc: Neil Horman, git, Zbigniew Jędrzejewski-Szmek,
	Clemens Buchacher, Phil Hord, Junio C Hamano

Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:
> On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:
>>  pick_one () {
>>         ff=--ff
>> +
>>         case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
>>         case "$force_rebase" in '') ;; ?*) ff= ;; esac
>>         output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
>> +
>> +       if is_empty_commit "$sha1"
>> +       then
>> +               empty_args="--allow-empty"
>> +       fi
>> +
>>         test -d "$rewritten" &&
>>                 pick_one_preserving_merges "$@" && return
>> -       output git cherry-pick $ff "$@"
>> +       output git cherry-pick $empty_args $ff "$@"
> 
> The is_empty_commit check seems to mean that if $sha1 is an "empty"
> commit, we pass the --allow-empty option to cherry-pick. If it's not
> empty, we don't. The word "allow" in "allow-empty" suggests that even
> if the commit is not empty, cherry-pick would not mind. So, can we
> always pass "allow-empty" to cherry-pick (i.e. even if the commit to
> pick is not empty)?

I don't think so. If the commit is not empty, but all its changes are
already in HEAD, then it will become "empty" when cherry-picked to HEAD.
In such a case, we usually do not want to record an empty commit, but stop
rebase to give to user a chance to deal with the situation.

-- Hannes

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-07-18  7:10       ` Johannes Sixt
@ 2012-07-18  7:16         ` Martin von Zweigbergk
  2012-07-18 12:17         ` Neil Horman
  1 sibling, 0 replies; 121+ messages in thread
From: Martin von Zweigbergk @ 2012-07-18  7:16 UTC (permalink / raw)
  To: Johannes Sixt
  Cc: Neil Horman, git, Zbigniew Jędrzejewski-Szmek,
	Clemens Buchacher, Phil Hord, Junio C Hamano

On Wed, Jul 18, 2012 at 12:10 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:
> Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:
>> On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:
>>>  pick_one () {
>>>         ff=--ff
>>> +
>>>         case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
>>>         case "$force_rebase" in '') ;; ?*) ff= ;; esac
>>>         output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
>>> +
>>> +       if is_empty_commit "$sha1"
>>> +       then
>>> +               empty_args="--allow-empty"
>>> +       fi
>>> +
>>>         test -d "$rewritten" &&
>>>                 pick_one_preserving_merges "$@" && return
>>> -       output git cherry-pick $ff "$@"
>>> +       output git cherry-pick $empty_args $ff "$@"
>>
>> The is_empty_commit check seems to mean that if $sha1 is an "empty"
>> commit, we pass the --allow-empty option to cherry-pick. If it's not
>> empty, we don't. The word "allow" in "allow-empty" suggests that even
>> if the commit is not empty, cherry-pick would not mind. So, can we
>> always pass "allow-empty" to cherry-pick (i.e. even if the commit to
>> pick is not empty)?
>
> I don't think so. If the commit is not empty, but all its changes are
> already in HEAD, then it will become "empty" when cherry-picked to HEAD.
> In such a case, we usually do not want to record an empty commit, but stop
> rebase to give to user a chance to deal with the situation.

Ah, makes sense. Thanks!

^ permalink raw reply	[flat|nested] 121+ messages in thread

* Re: [PATCH v8 4/4] git-rebase: add keep_empty flag
  2012-07-18  7:10       ` Johannes Sixt
  2012-07-18  7:16         ` Martin von Zweigbergk
@ 2012-07-18 12:17         ` Neil Horman
  1 sibling, 0 replies; 121+ messages in thread
From: Neil Horman @ 2012-07-18 12:17 UTC (permalink / raw)
  To: Johannes Sixt
  Cc: Martin von Zweigbergk, git, Zbigniew Jędrzejewski-Szmek,
	Clemens Buchacher, Phil Hord, Junio C Hamano

On Wed, Jul 18, 2012 at 09:10:06AM +0200, Johannes Sixt wrote:
> Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:
> > On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:
> >>  pick_one () {
> >>         ff=--ff
> >> +
> >>         case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
> >>         case "$force_rebase" in '') ;; ?*) ff= ;; esac
> >>         output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
> >> +
> >> +       if is_empty_commit "$sha1"
> >> +       then
> >> +               empty_args="--allow-empty"
> >> +       fi
> >> +
> >>         test -d "$rewritten" &&
> >>                 pick_one_preserving_merges "$@" && return
> >> -       output git cherry-pick $ff "$@"
> >> +       output git cherry-pick $empty_args $ff "$@"
> > 
> > The is_empty_commit check seems to mean that if $sha1 is an "empty"
> > commit, we pass the --allow-empty option to cherry-pick. If it's not
> > empty, we don't. The word "allow" in "allow-empty" suggests that even
> > if the commit is not empty, cherry-pick would not mind. So, can we
> > always pass "allow-empty" to cherry-pick (i.e. even if the commit to
> > pick is not empty)?
> 
> I don't think so. If the commit is not empty, but all its changes are
> already in HEAD, then it will become "empty" when cherry-picked to HEAD.
> In such a case, we usually do not want to record an empty commit, but stop
> rebase to give to user a chance to deal with the situation.
> 
> -- Hannes
> 

Yes, this is the meaning.  "Allow" was used in the sense of a filter, in that we
are allowing an empty commit to make it into the history, whereas a rebase or
cherry-pick would normally exclude it.
Neil

^ permalink raw reply	[flat|nested] 121+ messages in thread

end of thread, other threads:[~2012-07-18 12:18 UTC | newest]

Thread overview: 121+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-30 19:48 [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-03-30 19:48 ` [PATCH 1/4] git-cherry-pick: add keep-empty option Neil Horman
2012-03-30 20:34   ` Junio C Hamano
2012-03-30 21:15   ` Jeff King
2012-03-31 12:57   ` Neil Horman
2012-03-30 19:48 ` [PATCH 2/4] git-rebase: add keep_empty flag Neil Horman
2012-03-30 20:43   ` Junio C Hamano
2012-03-31 12:59     ` Neil Horman
2012-03-30 19:48 ` [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits Neil Horman
2012-03-30 20:46   ` Junio C Hamano
2012-03-31 13:01     ` Neil Horman
2012-03-30 20:47   ` Junio C Hamano
2012-03-31 13:03     ` Neil Horman
2012-03-30 19:48 ` [PATCH 4/4] git-commit-interactive: Allow " Neil Horman
2012-03-30 20:59   ` Junio C Hamano
2012-03-31 13:11     ` Neil Horman
2012-03-30 20:32 ` [PATCH 0/4] Enhance git-rebases flexibiilty in handling " Junio C Hamano
2012-04-05 19:39 ` [PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2] Neil Horman
2012-04-05 19:39   ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Neil Horman
2012-04-05 20:12     ` Junio C Hamano
2012-04-05 23:24       ` Neil Horman
2012-04-06  0:12         ` Neil Horman
2012-04-06  0:19         ` Jeff King
2012-04-06  1:12           ` Neil Horman
2012-04-06  1:20         ` Junio C Hamano
2012-04-06  2:20           ` Jeff King
2012-04-06  4:19             ` Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]) Jonathan Nieder
2012-04-06  6:55             ` [PATCH 1/5] argv-array: Add argv_array_pop function [v2] Junio C Hamano
2012-04-06  7:33               ` Jeff King
2012-04-06 16:49                 ` Junio C Hamano
2012-04-06 18:02             ` Neil Horman
2012-04-05 19:39   ` [PATCH 2/5] git-cherry-pick: add allow-empty option [v2] Neil Horman
2012-04-05 19:39   ` [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty " Neil Horman
2012-04-05 21:01     ` Junio C Hamano
2012-04-05 23:45       ` Neil Horman
2012-04-06  1:20         ` Junio C Hamano
2012-04-06 18:06       ` Neil Horman
2012-04-06 18:30     ` Johannes Sixt
2012-04-05 19:39   ` [PATCH 4/5] git-cherry-pick: Add test to validate new options [v2] Neil Horman
2012-04-05 19:39   ` [PATCH 5/5] git-rebase: add keep_empty flag [v2] Neil Horman
2012-04-10 15:47 ` [PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-04-10 15:47   ` [PATCH v3 1/4] git-cherry-pick: add allow-empty option Neil Horman
2012-04-10 16:45     ` Junio C Hamano
2012-04-10 18:13       ` Neil Horman
2012-04-10 19:32         ` Junio C Hamano
2012-04-10 20:00           ` Neil Horman
2012-04-10 20:32             ` Junio C Hamano
2012-04-10 20:39               ` Neil Horman
2012-04-10 21:09                 ` Junio C Hamano
2012-04-11  0:44                   ` Neil Horman
2012-04-11 16:52                     ` Junio C Hamano
2012-04-11 18:29                       ` Neil Horman
2012-04-11 18:50                         ` Junio C Hamano
2012-04-11 18:56                           ` Neil Horman
2012-04-10 15:47   ` [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
2012-04-10 17:04     ` Junio C Hamano
2012-04-10 18:25       ` Neil Horman
2012-04-10 15:47   ` [PATCH v3 3/4] git-cherry-pick: Add test to validate new options Neil Horman
2012-04-10 15:47   ` [PATCH v3 4/4] git-rebase: add keep_empty flag Neil Horman
2012-04-13 18:45 ` [PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-04-13 18:45   ` [PATCH v5 1/4] git-cherry-pick: add allow-empty option Neil Horman
2012-04-13 18:45   ` [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
2012-04-15 10:42     ` Clemens Buchacher
2012-04-16 15:38       ` Neil Horman
2012-04-16 22:10         ` Clemens Buchacher
2012-04-17 10:43           ` Neil Horman
2012-04-17 15:42           ` Junio C Hamano
2012-04-17 21:37             ` Clemens Buchacher
2012-04-18 10:41               ` Neil Horman
2012-04-13 18:45   ` [PATCH v5 3/4] git-cherry-pick: Add test to validate new options Neil Horman
2012-04-15  9:39     ` Clemens Buchacher
2012-04-16 11:04       ` Neil Horman
2012-04-16 16:14       ` Neil Horman
2012-04-16 16:35         ` Junio C Hamano
2012-04-16 16:50           ` Neil Horman
2012-04-16 21:42             ` Clemens Buchacher
2012-04-17 10:56               ` Neil Horman
2012-04-17 21:38                 ` Clemens Buchacher
2012-04-18 10:48                   ` Neil Horman
2012-04-18 18:34                     ` Clemens Buchacher
2012-04-13 18:45   ` [PATCH v5 4/4] git-rebase: add keep_empty flag Neil Horman
2012-04-15  9:33     ` Clemens Buchacher
2012-04-16 16:46       ` Neil Horman
2012-04-17 18:20 ` [PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-04-17 18:20   ` [PATCH v6 1/4] git-cherry-pick: add allow-empty option Neil Horman
2012-04-17 18:20   ` [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
2012-04-17 21:45     ` Clemens Buchacher
2012-04-18 10:49       ` Neil Horman
2012-04-17 18:20   ` [PATCH v6 3/4] git-cherry-pick: Add test to validate new options Neil Horman
2012-04-17 18:20   ` [PATCH v6 4/4] git-rebase: add keep_empty flag Neil Horman
2012-04-17 21:47     ` Clemens Buchacher
2012-04-18 10:50       ` Neil Horman
2012-04-18 22:58     ` Junio C Hamano
2012-04-19 13:08       ` Neil Horman
2012-04-19 17:53         ` Junio C Hamano
2012-04-18 19:17 ` [PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-04-18 19:17   ` [PATCH v7 1/4] git-cherry-pick: add allow-empty option Neil Horman
2012-04-18 19:17   ` [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
2012-04-18 22:59     ` Junio C Hamano
2012-04-18 19:17   ` [PATCH v7 3/4] git-cherry-pick: Add test to validate new options Neil Horman
2012-04-18 19:18   ` [PATCH v7 4/4] git-rebase: add keep_empty flag Neil Horman
2012-04-19 10:02     ` Zbigniew Jędrzejewski-Szmek
2012-04-19 11:49       ` Thomas Rast
2012-04-19 12:19         ` Zbigniew Jędrzejewski-Szmek
2012-04-19 13:12           ` Neil Horman
2012-04-19 18:59         ` Junio C Hamano
2012-04-19 19:05           ` Junio C Hamano
2012-04-20 10:35             ` Neil Horman
2012-04-20 14:36 ` [PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits Neil Horman
2012-04-20 14:36   ` [PATCH v8 1/4] git-cherry-pick: add allow-empty option Neil Horman
2012-04-20 14:36   ` [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option Neil Horman
2012-04-20 19:21     ` Junio C Hamano
2012-04-20 19:56       ` Neil Horman
2012-04-20 14:36   ` [PATCH v8 3/4] git-cherry-pick: Add test to validate new options Neil Horman
2012-04-20 14:36   ` [PATCH v8 4/4] git-rebase: add keep_empty flag Neil Horman
2012-04-25  1:50     ` Junio C Hamano
2012-04-25 10:38       ` Neil Horman
2012-07-18  6:20     ` Martin von Zweigbergk
2012-07-18  7:10       ` Johannes Sixt
2012-07-18  7:16         ` Martin von Zweigbergk
2012-07-18 12:17         ` Neil Horman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.