Re: [PATCH v1] rebase -m: Use empty tree base for parentless commits

2014-10-13 Thread Fabian Ruch
Hi,

Junio C Hamano writes:
 Fabian Ruch baf...@gmail.com writes:
 diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
 index d3fb67d..3f754ae 100644
 --- a/git-rebase--merge.sh
 +++ b/git-rebase--merge.sh
 @@ -67,7 +67,13 @@ call_merge () {
  GIT_MERGE_VERBOSITY=1  export GIT_MERGE_VERBOSITY
  fi
  test -z $strategy  strategy=recursive
 -eval 'git-merge-$strategy' $strategy_opts '$cmt^ -- $hd $cmt'
 +base=$(git rev-list --parents -1 $cmt | cut -d ' ' -s -f 2 -)
 +if test -z $base
 +then
 +# the empty tree sha1
 +base=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 +fi
 +eval 'git-merge-$strategy' $strategy_opts '$base -- $hd $cmt'
 
 This looks wrong.
 
 The interface to git-merge-$strategy is designed in such a way
 that each strategy should be capable of taking _no_ base at all.

Ok, but doesn't this use of the git-merge-$strategy interface (as shown
in the example below) apply only to the case where one wants to merge
two histories by creating a merge commit? When a merge commit is being
created, the documentation states that git-merge abstracts from the
commit history considering the _total change_ since a merge base on each
branch.

In contrast, here (i.e., in the case of git-rebase--merge) we care about
how the changes introduced by the _individual commits_ are applied.
Therefore, don't we want to be explicit about the base and tell
git-merge-$strategy exactly which changes it should merge into the
current head?

The codebase has always been doing this both for git-rebase--merge and
git-cherry-pick. What leads to the reported bug is that the latter
covers the case where the commit object has no parents but the former
doesn't. Root commits are handled by git-cherry-pick (and should be by
git-rebase--merge) using an explicit base for the same reason why
$cmt^ is given.

 See how unquoted $common is given to git-merge-$strategy in
 contrib/examples/git-merge.sh, i.e.
 
 eval 'git-merge-$strategy '$xopt' $common -- $head_arg $@'
 
 where common comes from
 
   common=$(git merge-base ...)
 
 which would be empty when you are looking at disjoint histories.

If there are still objections to the patch because of the magic number
and the cut, it might be worth considering an implementation of
git-rebase--merge using git-cherry-pick's merge strategy option.

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


[PATCH v1] rebase -m: Use empty tree base for parentless commits

2014-10-09 Thread Fabian Ruch
When the user specifies a merge strategy, `git-merge-$strategy` is
used in non-interactive mode to replay the changes introduced by the
current branch relative to some upstream. Specifically, for each
commit `c` that is not in upstream the changes that led from `c^` to
`c` are reapplied.

If the current has a different root than the upstream, either because
the history is disconnected or merged in a disconnected history, then
there will be a parentless commit `c` and `c^` will not refer to a
commit.

In order to cope with such a situation, check for every `c` whether
its list of parents is empty. If it is empty, determine the
introduced changes by comparing the committed tree to the empty tree
instead. Otherwise, take the differences between `c^` and `c` as
before.

The other git-rebase modes do not have similar problems because they
use git-cherry-pick to replay changes, even with strategy options. It
seems that the non-interactive rebase with merge strategies was not
implemented using git-cherry-pick because it did not support them at
the time (`git rebase --merge` added in 58634dbf and `git cherry-pick
--strategy` added in 91e52598). The idea of using the empty tree as
reference tree for orphan commits is taken from the git-cherry-pick
implementation.

Regarding the patch, we do not have to commit the empty tree before
we can pass it as a base argument to `git-merge-$strategy` because
tree objects are recognized as such and implicitly committed by
`git-merge-$strategy`.

Add a test. The test case rebases a single disconnected commit which
creates an isolated file on master and, therefore, does not require a
specific merge strategy. It is a mere sanity check.

Reported-by: David M. Lloyd david.ll...@redhat.com
Signed-off-by: Fabian Ruch baf...@gmail.com
---
Hi David,

I don't think you made a mistake at all. If I understand the --merge
mode of git-rebase correctly there is no need to require a parent.
The error occurs when the script tries to determine the changes your
merge commit introduces, which includes the whole importing/master
branch. The strategy is not yet part of the picture then and will not
be until the changes are being replayed.

The test case tries to simplify your scenario because the relevant
characteristic seems to be that a parentless commit gets rebased, the
root commit of importing/master.

Regards,
   Fabian

 git-rebase--merge.sh  |  8 +++-
 t/t3400-rebase.sh | 12 
 t/t3402-rebase-merge.sh   | 12 
 t/t3404-rebase-interactive.sh | 10 ++
 4 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index d3fb67d..3f754ae 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -67,7 +67,13 @@ call_merge () {
GIT_MERGE_VERBOSITY=1  export GIT_MERGE_VERBOSITY
fi
test -z $strategy  strategy=recursive
-   eval 'git-merge-$strategy' $strategy_opts '$cmt^ -- $hd $cmt'
+   base=$(git rev-list --parents -1 $cmt | cut -d ' ' -s -f 2 -)
+   if test -z $base
+   then
+   # the empty tree sha1
+   base=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+   fi
+   eval 'git-merge-$strategy' $strategy_opts '$base -- $hd $cmt'
rv=$?
case $rv in
0)
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 47b5682..9b0b57f 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -10,6 +10,8 @@ among other things.
 '
 . ./test-lib.sh
 
+. $TEST_DIRECTORY/lib-rebase.sh
+
 GIT_AUTHOR_NAME=author@name
 GIT_AUTHOR_EMAIL=bogus@email@address
 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
@@ -255,4 +257,14 @@ test_expect_success 'rebase commit with an ancient 
timestamp' '
grep author .* 34567 +0600$ actual
 '
 
+test_expect_success 'rebase disconnected' '
+   test_when_finished reset_rebase 
+   git checkout --orphan test-rebase-disconnected 
+   git rm -rf . 
+   test_commit disconnected 
+   git rebase master 
+   test_path_is_file disconnected.t 
+   test_cmp_rev master HEAD^
+'
+
 test_done
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index 5a27ec9..1653540 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -7,6 +7,8 @@ test_description='git rebase --merge test'
 
 . ./test-lib.sh
 
+. $TEST_DIRECTORY/lib-rebase.sh
+
 T=A quick brown fox
 jumps over the lazy dog.
 for i in 1 2 3 4 5 6 7 8 9 10
@@ -153,4 +155,14 @@ test_expect_success 'rebase --skip works with two 
conflicts in a row' '
git rebase --skip
 '
 
+test_expect_success 'rebase --merge disconnected' '
+   test_when_finished reset_rebase 
+   git checkout --orphan test-rebase-disconnected 
+   git rm -rf . 
+   test_commit disconnected 
+   git rebase --merge master 
+   test_path_is_file disconnected.t 
+   test_cmp_rev master HEAD^
+'
+
 test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8197ed2

Re: [PATCH v1] rebase -m: Use empty tree base for parentless commits

2014-10-09 Thread Fabian Ruch
Hi Junio,

On 10/09/2014 09:05 PM, Junio C Hamano wrote:
 Fabian Ruch baf...@gmail.com writes:
 diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
 index d3fb67d..3f754ae 100644
 --- a/git-rebase--merge.sh
 +++ b/git-rebase--merge.sh
 @@ -67,7 +67,13 @@ call_merge () {
  GIT_MERGE_VERBOSITY=1  export GIT_MERGE_VERBOSITY
  fi
  test -z $strategy  strategy=recursive
 -eval 'git-merge-$strategy' $strategy_opts '$cmt^ -- $hd $cmt'
 +base=$(git rev-list --parents -1 $cmt | cut -d ' ' -s -f 2 -)
 +if test -z $base
 +then
 +# the empty tree sha1
 +base=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 +fi
 +eval 'git-merge-$strategy' $strategy_opts '$base -- $hd $cmt'
 
 This looks wrong.

Ok.

 The interface to git-merge-$strategy is designed in such a way
 that each strategy should be capable of taking _no_ base at all.

The merge strategies resolve and octopus seem to refuse to run if no
base is specified. The former silently exits if no bases are given and
the latter dies saying Unable to find common commit.

 See how unquoted $common is given to git-merge-$strategy in
 contrib/examples/git-merge.sh, i.e.
 
 eval 'git-merge-$strategy '$xopt' $common -- $head_arg $@'
 
 where common comes from
 
   common=$(git merge-base ...)
 
 which would be empty when you are looking at disjoint histories.
 
 Also rev-list piped to cut is too ugly to live in our codebase X-.

Is there a better way to get the parents list from a shell script then?
I stole the construct from git-rebase--interactive.sh which uses it to
check for rewritten parents when preserving merges.

 Wouldn't it be sufficient to do something like this instead?
 
   eval 'git-merge-$strategy' $strategy_opts \
   $(git rev-parse --quiet --verify $cmt^) -- $hd $cmt

Yes, for the recursive strategies this seems to have the exact same
behaviour as it inserts the empty tree in case git-merge-base returns an
empty list. Nice, we would get rid of both the magic number and the cut.

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


Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword

2014-09-21 Thread Fabian Ruch
Hi Michael,

On 08/13/2014 02:47 PM, Michael Haggerty wrote:
 On 08/07/2014 01:59 AM, Fabian Ruch wrote:
 pick and reword are atomic to-do list commands in the sense that they
 open a new task which is closed after the respective command is
 completed. squash and fixup are not atomic. They create a new task
 which is not completed until the last squash or fixup is processed.
 
 I don't understand the distinction that you are attempting to draw
 between atomic and non-atomic commands.  For example, in the
 following command list:
 
 pick 111
 squash 222
 fixup 333
 
 the pick command doesn't seem very atomic, because the *end* result of
 the three commands is a single commit that is affected by all three
 commands.

Right, when I wrote the commit message I was thinking in abstract terms
so I implicitly thought of your example as a (single) squash/fixup
command. Now it has become obvious that I wasn't very thorough with the
implementation part. The git-rebase implementation is oblivious to the
context when it processes 'pick' lines and your example shows how 'pick'
lines can be part of squash/fixup command context. In conclusion, I
intended to keep options disabled for squash/fixup commands but failed
to do so because I neglected that a 'pick' line can initiate a
squash/fixup command.

 Furthermore, if we change the example to
 
 pick 111
 squash --reset-author 222
 fixup --signoff 333
 
 then isn't it clear that the user's intention was to apply both options,
 --reset-author and --signoff, to the resulting commit?

This seems to suggest an interpretation of todo lists similar to what I
was thinking of when writing the commit message, that is one in which
pick is not oblivious to the neighbouring commands. It might be a
problem that it forbids the (admittedly improbable) use case where
--reset-author is used to rewrite the authorship to something recent and
fixup to have an even more recent committership.

To reconcile this kind of vertical interpretation with the horizontal
specification of options one could introduce a todo list command taking
the list of commits to be squashed as an argument. However, that seems
to make it difficult to obtain the squash behaviour for some commits and
the fixup behaviour for others that are part of the same chain.

The alternative interpretation of todo lists as simplified batch scripts
for git commands would allow the intended behaviour (--reset-author and
--signoff applied to the resulting commit), not restrict the user
relatively to what she can already do on the command line and give
actually different meanings to the syntactically different todo lists

pick 111
squash --reset-author 222
fixup --signoff 333

and

pick 111
squash --signoff 222
fixup --reset-author 333

, which would be treated identically by an implementation that collects
the options. The current meaning of squash/fixup seems to be valid in
the batch interpretation.

 In other
 words, it seems to me that any options on such a chain of lines should
 be collected and applied to the final commit as a whole.

To summarise, I think line options might be confusing if we interpret

pick 111
squash --reset-author 222
fixup --signoff 333

as

combine the changes of 111, 222, 333
concatenate the messages of 111 and 222
edit the message
reset the authorship to the committership
add a Signed-off-by: line

and not as

pick 111
pick -n 222
commit amend --reset-author -m $squash_msg
pick -n 333
commit amend --signoff --edit

.

Thanks for pointing me at these issues. Atomic and non-atomic are
really poorly-chosen terminology and the squash-initiating 'pick' might
not be implemented correctly.

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


Re: Please help provide clarity on git rebase internals

2014-09-19 Thread Fabian Ruch
Hi Colin,

On 09/08/2014 01:25 PM, Colin Yates wrote:
 My understanding is that rebasing branch B onto branch A unrolls all
 of branch B's commits and then reduces them onto the HEAD of branch
 A.
 
 For example, I took featureA branch from develop three days ago.
 develop subsequently had commits #d1, #d2 and #d3. featureA also had
 #f1 and #f2 and in terms of time they are all intermingled.
 
 My understanding of rebase is that after issuing git fetch; git
 rebase origin/develop in featureA branch a git log should show #f2,
 #f1, #d3, #d2, #d1.

Almost, it will show #f2', #f1', #d3, #d2, #d1. The commits #f1 and #f2
must be recreated because the changes they introduce are being applied
to a different base, that is a different tree. The result of rebasing
#f1 and #f2 will be a tree different from the one at the tip of branch
'featureA'.

 I am seeing this, but sometimes I see something I can't explain and
 that is a merge conflict as if git was doing a merge rather than a
 rebase.

A rebase is a series of patch applications to a base different from the
one they were created in relation to. If a patch context is different in
the new base, the patch cannot be applied by simply replacing '-' lines
with '+' lines and a merge of changes is required. That merge can fail
itself and we see merge conflicts. It's no contradiction that a merge
(of changes) is happening even though git is not doing a merge (of
branches).

 For example, let's imagine that #f1 removed fileA, some time later #d1
 added a line to that file. If I was doing a merge then of course this
 should be a conflict, however applying #f1 to develop HEAD should work
 even if fileA has changed (i.e. #f1 removes the updated fileA).

The commit #f1 does not just record the deletion of the file named
'fileA' but also a patch that removes every single line in that file.
Another way to view the behaviour of 'git rm' is that the command does
not remove names from the tree but objects that are given by both a name
and a content. The replay of #f1 on top of #d3 conflicts because the
patch cannot be applied, the content does not match respectively.

 As it is I am frequently running into merge conflicts in this manner
 when it *appears* git is applying a patch from featureA onto develop
 _as it was then the patch was made_.

I'm not sure if I'm understanding correctly, but I'd say it doesn't just
appear that way. First, git-rebase takes the patch that represents the
changes between develop@{3 days ago} and #f1 and applies it to #d3. The
result is commit #f1'. Then it applies the differences between #f1 and
#f2 to #f1', which in turn results in #f2'.

 I am also seeing merge conflicts that occur between commits in the
 develop branch itself as well, which I assumed would be effectively
 read-only.

You're right, the branch 'develop' shouldn't be touched at all if you
run 'git rebase develop' on branch 'featureA'. Do you mean between
commits in the *featureA* branch itself instead, i.e. it is unexpected
if the replay of #f2 fails after the replay of #f1 succeeded?

 In terms of functional programming I thought rebase was a pure reduce
 of a sequence of patches from featureA branch onto HEAD.

I like how you're viewing 'rebase' as, I guess, a right fold with the
base as the initial element and 'apply'/'cherry-pick' as the operator,
but I'm not sure what we can learn from this representation. Is it true
that there is an emphasis on pure here suggesting that this is where
the functional interpretation fails?

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


Re: [PATCH] t1503: test rev-parse --verify --quiet with deleted reflogs

2014-09-14 Thread Fabian Ruch
Hi David,

On 09/14/2014 10:30 AM, David Aguilar wrote:
 Ensure that rev-parse --verify --quiet is silent when asked
 about deleted reflog entries.
 
 Signed-off-by: David Aguilar dav...@gmail.com
 ---
 This verifies and depends on refs: make rev-parse --quiet actually quiet.
 
  t/t1503-rev-parse-verify.sh | 9 +
  1 file changed, 9 insertions(+)
 
 diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
 index 813cc1b..731c21c 100755
 --- a/t/t1503-rev-parse-verify.sh
 +++ b/t/t1503-rev-parse-verify.sh
 @@ -83,6 +83,15 @@ test_expect_success 'fails silently when using -q' '
   test -z $(cat error)
  '
  
 +test_expect_success 'fails silently when using -q with deleted reflogs' '
 + ref=$(git rev-parse HEAD) 
 + : .git/logs/refs/test 
 + git update-ref -m test refs/test $ref 

I'm just curious, why not simply

   git branch test

?

 + git reflog delete --updateref --rewrite refs/test@{0} 
 + test_must_fail git rev-parse --verify --quiet refs/test@{0} 2error 

Is it a shortcoming of the specification that it doesn't consider
whatever might be written to stdout? Is it acceptable that if the
git-rev-parse command succeeds, the error message from test_must_fail
will be written to the file error and, therefore, somewhat hidden from
the user running the tests?

 + test -z $(cat error)

test(1) comes with an option (-s) to perform such tests and test-lib.sh
defines test_must_be_empty which additionally outputs the given file's
contents if its not empty.

 +'
 +
  test_expect_success 'no stdout output on error' '
   test -z $(git rev-parse --verify) 
   test -z $(git rev-parse --verify foo) 
 

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


Re: [RFC/PATCH 0/3] Teach revert/cherry-pick the --no-verify option

2014-09-05 Thread Fabian Ruch
Hi Johan,

Johan Herland writes:
 A colleague of mine noticed that cherry-pick does not accept the
 --no-verify option to skip running the pre-commit/commit-msg hooks.

neither git-cherry-pick nor git-revert execute the pre-commit or
commit-msg hooks at the moment. The underlying rationale can be found in
the log message of commit 9fa4db5 (Do not verify
reverted/cherry-picked/rebased patches.). Indeed, the sequencer uses
git-commit internally which executes the two verify hooks by default.
However, the particular command line being used implicitly specifies the
--no-verify option. This behaviour is implemented in
sequencer.c#run_git_commit as well, right before the configurable
git-commit options are handled. I guess that's easily overlooked since
the documentation doesn't mention it and the implementation uses the
short version -n of --no-verify.

The reasons why the new test cases succeed nonetheless are manifold. I
hope they're still understandable even though I don't put the comments
next to the code.

The revert with failing hook test case fails if run in isolation,
which can be achieved by using the very cool --run option of test-lib.
More specifically, git-revert does not fail because it executes the
failing hook but because the preceding test case leaves behind an
uncommitted index.

In the cherry-pick with failing hook test case, git-cherry-pick really
fails because it doesn't know the --no-verify option yet, which
presumably ended up there only by accident. This test case is
meaningless if run in isolation because it assumes that revert with
failing hook creates a commit (else HEAD^ points nowhere).

I like your patchset for that it makes it explicit in both the
documentation and the tests whether the commits resulting from
cherry-picks are being verified or not.

Kind regards,
   Fabian

 Here's a first attempt at adding --no-verify to the revert/cherry-pick.
 
 Have fun! :)
 
 ...Johan
 
 Johan Herland (3):
   t7503/4: Add failing testcases for revert/cherry-pick --no-verify
   revert/cherry-pick: Add --no-verify option, and pass it on to commit
   revert/cherry-pick --no-verify: Update documentation
 
  Documentation/git-cherry-pick.txt |  4 
  Documentation/git-revert.txt  |  4 
  Documentation/githooks.txt| 20 ++--
  builtin/revert.c  |  1 +
  sequencer.c   |  7 +++
  sequencer.h   |  1 +
  t/t7503-pre-commit-hook.sh| 24 
  t/t7504-commit-msg-hook.sh| 24 
  8 files changed, 75 insertions(+), 10 deletions(-)
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 00/27] Enable options --signoff, --reset-author for pick, reword, edit

2014-08-18 Thread Fabian Ruch
Hi,

this is the third reroll of the patch series that makes the
well-known commit options `--signoff` and `--reset-author` available
to be used with the to-do list commands `pick`, `reword` and `edit`.

What follows is a short changelog since the second reroll from almost
two weeks ago. The changes were mostly made in response to Thomas'
review.

- Merely a commit message comment: The `editor.sh` wrapper script is
  still necessary to use `output` with interactive to-do list
  commands because the `--quiet` option does not force all commands
  to be totally silent.

- `git-rebase--interactive.sh` now uses the quoting functionality of
  git-rev-parse when assigning the `editor.sh` path to the
  `GIT_EDITOR` environment variable, in case the path includes double
  quotes itself.

- The tests dealing with squash commits that violate either
  commit-msg or pre-commit now test `squash` and `fixup` sequences
  with more than two commits. This is important since the final
  commit is created on a different code path than the others.

- The `fake_editor.sh` change that prints the debug output on stderr
  instead of stdout is now a separate patch so that it can be
  referred to directly. The change might be considered a hack and
  needs revision.

- Since whitespace and shell quoting are not supported by line
  options, the `opts` variable does not need to be evaluated using
  `eval` anymore.

- Malformed to-do command lines either trigger an unknown command
  or an unknown option error message but not both.

- A test case that specifies that `git rebase --continue` only
  commits staged changes if the user has not committed on top of the
  last successfully replayed commit in the meantime. The rationale
  behind this is that `git rebase --continue` commits using the
  author information of the commit it tried to replay last. While it
  perfectly makes sense to assume that this information is correct
  when HEAD has not changed, it is probable that it is incorrect when
  the user has created commits herself because the rebase process was
  interrupted for conflict resolution only and one must know
  internals to intentionally make `git rebase --continue` commit
  changes on top of user-created commits using original author
  information.

- `do_pick` did not preserve the authorship of the original commit
  when it was asked to rewrite the commit, for instance using
  `reword`. This was fixed by applying the authorship of the named
  commit using `do_with_author`. That doesn't interfere with squash
  commits because `do_with_author` is a no-op when used with `git
  commit --amend`.

- `git rebase --continue` did not apply the line options after
  conflict resolution. This was added by remembering line options the
  way `git-rebase--interactive.sh` reminds itself of amending
  commits.

- The test suite `t3427-rebase-line-options.sh` is responsible for
  the specification of to-do lists that use line options.

- The two line options available are now documented both in the
  git-rebase man page and the to-do list help text.

Thanks for your time,
   Fabian

Fabian Ruch (27):
  rebase -i: allow replaying commits with empty log messages
  rebase -i: allow squashing empty commits without complaints
  rebase -i: allow rewording empty commits without complaints
  fake_editor: leave standard output unchanged
  rebase -i: hide interactive command messages in verbose mode
  rebase -i: discard redundant message when rewording fails
  commit: allow disabling pre-commit and commit-msg separately
  rebase -i: verify squash messages using commit-msg
  rebase -i: do not verify reworded patches using pre-commit
  rebase -i: teach do_pick the option --edit
  rebase -i: implement reword in terms of do_pick
  rebase -i: log the replay of root commits
  rebase -i: do not use -C when --no-edit is sufficient
  rebase -i: commit only once when rewriting picks
  rebase -i: do not die in do_pick
  rebase -i: teach do_pick the option --amend
  rebase -i: teach do_pick the option --file
  rebase -i: remove no-op do_with_author git commit --amend
  rebase -i: prepare for squash in terms of do_pick --amend
  rebase -i: implement squash in terms of do_pick
  rebase -i: explicitly distinguish replay commands and exec tasks
  rebase -i: parse to-do list command line options
  rebase -i: teach do_pick the option --reset-author
  rebase -i: teach do_pick the option --signoff
  rebase -i: do not overwrite user author information
  rebase -i: refuse to commit when resuming with updated head
  rebase -i: enable --signoff, --reset-author for pick, reword, edit

 Documentation/git-commit.txt   |   8 +-
 Documentation/git-rebase.txt   |  13 ++
 builtin/commit.c   |  32 +++-
 git-rebase--interactive.sh | 370 -
 git-rebase.sh  |  13 +-
 t/lib-rebase.sh|  28 +++-
 t/t3404-rebase-interactive.sh  | 290 ++--
 t/t3406-rebase-message.sh  |  18

[PATCH v3 03/27] rebase -i: allow rewording empty commits without complaints

2014-08-18 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If `--keep-empty` is
passed as option to git-rebase--interactive, empty commits ought to
be replayed without complaints. However, if the users chooses to
reword an empty commit by changing the respective to-do list entry
from

pick fa1afe1 Empty commit

to

reword fa1afe1 Empty commit

, then git-rebase--interactive suddenly fails to replay the empty
commit. This is especially counterintuitive because `reword` is
thought of as a `pick` that alters the log message in some way but
nothing more and the unchanged to-do list entry would not fail.

Handle `reword` by cherry-picking the named commit and editing the
log message using

git commit --allow-empty --amend

instead of

git commit --amend.

Add test.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 33 +
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index ada340c..eb1dcda 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
warn This is most likely due to an empty commit 
message, or the pre-commit hook
warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a95cb2a..f4e886f 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -75,6 +75,39 @@ test_expect_success 'rebase --keep-empty' '
test_line_count = 6 actual
 '
 
+test_expect_success 'rebase --keep-empty (reword)' '
+   git checkout -b reword-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 reword 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 6 actual
+'
+
+test_expect_success 'rebase --keep-empty (edit)' '
+   git checkout -b edit-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 edit 2 git rebase --keep-empty -i HEAD~2 
+   git rebase --continue 
+   git log --oneline actual 
+   test_line_count = 6 actual
+'
+
+test_expect_success 'rebase --keep-empty (fixup)' '
+   git checkout -b fixup-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 fixup 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 5 actual
+'
+
+test_expect_success 'rebase --keep-empty (squash)' '
+   git checkout -b squash-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 squash 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 5 actual
+'
+
 test_expect_success 'rebase -i with the exec command' '
git checkout master 
(
-- 
2.0.1

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


[PATCH v3 04/27] fake_editor: leave standard output unchanged

2014-08-18 Thread Fabian Ruch
The helper function `set_fake_editor` installs a script as
`GIT_EDITOR` that applies pre-defined editing rules to the files it
is called with, which is a quite powerful tool when writing test
cases for git-rebase--interactive. To aid in debugging the changes it
makes, the installed script dumps the file contents to stdout before
and after editing. That interferes with the output from
git-rebase--interactive, however, and the debug information has to be
removed from stdout in a error-prone way. Print the editor contents
on stderr instead.

When a test case wants to analyse stderr, we need to come up with a
different solution. The less convenient possibility that always
remains is to store the debug output in a file in the trash
directory or even keeping copies of the edited files before and after
editing.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 t/lib-rebase.sh   |  8 
 t/t3404-rebase-interactive.sh | 18 ++
 2 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 6bd2522..0cd1193 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -41,8 +41,8 @@ set_fake_editor () {
test -z $FAKE_LINES  exit
grep -v '^#'  $1  $1.tmp
rm -f $1
-   echo 'rebase -i script before editing:'
-   cat $1.tmp
+   echo 'rebase -i script before editing:' 2
+   cat $1.tmp 2
action=pick
for line in $FAKE_LINES; do
case $line in
@@ -59,8 +59,8 @@ set_fake_editor () {
action=pick;;
esac
done
-   echo 'rebase -i script after editing:'
-   cat $1
+   echo 'rebase -i script after editing:' 2
+   cat $1 2
EOF
 
test_set_editor $(pwd)/fake-editor.sh
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index f4e886f..7cc6ebf 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -882,9 +882,8 @@ test_expect_success 'running git rebase -i --exec git show 
HEAD' '
(
FAKE_LINES=1 exec_git_show_HEAD 2 exec_git_show_HEAD 
export FAKE_LINES 
-   git rebase -i HEAD~2 expect
+   git rebase -i HEAD~2 expected
) 
-   sed -e 1,9d expect expected 
test_cmp expected actual
 '
 
@@ -896,9 +895,8 @@ test_expect_success 'running git rebase --exec git show 
HEAD -i' '
(
FAKE_LINES=1 exec_git_show_HEAD 2 exec_git_show_HEAD 
export FAKE_LINES 
-   git rebase -i HEAD~2 expect
+   git rebase -i HEAD~2 expected
) 
-   sed -e 1,9d expect expected 
test_cmp expected actual
 '
 
@@ -910,9 +908,8 @@ test_expect_success 'running git rebase -ix git show 
HEAD' '
(
FAKE_LINES=1 exec_git_show_HEAD 2 exec_git_show_HEAD 
export FAKE_LINES 
-   git rebase -i HEAD~2 expect
+   git rebase -i HEAD~2 expected
) 
-   sed -e 1,9d expect expected 
test_cmp expected actual
 '
 
@@ -924,9 +921,8 @@ test_expect_success 'rebase -ix with several CMD' '
(
FAKE_LINES=1 exec_git_show_HEAD;_pwd 2 
exec_git_show_HEAD;_pwd 
export FAKE_LINES 
-   git rebase -i HEAD~2 expect
+   git rebase -i HEAD~2 expected
) 
-   sed -e 1,9d expect expected 
test_cmp expected actual
 '
 
@@ -939,9 +935,8 @@ test_expect_success 'rebase -ix with several instances of 
--exec' '
FAKE_LINES=1 exec_git_show_HEAD exec_pwd 2
exec_git_show_HEAD exec_pwd 
export FAKE_LINES 
-   git rebase -i HEAD~2 expect
+   git rebase -i HEAD~2 expected
) 
-   sed -e 1,11d expect expected 
test_cmp expected actual
 '
 
@@ -965,9 +960,8 @@ test_expect_success 'rebase -ix with --autosquash' '
git checkout -b autosquash_expected 
FAKE_LINES=1 fixup 3 fixup 4 exec_git_show_HEAD 2 
exec_git_show_HEAD 
export FAKE_LINES 
-   git rebase -i HEAD~4 expect
+   git rebase -i HEAD~4 expected
) 
-   sed -e 1,13d expect expected 
test_cmp expected actual
 '
 
-- 
2.0.1

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


[PATCH v3 01/27] rebase -i: allow replaying commits with empty log messages

2014-08-18 Thread Fabian Ruch
git-rebase--interactive handles empty log messages inconsistently
between enabled and disabled fast-forwards. By default, commits with
empty log messages are rebased successfully like in non-interactive
mode. In contrast, the `--no-ff` option aborts the replay of such
commits.

In line with not verifying rebased commits and behaving like
git-rebase for `pick` lines, use the `--allow-empty-message` option
to replay commits. Root commits are replayed by recreating them in
`do_pick` using git-commit and all other commits are replayed using
git-cherry-pick in `pick_one`. Apply the option, understood by both
git-commit and git-cherry-pick, at the respective sites.

In case of `reword` and `squash`, continue to abort the rebase if the
_resulting_ commit would have no commit message. The rationale behind
this default is that patches and their log messages should be
verified at least once. For unchanged commits this is assumed to have
happened according to the author's standards when she created the
commits for the first time. While the empty log message can always be
kept in place by editing and resuming the aborted rebase, a debatable
alternative could be to teach git-rebase--interactive the option
`--allow-empty-message` for disabling complaints about empty log
messages even in changed commits.

The `fixup` case is different again because it throws away the second
commit's log message and uses the first log message for the changed
commit. Do not abort the rebase if that message is empty either since
it is assumed to have been verified already.

The remaining to-do list command `edit` is handled just like `pick`
for this matter, because git-rebase--interactive replays the named
commit without changes before the rebase is interrupted and the user
can make her changes to the replayed commit.

Add tests. In particular, design the `squash`-specific test case such
that it involves interim commits and `fixup` steps. Interim commits
should not trigger failures themselves and `fixup` steps should not
let git-rebase--interactive forget that it is still dealing with a
`squash` result.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 10 ++
 t/t3404-rebase-interactive.sh | 38 ++
 t/t3412-rebase-root.sh| 16 
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b64dd28..3222bf6 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -249,7 +249,7 @@ pick_one () {
 
test -d $rewritten 
pick_one_preserving_merges $@  return
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $empty_args $ff $@
 }
@@ -363,7 +363,7 @@ pick_one_preserving_merges () {
echo $sha1 $(git rev-parse HEAD^0)  
$rewritten_list
;;
*)
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $@ ||
die_with_patch $sha1 Could not pick $sha1
@@ -549,7 +549,8 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   do_with_author output git commit --amend --no-verify -F 
$squash_msg \
+   do_with_author output git commit --allow-empty-message \
+   --amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
;;
@@ -557,7 +558,8 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --amend --no-verify 
-F $fixup_msg \
+   do_with_author git commit --allow-empty-message 
\
+   --amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8197ed2..9c71835 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1039,4 +1039,42 @@ test_expect_success 'short SHA-1 collide' '
)
 '
 
+test_expect_success 'setup commits with empty commit log

[PATCH v3 08/27] rebase -i: verify squash messages using commit-msg

2014-08-18 Thread Fabian Ruch
Using the to-do list command `squash` the user can specify two or
more commits and git-rebase creates one commit that introduces all
their changes combined. The authorship for the created commit is
taken from the first commit specified and the user can edit the log
message. There is a variant of `squash` available named `fixup` which
also takes the first log message without asking for user input.

While it is reasonable to not verify replayed changes twice or
rejecting some other author's changes in her name, it is insufficient
to not verify the user input used as log message in the case of
`squash`. Specify the git-commit option `--no-pre-commit` instead of
`--no-verify` when committing the squash result, but not before, to
let the commit-msg hook verify the final squash message. For the same
reasons the pre-commit hook is disabled in all replay modes, the
commit-msg hook is disabled in `fixup` mode.

Add tests. In addition to the existing test checking that the
pre-commit hook is disabled when simply picking a commit, provide a
test checking that the commit-msg hook is disabled as well.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 80 +++
 2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index cf62daa..54c4614 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -562,7 +562,7 @@ do_next () {
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author output git commit --allow-empty 
--amend --no-verify -F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author output git commit --allow-empty 
--amend --no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 7cc6ebf..abb829e 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -664,6 +664,86 @@ test_expect_success 'rebase a commit violating pre-commit' 
'
 
 '
 
+test_expect_success 'setup failing pre-commit' '
+   HOOKDIR=$(git rev-parse --git-dir)/hooks 
+   mkdir -p $HOOKDIR 
+   PRE_COMMIT=$HOOKDIR/pre-commit 
+   cat $PRE_COMMIT -EOF 
+   #!/bin/sh
+   echo running failing pre-commit...
+   exit 1
+   EOF
+   chmod +x $PRE_COMMIT 
+   git checkout -b violating-pre-commit master 
+   test_must_fail test_commit pre-commit-violated-1 
+   test_commit --no-verify pre-commit-violated-1 
+   test_must_fail test_commit pre-commit-violated-2 
+   test_commit --no-verify pre-commit-violated-2 
+   test_must_fail test_commit pre-commit-violated-3 
+   test_commit --no-verify pre-commit-violated-3
+'
+
+test_expect_success 'squash commits violating pre-commit' '
+   git checkout -b squash-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=1 squash 2 squash 3 git rebase -i master
+'
+
+test_expect_success 'fixup commits violating pre-commit' '
+   git checkout -b fixup-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=1 fixup 2 fixup 3 git rebase -i master
+'
+
+test_expect_success 'clean up failing pre-commit' '
+   rm $PRE_COMMIT
+'
+
+test_expect_success 'setup failing commit-msg' '
+   HOOKDIR=$(git rev-parse --git-dir)/hooks 
+   mkdir -p $HOOKDIR 
+   COMMIT_MSG=$HOOKDIR/commit-msg 
+   cat $COMMIT_MSG -EOF 
+   #!/bin/sh
+   echo running failing commit-msg...
+   exit 1
+   EOF
+   chmod +x $COMMIT_MSG 
+   git checkout -b violating-commit-msg master 
+   test_must_fail test_commit commit-msg-violated-1 
+   test_commit --no-verify commit-msg-violated-1 
+   test_must_fail test_commit commit-msg-violated-2 
+   test_commit --no-verify commit-msg-violated-2 
+   test_must_fail test_commit commit-msg-violated-3 
+   test_commit --no-verify commit-msg-violated-3
+'
+
+test_expect_success 'rebase a commit violating commit-msg' '
+   git checkout -b rebase-violating-commit-msg violating-commit-msg 
+   set_fake_editor 
+   FAKE_LINES=1 git rebase -i master
+'
+
+test_expect_success 'squash commits violating commit-msg' '
+   git checkout -b squash-violating-commit-msg violating-commit-msg 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=1 squash 2 squash 3 git rebase -i 
master 
+   git commit --no-verify --amend 
+   git rebase --continue
+'
+
+test_expect_success 'fixup commits violating commit

[PATCH v3 02/27] rebase -i: allow squashing empty commits without complaints

2014-08-18 Thread Fabian Ruch
The to-do list commands `squash` and `fixup` apply the changes
introduced by the named commit to the tree but instead of creating
a new commit on top of the current head it replaces the previous
commit with a new commit that records the updated tree. If the
result is an empty commit git-rebase stops with the error message

   You asked to amend the most recent commit, but doing so would make
   it empty. You can repeat your command with --allow-empty, or you can
   remove the commit entirely with git reset HEAD^.

This message is not very helpful because neither does git-rebase
support an option `--allow-empty` nor does the messages say how to
resume the rebase. Firstly, change the error message to

   The squash result is empty and --keep-empty was not specified.

   You can remove the squash commit now with

 git reset HEAD^

   Once you are done, run

 git rebase --continue

If the user wishes to squash a sequence of commits into one
commit, f. i.

   pick A
   squash Revert A
   squash A'

, it does not matter for the end result that the first squash
result, or any sub-sequence in general, is going to be empty. The
squash message is not affected at all by which commits are created
and only the commit created by the last line in the sequence will
end up in the final history. Secondly, print the error message
only if the whole squash sequence produced an empty commit.

Lastly, since an empty squash commit is not a failure to rewrite
the history as planned, issue the message above as a mere warning
and interrupt the rebase with the return value zero. The
interruption should be considered as a notification with the
chance to undo it on the spot. Specifying the `--keep-empty`
option tells git-rebase to keep empty squash commits in the
rebased history without notification.

Add tests.

Reported-by: Peter Krefting pe...@softwolves.pp.se
Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 20 +++---
 t/t3404-rebase-interactive.sh | 62 +++
 2 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3222bf6..ada340c 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -549,7 +549,7 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   do_with_author output git commit --allow-empty-message \
+   do_with_author output git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
@@ -558,18 +558,32 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --allow-empty-message 
\
+   do_with_author git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author git commit --amend --no-verify 
-F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author git commit --allow-empty --amend 
--no-verify -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
rm -f $squash_msg $fixup_msg
+   if test -z $keep_empty  is_empty_commit HEAD
+   then
+   echo $sha1 $state_dir/stopped-sha
+   warn The squash result is empty and 
--keep-empty was not specified.
+   warn
+   warn You can remove the squash commit now with
+   warn
+   warn   git reset HEAD^
+   warn
+   warn Once you are done, run
+   warn
+   warn   git rebase --continue
+   exit 0
+   fi
;;
esac
record_in_rewritten $sha1
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9c71835..a95cb2a

[PATCH v3 05/27] rebase -i: hide interactive command messages in verbose mode

2014-08-18 Thread Fabian Ruch
git-rebase--interactive prints summary messages of the commits it
creates in the final history only if the `--verbose` option is
specified by the user and suppresses them otherwise. This behaviour
is implemented by wrapping git-commit calls in a shell function named
`output` which redirects stderr to stdout, captures stdout in a shell
variable and ignores its contents unless the command exits with an
error status.

The command lines used to implement the to-do list commands `reword`
and `squash` print diagnostic messages even in non-verbose mode. The
reason for this inconsistency is that both commands launch the log
message editor `GIT_EDITOR` which usually requires a working terminal
attached to stdin. Wrapping the `reword` and `squash` command lines
in `output` would seemingly freeze the terminal (see commit 7725cb5,
rebase -i: fix reword when using a terminal editor). Temporarily
redirect the `GIT_EDITOR` output to a third file descriptor in order
to ship it around the capture stream. Wrap the remaining git-commit
command lines in the new `output`. At the moment, it is still no
alternative to pass the `--quiet` option in non-verbose mode because
git-merge-recursive for instance prints some messages regardless of
the verbosity level.

In order to temporarily redirect the editor output, the new
definition of `output` creates a wrapper script in the state
directory to be used as `GIT_EDITOR`. Make sure the state directory
exists before `output` is called for the first time.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh |  9 +
 git-rebase.sh  | 13 +++--
 t/t3406-rebase-message.sh  | 18 ++
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index eb1dcda..cebe742 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
warn This is most likely due to an empty commit 
message, or the pre-commit hook
warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
@@ -558,14 +558,14 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --allow-empty-message 
--allow-empty \
+   do_with_author output git commit 
--allow-empty-message --allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author git commit --allow-empty --amend 
--no-verify -F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author output git commit --allow-empty 
--amend --no-verify -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
@@ -923,6 +923,8 @@ EOF
;;
 esac
 
+mkdir -p $state_dir || die Could not create temporary $state_dir
+
 git var GIT_COMMITTER_IDENT /dev/null ||
die You need to set your committer info first
 
@@ -938,7 +940,6 @@ then
 fi
 
 orig_head=$(git rev-parse --verify HEAD) || die No HEAD?
-mkdir -p $state_dir || die Could not create temporary $state_dir
 
 :  $state_dir/interactive || die Could not mark as interactive
 write_basic_state
diff --git a/git-rebase.sh b/git-rebase.sh
index 55da9db..46141b8 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -131,9 +131,18 @@ write_basic_state () {
 output () {
case $verbose in
'')
-   output=$($@ 21 )
+   cat $state_dir/editor.sh -EOF
+   #!/bin/sh
+   $(git var GIT_EDITOR) \$@ 3
+   EOF
+   chmod +x $state_dir/editor.sh
+   (
+   GIT_EDITOR=$(git rev-parse --sq-quote 
$state_dir/editor.sh)
+   export GIT_EDITOR
+   $@ 31 1$state_dir/output 21
+   )
status=$?
-   test $status != 0  printf %s\n $output
+   test $status != 0  cat $state_dir/output
return $status

[PATCH v3 06/27] rebase -i: discard redundant message when rewording fails

2014-08-18 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If the edited log
message is empty or is found ill-formatted by one of the commit
hooks, git-rebase--interactive prints three error messages to the
console.

1. The git-commit output, which contains all the output from hook
   scripts.
2. A rebase diagnosis saying at which task on the to-do list it
   got stuck.
3. Generic presumptions about what could have triggered the
   error.

The third message contains redundant information and does not add any
enlightenment either, which makes the output unnecessarily longish
and different from the other commands' output. For instance, this is
what the output looks like if the log message is empty (contains
duplicate Signed-off-by lines).

(1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by 
lines.)
(2.) Could not amend commit after successfully picking fa1afe1... Some 
change
(3.) This is most likely due to an empty commit message, or the pre-commit 
hook
 failed. If the pre-commit hook failed, you may need to resolve the 
issue before
 you are able to reword the commit.

Discard the third message.

It is true that a failed hook script might not output any diagnosis
but then the generic message is not of much help either. Since this
lack of information affects the built-in git commands for commit,
merge and cherry-pick first, the solution would be to keep track of
the failed hooks in their output so that the user knows which of her
hooks require improvement.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index cebe742..cf62daa 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -506,9 +506,6 @@ do_next () {
do_pick $sha1 $rest
output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
-   warn This is most likely due to an empty commit 
message, or the pre-commit hook
-   warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
-   warn you are able to reword the commit.
exit_with_patch $sha1 1
}
record_in_rewritten $sha1
-- 
2.0.1

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


[PATCH v3 25/27] rebase -i: do not overwrite user author information

2014-08-18 Thread Fabian Ruch
The shell function `get_author_ident_from_commit` defined by
git-sh-setup retrieves the author information from the named commit
and returns assignments of the environment variables

GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_DATE

ready for evaluation by the shell.

This interface is used in conjunction with the so-called author
script which is a git-rebase--interactive state file that contains
the `get_author_ident_from_commit` output. It is sourced when `git
rebase --continue` is executed after conflict resolution to retain
the original commit authorship.

The variable assignments are only exported by the subshell that
executes the git-commit command line that commits the resolved
conflicts. That is taken care of by wrapping the git-commit call in
`do_with_author`. However, this is not enough protection from
modifying the git environment variables unintentionally because the
user running git-rebase could have already exported those herself.
And therefore, a bare git-commit could result in an authorship that
is neither intended by the user nor by git-rebase--interactive.

While it is not an issue now (either `do_with_author`,
git-cherry-pick or `--amend` are used to create commits), the
unnecessary loss of the author name and e-mail copied from the user
environment, and the unneeded fixing of the author date might become
a problem when we decide to support something similar to
`--reset-author` or `--ignore-date in interactive git-rebase.

Do not assign the git environment variables until in the
`do_with_author` subshell.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 73c97a1..8fbfe6d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -166,7 +166,7 @@ make_patch () {
test -f $msg ||
commit_message $1  $msg
test -f $author_script ||
-   get_author_ident_from_commit $1  $author_script
+   echo $1  $author_script
 }
 
 die_with_patch () {
@@ -215,9 +215,13 @@ is_merge_commit()
 }
 
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
-# GIT_AUTHOR_DATE exported from the current environment.
+# GIT_AUTHOR_DATE assigned the author information extracted from the
+# named commit and exported.
 do_with_author () {
(
+   sha1=$1
+   shift
+   eval $(get_author_ident_from_commit $sha1)
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
$@
)
@@ -348,13 +352,11 @@ pick_one_preserving_merges () {
test a$1 = a-n  die Refusing to squash a merge: 
$sha1
 
# redo merge
-   author_script_content=$(get_author_ident_from_commit 
$sha1)
-   eval $author_script_content
msg_content=$(commit_message $sha1)
# No point in merging the first parent, that's HEAD
new_parents=${new_parents# $first_parent}
merge_args=--no-log --no-ff
-   if ! do_with_author output eval \
+   if ! do_with_author $sha1 output eval \
'git merge ${gpg_sign_opt:+$gpg_sign_opt} \
$merge_args $strategy_args -m $msg_content 
$new_parents'
then
@@ -592,8 +594,7 @@ do_pick () {
do_with_author=
if test -z $rewrite_reset_author  test -z $rewrite_amend
then
-   eval $(get_author_ident_from_commit $1)
-   do_with_author=do_with_author
+   do_with_author=do_with_author $1
fi
$do_with_author output git commit \
   --allow-empty --no-post-rewrite -n --no-edit \
@@ -1041,9 +1042,9 @@ first and then run 'git rebase --continue' again.
${gpg_sign_opt:+$gpg_sign_opt} ||
die Could not commit staged changes.
else
-   . $author_script ||
+   test -r $author_script ||
die Error trying to find the author identity 
to amend commit
-   do_with_author git commit --no-verify -F $msg -e \
+   do_with_author $(cat $author_script) git commit 
--no-verify -F $msg -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die Could not commit staged changes.
fi
-- 
2.0.1

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


[PATCH v3 24/27] rebase -i: teach do_pick the option --signoff

2014-08-18 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is currently used to implement most of the to-do list commands
and offers additional options that will eventually find their way
onto to-do lists.

To extend the repertoire of available options, add the git-commit and
git-cherry-pick option `--signoff` to the `do_pick` interface. It
appends a Signed-off-by: line using the committer identity to the log
message of the picked commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 6c75bc5..73c97a1 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,15 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
+# do_pick [--signoff] [--reset-author] [--amend] [--file file]
+# [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# -s, --signoff
+# Insert a Signed-off-by: line using the committer identity at the
+# end of the commit log message. This creates a fresh commit.
+#
 # --reset-author
 # Pretend the changes were made for the first time. Declare that the
 # authorship of the resulting commit now belongs to the committer.
@@ -504,6 +509,7 @@ record_in_rewritten() {
 do_pick () {
allow_empty_message=y
rewrite=
+   rewrite_signoff=
rewrite_reset_author=
rewrite_amend=
rewrite_edit=
@@ -511,6 +517,10 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   -s|--signoff)
+   rewrite=y
+   rewrite_signoff=y
+   ;;
--reset-author)
rewrite=y
rewrite_reset_author=y
@@ -588,6 +598,7 @@ do_pick () {
$do_with_author output git commit \
   --allow-empty --no-post-rewrite -n --no-edit \
   ${allow_empty_message:+--allow-empty-message} \
+  ${rewrite_signoff:+--signoff} \
   ${rewrite_amend:+--amend 
${rewrite_reset_author:+--reset-author}} \
   ${rewrite_edit:+--edit --commit-msg} \
   ${rewrite_message:+--file $rewrite_message} \
-- 
2.0.1

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


[PATCH v3 23/27] rebase -i: teach do_pick the option --reset-author

2014-08-18 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement many of the to-do list commands.
Eventually, the complete `do_pick` interface will be exposed to the
user in some form or another and those commands will become simple
aliases for the `do_pick` options now used to implement them.

Add the git-commit option `--reset-author` to the options pool of
`do_pick`. It rewrites the author date and name of the picked commit
to match the committer date and name.

If `--reset-author` is passed to `do_pick`, set the `rewrite` flag
and relay the option to the git-commit command line which creates the
final commit. If `--amend` is not passed as well, the fresh
authorship effect is achieved by the mere fact that we are creating a
new commit. Do not even source the ident information in that case
because the user shell might have already exported the respective
environment variables.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 26 ++
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8b39f2d..6c75bc5 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,18 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--file file] [--edit] commit
+# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --reset-author
+# Pretend the changes were made for the first time. Declare that the
+# authorship of the resulting commit now belongs to the committer.
+# This also renews the author timestamp. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # --amend
 # After picking commit, replace the current head commit with a new
 # commit that also introduces the changes of commit.
@@ -496,12 +504,17 @@ record_in_rewritten() {
 do_pick () {
allow_empty_message=y
rewrite=
+   rewrite_reset_author=
rewrite_amend=
rewrite_edit=
rewrite_message=
while test $# -gt 0
do
case $1 in
+   --reset-author)
+   rewrite=y
+   rewrite_reset_author=y
+   ;;
--amend)
if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse -q --verify HEAD /dev/null
then
@@ -566,11 +579,16 @@ do_pick () {
 
if test -n $rewrite
then
-   eval $(get_author_ident_from_commit $1)
-   do_with_author output git commit \
+   do_with_author=
+   if test -z $rewrite_reset_author  test -z $rewrite_amend
+   then
+   eval $(get_author_ident_from_commit $1)
+   do_with_author=do_with_author
+   fi
+   $do_with_author output git commit \
   --allow-empty --no-post-rewrite -n --no-edit \
   ${allow_empty_message:+--allow-empty-message} \
-  ${rewrite_amend:+--amend} \
+  ${rewrite_amend:+--amend 
${rewrite_reset_author:+--reset-author}} \
   ${rewrite_edit:+--edit --commit-msg} \
   ${rewrite_message:+--file $rewrite_message} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
-- 
2.0.1

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


[PATCH v3 27/27] rebase -i: enable --signoff, --reset-author for pick, reword, edit

2014-08-18 Thread Fabian Ruch
Lift the general unknown option blockade for the `pick`, `reword` and
`edit` commands. If `do_cmd` comes across one of the options
`--signoff` and `--reset-author` while parsing a to-do entry and the
scheduled command is either `pick` or `reword`, relay the option to
`do_pick`.

Remember to add Signed-off-by: and to reset the authorship even when
the rebase is interrupted for conflict resolution and `git rebase
--continue` creates the commit. Employ the same mechanism that is
used to remember amending an interim squash commit after conflict
resolution or a commit after editing. If a line option was specified,
create the files `signoff` and `resetauthor` respectively in the
state directory. While `signoff` is handled by simply specifying the
`--signoff` option when creating the commit, the `resetauthor` case
is somewhat more involved. The author script contains the author
information of the replayed commit. Renewing the authorship means
using the user environment for the authorship so that we need to skip
the author script if `resetauthor` exists and we are not amending. If
we are amending, `--reset-author` must be passed to git-commit
because otherwise the authorship of HEAD would be used.

`do_pick` options like `--gpg-sign` and `--file` are not yet
supported because `do_cmd` cannot handle option arguments and options
with spaces at the moment. `squash` and `fixup` still do not accept
user options as the interplay of `--reset-author` and the author
script is yet to be determined.

Document the new options by listing them in the to-do help and giving
a usage example in the INTERACTIVE MODE section of the git-rebase
man page.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 Documentation/git-rebase.txt   |  13 +++
 git-rebase--interactive.sh |  38 +++-
 t/t3427-rebase-line-options.sh | 192 -
 3 files changed, 240 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 2a93c64..10c0fd2 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -508,6 +508,19 @@ rebasing.
 If you just want to edit the commit message for a commit, replace the
 command pick with the command reword.
 
+The commands pick, reword and edit understand some well-known
+options. To add a Signed-off-by line at the end of the commit
+message, pass the `--signoff` option. The authorship can be renewed
+by specifying the `--reset-author` option. For instance, before you
+decide to publish a heavily edited commit you might want to reset the
+authorship and add your signature. You can do so on a per line basis:
+
+---
+pick deadbee The oneline of this commit
+pick --reset-author --signoff fa1afe1 The oneline of the next commit
+...
+---
+
 If you want to fold two or more commits into one, replace the command
 pick for the second and subsequent commits with squash or fixup.
 If the commits had different authors, the folded commit will be
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 51ee80c..0db5001 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -72,9 +72,15 @@ last_head=$state_dir/last_head
 # file 'amend' is created. When git rebase --continue is executed,
 # if there are any staged changes then they will be amended to the
 # HEAD commit, but only provided the HEAD commit is still the commit
-# to be edited or the squash commit. When any other rebase command is
+# to be edited or the squash commit. Similarly, when a Signed-off-by:
+# should be added to a log message or the authorship should be
+# renewed, the files 'signoff' and 'resetauthor' are created
+# respectively, and git rebase --continue carries out the changes
+# after conflict resolution. When any other rebase command is
 # processed, these files are deleted.
 amend=$state_dir/amend
+signoff=$state_dir/signoff
+resetauthor=$state_dir/resetauthor
 
 # For the post-rewrite hook, we make a list of rewritten commits and
 # their new sha1s.  The rewritten-pending list keeps the sha1s of
@@ -149,6 +155,10 @@ Commands:
  f, fixup = like squash, but discard this commit's log message
  x, exec = run command (the rest of the line) using shell
 
+Options:
+ [pick | reword | edit] --signoff = add a Signed-off-by line
+ [pick | reword | edit] --reset-author = renew authorship
+
 These lines can be re-ordered; they are executed from top to bottom.
 
 If you remove a line here THAT COMMIT WILL BE LOST.
@@ -528,10 +538,12 @@ do_pick () {
-s|--signoff)
rewrite=y
rewrite_signoff=y
+   $signoff
;;
--reset-author)
rewrite=y
rewrite_reset_author=y
+   $resetauthor
;;
--amend

[PATCH v3 07/27] commit: allow disabling pre-commit and commit-msg separately

2014-08-18 Thread Fabian Ruch
Introduce the git-commit command line options `--no-pre-commit` and
`--no-commit-msg` to disable the pre-commit and commit-msg hooks,
respectively. Make `--no-verify` a synonym for specifying both at the
same time.

This change is motivated by an internal usage of git-commit in
git-rebase--interactive to disable pre-commit while keeping
commit-msg enabled when rewording a commit.

Make `test_commit` forward unknown options to git-commit instead of
teaching it all possible options. In order to support leading double
dashes in `message`, stop interpreting `test_commit` arguments
following a `--` argument as options. This wasn't a problem before
because the first unknown option would be used as `message`.

Allow disabling tag creation to avoid name clashes when using
`test_commit` with the same arguments several times from the same
test suite. By default, `test_commit` tags successful commits using
git-tag for easy reference. The `--notag` option skips this step.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 Documentation/git-commit.txt |  8 -
 builtin/commit.c | 32 ++---
 t/t7503-pre-commit-hook.sh   | 65 -
 t/t7504-commit-msg-hook.sh   | 85 ++--
 t/test-lib-functions.sh  | 23 
 5 files changed, 176 insertions(+), 37 deletions(-)

diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 0bbc8f5..28a2c5c 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -158,7 +158,7 @@ OPTIONS
 
 -n::
 --no-verify::
-   This option bypasses the pre-commit and commit-msg hooks.
+   A synonym for `--no-pre-commit --no-commit-msg`.
See also linkgit:githooks[5].
 
 --allow-empty::
@@ -238,6 +238,12 @@ You should understand the implications of rewriting 
history if you
 amend a commit that has already been published.  (See the RECOVERING
 FROM UPSTREAM REBASE section in linkgit:git-rebase[1].)
 
+--no-pre-commit::
+   This option bypasses the pre-commit hook.
+
+--no-commit-msg::
+   This option bypasses the commit-msg hook.
+
 --no-post-rewrite::
Bypass the post-rewrite hook.
 
diff --git a/builtin/commit.c b/builtin/commit.c
index 5ed6036..dfd354e 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -98,12 +98,27 @@ static char *edit_message, *use_message;
 static char *fixup_message, *squash_message;
 static int all, also, interactive, patch_interactive, only, amend, signoff;
 static int edit_flag = -1; /* unspecified */
-static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
+static int quiet, verbose, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
 static char *sign_commit;
 
 /*
+ * The verify variable is interpreted as a bitmap of enabled commit
+ * verification hooks according to the legend below.
+ *
+ * By default, the pre-commit and commit-msg hooks are enabled. This
+ * is represented by both the PRE_COMMIT and COMMIT_MSG bits being
+ * set.
+ *
+ * The bitmap is changed through the command line options
+ * --no-verify, --no-pre-commit and --no-commit-msg.
+ */
+#define PRE_COMMIT (10)
+#define COMMIT_MSG (11)
+static int verify = PRE_COMMIT | COMMIT_MSG;
+
+/*
  * The default commit message cleanup mode will remove the lines
  * beginning with # (shell comments) and leading and trailing
  * whitespaces (empty lines or containing only whitespaces)
@@ -661,7 +676,8 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
/* This checks and barfs if author is badly specified */
determine_author_info(author_ident);
 
-   if (!no_verify  run_commit_hook(use_editor, index_file, pre-commit, 
NULL))
+   if (verify  PRE_COMMIT 
+   run_commit_hook(use_editor, index_file, pre-commit, NULL))
return 0;
 
if (squash_message) {
@@ -962,7 +978,7 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
}
}
 
-   if (!no_verify 
+   if (verify  COMMIT_MSG 
run_commit_hook(use_editor, index_file, commit-msg, 
git_path(commit_editmsg), NULL)) {
return 0;
}
@@ -1590,7 +1606,9 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
OPT_BOOL(0, interactive, interactive, N_(interactively add 
files)),
OPT_BOOL('p', patch, patch_interactive, N_(interactively 
add changes)),
OPT_BOOL('o', only, only, N_(commit only specified files)),
-   OPT_BOOL('n', no-verify, no_verify, N_(bypass pre-commit 
hook)),
+   OPT_NEGBIT('n', no-verify, verify,
+  N_(synonym for --no-pre-commit --no-commit-msg),
+  PRE_COMMIT | COMMIT_MSG),
OPT_BOOL(0, dry-run, dry_run, N_(show what would be 
committed

[PATCH v3 16/27] rebase -i: teach do_pick the option --amend

2014-08-18 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list commands `pick`, `reword`
and `edit`. To cater for the different pick behaviours (like
`squash`), `do_pick` accepts several options not only from the
git-cherry-pick but also the git-commit interface.

Add the option `--amend` from the git-commit interface to the options
pool of `do_pick`. It creates a new commit for the changes introduced
by the picked commit and the previous one. The previous commit is
then replaced with the new commit. If no other options are specified,
the log message of the previous commit is used.

Be careful when `--amend` is used to pick a root commit because HEAD
might point to the sentinel commit but there is still nothing to
amend. Be sure to initialize `amend` so that commits are squashed
even when git-rebase--interactive is interrupted for resolving
conflicts. It is not a mistake to do the initialization regardless of
any conflicts because `amend` is always cleared before the next to-do
item is processed.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index a5a8aa3..20a637a 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,16 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit
+# do_pick [--amend] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --amend
+# After picking commit, replace the current head commit with a new
+# commit that also introduces the changes of commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -489,6 +495,16 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   --amend)
+   if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse -q --verify HEAD /dev/null
+   then
+   warn do_pick: nothing to amend
+   return 2
+   fi
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
-- 
2.0.1

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


[PATCH v3 09/27] rebase -i: do not verify reworded patches using pre-commit

2014-08-18 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. This happens in two
steps. Firstly, the named commit is cherry-picked. Secondly, the
commit created in the first step is amended using an unchanged index
to edit the log message. The pre-commit hook is meant to verify the
changes introduced by a commit (for instance, catching inserted
trailing white space). Since the committed tree is not changed
between the two steps and we do not verify rebased patches, do not
execute the pre-commit hook in the second step.

Specify the git-commit option `--no-pre-commit` to disable the
pre-commit hook when editing the log message. The commit-msg hook
will still be executed to verify the edited commit log message. As
before, if the hook finds the new log message ill-formatted, the
rebase will be interrupted with the unchanged commit replayed and the
new log message in `$GIT_DIR/COMMIT_EDITMSG`.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 14 ++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 54c4614..570c4e9 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
exit_with_patch $sha1 1
}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index abb829e..ecdab11 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -683,6 +683,13 @@ test_expect_success 'setup failing pre-commit' '
test_commit --no-verify pre-commit-violated-3
 '
 
+test_expect_success 'reword a commit violating pre-commit' '
+   git checkout -b reword-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=reword 1 git rebase -i master
+'
+
 test_expect_success 'squash commits violating pre-commit' '
git checkout -b squash-violating-pre-commit violating-pre-commit 
test_when_finished reset_rebase 
@@ -726,6 +733,13 @@ test_expect_success 'rebase a commit violating commit-msg' 
'
FAKE_LINES=1 git rebase -i master
 '
 
+test_expect_success 'reword a commit violating commit-msg' '
+   git checkout -b reword-violating-commit-msg violating-commit-msg 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=reword 1 git rebase -i master
+'
+
 test_expect_success 'squash commits violating commit-msg' '
git checkout -b squash-violating-commit-msg violating-commit-msg 
set_fake_editor 
-- 
2.0.1

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


[PATCH v3 26/27] rebase -i: refuse to commit when resuming with updated head

2014-08-18 Thread Fabian Ruch
If git-rebase--interactive fails to apply the changes introduced by a
commit due to conflicts, it interrupts the rebase process and gives
the user a shell to resolve the conflicts manually. The process is
resumed when the user executes `git rebase --continue`. If the index
has changes, the script assumes that those are to be committed under
the authorship and with the log message of the commit it tried to
replay last. However, that assumption is most likely incorrect if the
user has already committed the resolved changes herself. To prevent
committing unrelated changes under the wrong authorship and with the
wrong log message, at least check that HEAD is still at the same
commit by tracking the hash of the last replayed commit. A similar
check already happens before `git rebase --continue` amends the
previous commit after an `edit` or a conflicted `squash` command.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 35 +--
 t/t3404-rebase-interactive.sh | 12 
 2 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8fbfe6d..51ee80c 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -62,13 +62,18 @@ msgnum=$state_dir/msgnum
 # being rebased.
 author_script=$state_dir/author-script
 
-# When an edit rebase command is being processed, the SHA1 of the
-# commit to be edited is recorded in this file.  The same happens when
-# rewriting a root commit fails, for instance reword.  When git
-# rebase --continue is executed, if there are any staged changes then
-# they will be amended to the HEAD commit, but only provided the HEAD
-# commit is still the commit to be edited.  When any other rebase
-# command is processed, this file is deleted.
+# This file keeps track of the SHA1 of the last replayed commit, the
+# new parent of the next commit being replayed. It is used to make
+# sure that git rebase --continue only commits resolved conflicts
+# or edit changes automatically.
+last_head=$state_dir/last_head
+
+# When an edit or a squash rebase command is being processed, the
+# file 'amend' is created. When git rebase --continue is executed,
+# if there are any staged changes then they will be amended to the
+# HEAD commit, but only provided the HEAD commit is still the commit
+# to be edited or the squash commit. When any other rebase command is
+# processed, these files are deleted.
 amend=$state_dir/amend
 
 # For the post-rewrite hook, we make a list of rewritten commits and
@@ -179,7 +184,8 @@ die_with_patch () {
 exit_with_patch () {
echo $1  $state_dir/stopped-sha
make_patch $1
-   git rev-parse --verify HEAD  $amend
+   $amend
+   git rev-parse --verify HEAD $last_head
gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)}
warn You can amend the commit now, with
warn
@@ -535,7 +541,7 @@ do_pick () {
fi
rewrite=y
rewrite_amend=y
-   git rev-parse --verify HEAD $amend
+   $amend
;;
-F|--file)
if test $# -eq 0
@@ -572,7 +578,7 @@ do_pick () {
then
rewrite=y
rewrite_amend=y
-   git rev-parse --verify HEAD $amend
+   $amend
 
# Set the correct commit message and author info on the
# sentinel root before cherry-picking the original changes
@@ -734,6 +740,7 @@ do_replay () {
 
 do_next () {
rm -f $msg $author_script $amend || exit
+   git rev-parse --verify HEAD $last_head || exit
read -r command args $todo
 
case $command in
@@ -1031,13 +1038,13 @@ In both case, once you're done, continue with:
   git rebase --continue
 
fi
-   if test -f $amend
-   then
-   current_head=$(git rev-parse --verify HEAD)
-   test $current_head = $(cat $amend) ||
+   current_head=$(git rev-parse --verify HEAD)
+   test $current_head = $(cat $last_head) ||
die \
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again.
+   if test -f $amend
+   then
git commit --amend --no-verify -F $msg -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die Could not commit staged changes.
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index c037a07..5955bd8 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -444,6 +444,18 @@ test_expect_success '--continue tries to commit' '
git show HEAD | grep chouette
 '
 
+test_expect_success '--continue does not commit

[PATCH v3 18/27] rebase -i: remove no-op do_with_author git commit --amend

2014-08-18 Thread Fabian Ruch
The author script is a file in the state directory that contains
assignments of the environment variables

GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_DATE

to be evaluated by the shell. It is used to store author information
and has two applications in `git-rebase--interactive.sh`. Firstly,
the authorship of squash commits is read from it while the squash
commit is being amended step by step. Secondly, after conflict
resolution `git rebase --continue` restores the author information of
the original commit by sourcing the author script. For the
assignments of the git environment variables to take effect,
git-rebase--interactive executes the respective git-commit commands
wrapped in `do_with_author`. That shell function executes the named
command in a subshell that exports the git environment variables.

Since

git commit --amend

has been used instead of

git reset --soft HEAD^
git commit

to amend squash commits, wrapping git-commit in `do_with_author` has
become a no-op because, unless the `--reset-author` option is
specified, `git commit --amend` ignores the user environment and
reuses the authorship of the commit it amends. To make the code
clearer and until we decide to use other authorships for squash
commits than the one of the first commit, unwrap `git commit
--amend`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 17 +++--
 t/t3404-rebase-interactive.sh | 23 +++
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index f8be238..ab807e5 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -622,9 +622,6 @@ do_next () {
 
mark_action_done
update_squash_messages $squash_style $sha1
-   author_script_content=$(get_author_ident_from_commit HEAD)
-   echo $author_script_content  $author_script
-   eval $author_script_content
if ! pick_one -n $sha1
then
git rev-parse --verify HEAD $amend
@@ -634,7 +631,7 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   do_with_author output git commit --allow-empty-message 
--allow-empty \
+   output git commit --allow-empty-message --allow-empty \
--amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
@@ -643,14 +640,14 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author output git commit 
--allow-empty-message --allow-empty \
+   output git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author output git commit --allow-empty 
--amend --no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
+   output git commit --allow-empty --amend 
--no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
@@ -939,7 +936,7 @@ continue)
then
: Nothing to commit -- skip this
else
-   if ! test -f $author_script
+   if ! test -f $author_script  ! test -f $amend
then
gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse 
--sq-quote $gpg_sign_opt)}
die You have staged changes in your working tree. If 
these changes are meant to be
@@ -956,8 +953,6 @@ In both case, once you're done, continue with:
   git rebase --continue
 
fi
-   . $author_script ||
-   die Error trying to find the author identity to amend 
commit
if test -f $amend
then
current_head=$(git rev-parse --verify HEAD)
@@ -965,10 +960,12 @@ In both case, once you're done, continue with:
die \
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again.
-   do_with_author git commit --amend

[PATCH v3 22/27] rebase -i: parse to-do list command line options

2014-08-18 Thread Fabian Ruch
Read in to-do list lines as

command args

instead of

command sha1 rest

so that to-do list command lines can specify additional arguments
apart from the commit hash and the log message title, which become
the non-options in `args`. Loop over `args`, put all options (an
argument beginning with a dash) in `opts`, stop the loop on the first
non-option and assign it to `sha1`. For instance, the to-do list

reword --signoff fa1afe1 Some change

is parsed as `command=reword`, `opts= '--signoff'` (including the
single quotes and the space for evaluation and concatenation of
options), `sha1=fa1afel` and `rest=Some change`. The loop does not
know the options it parses so that options that take an argument
themselves are not supported at the moment. Neither are options that
contain spaces because the shell expansion of `args` in `do_next`
interprets white space characters as argument separator.

Print an error message for unknown or unsupported command line
options, which means an error for all specified options at the
moment. Cleanly break the `do_next` loop by assigning a reason to the
local variable `malformed`, which triggers the unknown command code
in `do_replay`. Move the error code to the beginning of `do_replay`
so that unknown commands are reported before bad options are as only
the first error we come across is reported. For instance, the to-do
list from above produces the error

Unknown 'reword' option: --signoff
Please fix this using 'git rebase --edit-todo'.

The to-do list is also parsed when the commit hashes are translated
between long and short format before and after the to-do list is
edited. Apply the same procedure as in `do_replay` with the exception
that we only care about where the options stop and the commit hash
begins. Do not reject any options when transforming the commit
hashes.

Enable the specification of to-do list command line options in
`FAKE_LINES` the same way this is accomplished for command lines
passed to `exec`. Define a new `fake_editor.sh` that edits a static
to-do list instead of the one passed as argument when invoked by
git-rebase. Add a test case that checks that unknown options are
refused and can be corrected using `--edit-todo`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 95 +++---
 t/lib-rebase.sh| 20 -
 t/t3427-rebase-line-options.sh | 26 
 3 files changed, 114 insertions(+), 27 deletions(-)
 create mode 100755 t/t3427-rebase-line-options.sh

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index e140bf0..8b39f2d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -578,30 +578,71 @@ do_pick () {
 }
 
 do_replay () {
+   malformed=
command=$1
-   sha1=$2
-   rest=$3
+   shift
+   case $command in
+   pick|reword|edit|squash|fixup)
+   ;;
+   *)
+   read -r command $todo
+   malformed=Unknown command: $command
+   ;;
+   esac
+
+   opts=
+   while test $# -gt 0  test -z $malformed
+   do
+   case $1 in
+   -*)
+   malformed=Unknown '$command' option: $1
+   ;;
+   *)
+   break
+   ;;
+   esac
+   opts=$opts $1
+   shift
+   done
+   sha1=$1
+   shift
+   rest=$*
+
+   if test -n $malformed
+   then
+   warn $malformed
+   fixtodo=Please fix this using 'git rebase --edit-todo'.
+   if git rev-parse --verify -q $sha1 /dev/null
+   then
+   die_with_patch $sha1 $fixtodo
+   else
+   die $fixtodo
+   fi
+   fi
 
case $command in
pick|p)
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
+   do_pick --edit $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
edit|e)
comment_for_reflog edit
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
warn Stopped at $sha1... $rest

[PATCH v3 15/27] rebase -i: do not die in do_pick

2014-08-18 Thread Fabian Ruch
Since `do_pick` might be executed in a sub-shell (a modified author
environment for instance), calling `die` in `do_pick` has no effect
but exiting the sub-shell with a failure exit status. The
git-rebase--interactive script is not terminated. Moreover, if
`do_pick` is called while a squash or fixup is in effect,
`die_with_patch` will discard `$squash_msg` as commit message.
Lastly, after a `die` in `do_pick` `do_next` has no chance to
reschedule tasks that failed before changes could be applied.

Indicate an error in `do_pick` using return statements and properly
kill the script at the call sites. Although possible in principle,
the issued error messages are no more indicating whether `do_pick`
failed while applying or while committing the changes. This reduces
code complexity at the call site and does not matter from a user's
point of view because a glance at the index reveals whether there are
conflicts or not and in-depth troubleshooting is still possible using
the `--verbose` option.

Remove the commit message title argument from `do_pick`'s interface,
which has become unused.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 34 +++---
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 181e06a..a5a8aa3 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit title
+# do_pick [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -476,9 +476,11 @@ record_in_rewritten() {
 # commit
 # The commit to cherry-pick.
 #
-# title
-# The commit message title of commit. Used for information
-# purposes only.
+# The return value is 1 if applying the changes resulted in a conflict
+# and 2 if the specified arguments were incorrect. If the changes could
+# be applied successfully but creating the commit failed, a value
+# greater than 2 is returned. No commit is created in either case and
+# the index is left with the (conflicting) changes in place.
 do_pick () {
allow_empty_message=y
rewrite=
@@ -493,7 +495,8 @@ do_pick () {
allow_empty_message=
;;
-*)
-   die do_pick: unrecognized option -- $1
+   warn do_pick: unrecognized option -- $1
+   return 2
;;
*)
break
@@ -501,7 +504,11 @@ do_pick () {
esac
shift
done
-   test $# -ne 2  die do_pick: wrong number of arguments
+   if test $# -ne 1
+   then
+   warn do_pick: wrong number of arguments
+   return 2
+   fi
 
if test $(git rev-parse HEAD) = $squash_onto
then
@@ -519,11 +526,9 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one -n $1 || return 1
else
-   pick_one ${rewrite:+-n} $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one ${rewrite:+-n} $1 || return 1
fi
 
if test -n $rewrite
@@ -534,8 +539,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_with_patch $1 Could not rewrite commit after 
successfully picking $1... $2
+  ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 }
 
@@ -550,21 +554,21 @@ do_next () {
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 $rest
+   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 $rest
+   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
record_in_rewritten $sha1
;;
edit|e)
comment_for_reflog edit
 
mark_action_done
-   do_pick $sha1 $rest
+   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
warn Stopped at $sha1... $rest
exit_with_patch $sha1 0
;;
-- 
2.0.1

--
To unsubscribe from this list: send the line unsubscribe

[PATCH v3 19/27] rebase -i: prepare for squash in terms of do_pick --amend

2014-08-18 Thread Fabian Ruch
Rewrite `squash` and `fixup` handling in `do_next` using the sequence

pick_one
commit

in order to test the correctness of a single `do_squash` or
parameterised `do_pick` and make the subsequent patch reimplementing
`squash` in terms of such a single function more readable.

Do not call `rm -f $GIT_DIR/MERGE_MSG` since it has no effect on
the state after git-rebase--interactive terminates. The option `-F`
makes git-commit ignore `MERGE_MSG` for the log message. If
git-commit succeeds, `MERGE_MSG` is removed, and if it fails,
`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.
In summary, removing `MERGE_MSG` neither influences the squash commit
message nor the file state after git-commit returns.

Moreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch
`$squash_msg` so that it is correct to execute `pick_one` immediately
before git-commit.

Might be squashed into the subsequent commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 21 +++--
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index ab807e5..614579c 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -622,15 +622,15 @@ do_next () {
 
mark_action_done
update_squash_messages $squash_style $sha1
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 $rest
-   fi
case $(peek_next_command) in
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not apply 
$sha1... $rest
+   fi
output git commit --allow-empty-message --allow-empty \
--amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
@@ -640,13 +640,22 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
output git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   rm -f $GIT_DIR/MERGE_MSG
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
output git commit --allow-empty --amend 
--no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
-- 
2.0.1

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


[PATCH v3 17/27] rebase -i: teach do_pick the option --file

2014-08-18 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`, `reword` and
`edit`. To cater for the different pick behaviours (like `squash`),
`do_pick` accepts several options not only from the git-cherry-pick
but also the git-commit interface.

Add the option `--file` from the git-commit interface to the options
pool of `do_pick`. It expects an argument itself which is interpreted
as a file path and takes the commit message from the given file. If
`--file` is passed to `do_pick`, assign the given file path to the
local variable `rewrite_message` and relay the option

--file $rewrite_message

to the git-commit command line which creates the commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 20 +++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 20a637a..f8be238 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--edit] commit
+# do_pick [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -474,6 +474,12 @@ record_in_rewritten() {
 #
 # _This is not a git-cherry-pick option._
 #
+# -F file, --file file
+# Take the commit message from the given file. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -492,6 +498,7 @@ do_pick () {
rewrite=
rewrite_amend=
rewrite_edit=
+   rewrite_message=
while test $# -gt 0
do
case $1 in
@@ -505,6 +512,16 @@ do_pick () {
rewrite_amend=y
git rev-parse --verify HEAD $amend
;;
+   -F|--file)
+   if test $# -eq 0
+   then
+   warn do_pick: option --file specified but no 
file given
+   return 2
+   fi
+   rewrite=y
+   rewrite_message=$2
+   shift
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
@@ -555,6 +572,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
+  ${rewrite_message:+--file $rewrite_message} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 }
-- 
2.0.1

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


[PATCH v3 21/27] rebase -i: explicitly distinguish replay commands and exec tasks

2014-08-18 Thread Fabian Ruch
There are two kinds of to-do list commands available. One kind
replays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that
is) and the other executes a shell command (`exec`). We will call the
first kind replay commands.

The two kinds of tasks are scheduled using different line formats.
Replay commands expect a commit hash argument following the command
name and exec concatenates all arguments to assemble a command line.

Adhere to the distinction of formats by not trying to parse the
`sha1` field unless we are dealing with a replay command. Move the
replay command handling code to a new function `do_replay` which
assumes the first argument to be a commit hash and make no more such
assumptions in `do_next`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 42 --
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 6a123f0..e140bf0 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -577,13 +577,12 @@ do_pick () {
fi
 }
 
-do_next () {
-   rm -f $msg $author_script $amend || exit
-   read -r command sha1 rest  $todo
+do_replay () {
+   command=$1
+   sha1=$2
+   rest=$3
+
case $command in
-   $comment_char*|''|noop)
-   mark_action_done
-   ;;
pick|p)
comment_for_reflog pick
 
@@ -659,6 +658,28 @@ do_next () {
esac
record_in_rewritten $sha1
;;
+   *)
+   read -r command $todo
+   warn Unknown command: $command
+   fixtodo=Please fix this using 'git rebase --edit-todo'.
+   if git rev-parse --verify -q $sha1 /dev/null
+   then
+   die_with_patch $sha1 $fixtodo
+   else
+   die $fixtodo
+   fi
+   ;;
+   esac
+}
+
+do_next () {
+   rm -f $msg $author_script $amend || exit
+   read -r command sha1 rest $todo
+
+   case $command in
+   $comment_char*|''|noop)
+   mark_action_done
+   ;;
x|exec)
read -r command rest  $todo
mark_action_done
@@ -698,14 +719,7 @@ do_next () {
fi
;;
*)
-   warn Unknown command: $command $sha1 $rest
-   fixtodo=Please fix this using 'git rebase --edit-todo'.
-   if git rev-parse --verify -q $sha1 /dev/null
-   then
-   die_with_patch $sha1 $fixtodo
-   else
-   die $fixtodo
-   fi
+   do_replay $command $sha1 $rest
;;
esac
test -s $todo  return
-- 
2.0.1

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


[PATCH v3 13/27] rebase -i: do not use -C when --no-edit is sufficient

2014-08-18 Thread Fabian Ruch
The command line used to recreate root commits uses `-C` to suppress
the log message editor. This is unnecessarily confusing, though,
because that suppression is a secondary effect of the option. The
main purpose of `-C` is to pull the metadata from another commit, but
here we know that this is a no-op, since we are amending a commit
just created from the same data.

At the time `-C` was introduced, git-commit did not yet have a
documented `--no-edit`, and this was a reasonable way to get the
desired behavior. Switch it to use `--no-edit` to make the intended
effect more obvious.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index f4bb822..6561831 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -511,7 +511,7 @@ do_pick () {
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
output git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -C $1 \
+  --amend --no-post-rewrite -n --no-edit \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


[PATCH v3 11/27] rebase -i: implement reword in terms of do_pick

2014-08-18 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If one thinks of `pick`
entries as scheduled `cherry-pick` command lines, then `reword`
becomes an alias for the command line `cherry-pick --edit`. The
porcelain `rebase--interactive` defines a function `do_pick` for
processing the `pick` entries on to-do lists. Reimplement `reword` in
terms of `do_pick --edit`.

If the user picks a commit using the to-do list line

reword fa1afe1 Some change

execute the command `do_pick --edit fa1afe1 Some change` which
carries out exactly the same steps as the case arm for `reword` in
`do_next` so far.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8a89ced..2d768b3 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -546,11 +546,7 @@ do_next () {
comment_for_reflog reword
 
mark_action_done
-   do_pick $sha1 $rest
-   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
-   warn Could not amend commit after successfully picking 
$sha1... $rest
-   exit_with_patch $sha1 1
-   }
+   do_pick --edit $sha1 $rest
record_in_rewritten $sha1
;;
edit|e)
-- 
2.0.1

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


[PATCH v3 14/27] rebase -i: commit only once when rewriting picks

2014-08-18 Thread Fabian Ruch
The options passed to `do_pick` determine whether the picked commit
will be rewritten or not. If the commit gets rewritten, because the
user requested to edit the commit message for instance, let
`pick_one` merely apply the changes introduced by the commit and do
not commit the resulting tree yet. If the commit is replayed as is,
leave it to `pick_one` to recreate the commit (possibly by
fast-forwarding the head). This makes it easier to combine git-commit
options like `--edit` and `--amend` in `do_pick` because
git-cherry-pick does not support `--amend`.

In the case of `--edit`, do not `exit_with_patch` but assign
`rewrite` to pick the changes with `-n`. If the pick conflicts, no
commit is created which we would have to amend when continuing the
rebase. To complete the pick after the conflicts are resolved the
user just resumes with `git rebase --continue`.

git-commit lets the user edit the commit log message by default. We
do not want that for the rewriting git-commit command line because
the default behaviour of git-rebase is exactly the opposite. Pass
`--no-edit` when rewriting a picked commit. An explicit `--edit`
passed to `do_pick` (for instance, when reword is executed) enables
the editor launch again. Similarly, pass `--allow-empty-message`
unless the log message is edited.

If `rebase--interactive` is used to rebase a complete branch onto
some head, `rebase` creates a sentinel commit that requires special
treatment by `do_pick`. Do not finalize the pick here either because
its commit message can be altered as for any other pick. Since the
orphaned root commit gets a temporary parent, it is always rewritten.
Safely use the rewrite infrastructure of `do_pick` to create the
final commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 41 ++---
 t/t3404-rebase-interactive.sh | 10 ++
 2 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 6561831..181e06a 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -63,9 +63,10 @@ msgnum=$state_dir/msgnum
 author_script=$state_dir/author-script
 
 # When an edit rebase command is being processed, the SHA1 of the
-# commit to be edited is recorded in this file.  When git rebase
-# --continue is executed, if there are any staged changes then they
-# will be amended to the HEAD commit, but only provided the HEAD
+# commit to be edited is recorded in this file.  The same happens when
+# rewriting a root commit fails, for instance reword.  When git
+# rebase --continue is executed, if there are any staged changes then
+# they will be amended to the HEAD commit, but only provided the HEAD
 # commit is still the commit to be edited.  When any other rebase
 # command is processed, this file is deleted.
 amend=$state_dir/amend
@@ -479,12 +480,17 @@ record_in_rewritten() {
 # The commit message title of commit. Used for information
 # purposes only.
 do_pick () {
-   edit=
+   allow_empty_message=y
+   rewrite=
+   rewrite_amend=
+   rewrite_edit=
while test $# -gt 0
do
case $1 in
-e|--edit)
-   edit=y
+   rewrite=y
+   rewrite_edit=y
+   allow_empty_message=
;;
-*)
die do_pick: unrecognized option -- $1
@@ -499,6 +505,10 @@ do_pick () {
 
if test $(git rev-parse HEAD) = $squash_onto
then
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+
# Set the correct commit message and author info on the
# sentinel root before cherry-picking the original changes
# without committing (-n).  Finally, update the sentinel again
@@ -509,22 +519,23 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 
-   output git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n --no-edit \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
+   pick_one -n $1 ||
die_with_patch $1 Could not apply $1... $2
else
-   pick_one $1 ||
+   pick_one ${rewrite:+-n} $1 ||
die_with_patch $1 Could not apply $1... $2
fi
 
-   if test -n $edit
+   if test -n $rewrite
then
-   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
-   warn Could not amend commit after successfully picking 
$1... $2

[PATCH v3 20/27] rebase -i: implement squash in terms of do_pick

2014-08-18 Thread Fabian Ruch
The to-do list command `squash` and its close relative `fixup` replay
the changes of a commit like `pick` but do not recreate the commit.
Instead they replace the previous commit with a new commit that also
introduces the changes of the squashed commit. This is roughly like
cherry-picking without committing and using git-commit to amend the
previous commit.

The to-do list

pick   a Some changes
squash b Some more changes

gets translated into the sequence of git commands

git cherry-pick a
git cherry-pick -n b
git commit --amend

and if git-cherry-pick supported `--amend` this would look even more
like the to-do list it is based on

git cherry-pick a
git cherry-pick --amend b.

Since `do_pick` takes care of `pick` entries and the above suggests
`squash` as an alias for `pick --amend`, reimplement `squash` in
terms of `do_pick --amend`. Introduce `$squash_msg` as the commit
message via the `--file` option. When the last commit of a squash
series is processed, the user is asked to review the log message.
Pass `--edit` as additional option in this case. The only difference
in the options passed to git-commit and `do_pick` is the omitted
`--no-verify`. However, `do_pick` does not execute the verification
hooks anyway because it solely replays commits and assumes that they
have been verified before.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 32 ++--
 1 file changed, 6 insertions(+), 26 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 614579c..6a123f0 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -626,39 +626,19 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not apply 
$sha1... $rest
-   fi
-   output git commit --allow-empty-message --allow-empty \
-   --amend --no-verify -F $squash_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_pick --amend -F $squash_msg $sha1 \
+   || die_failed_squash $sha1 $rest
;;
*)
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   output git commit --allow-empty-message 
--allow-empty \
-   --amend --no-verify -F $fixup_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_pick --amend -F $fixup_msg $sha1 \
+   || die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   output git commit --allow-empty --amend 
--no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_pick --amend -F $GIT_DIR/SQUASH_MSG -e 
$sha1 \
+   || die_failed_squash $sha1 $rest
fi
rm -f $squash_msg $fixup_msg
if test -z $keep_empty  is_empty_commit HEAD
-- 
2.0.1

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


[PATCH v3 10/27] rebase -i: teach do_pick the option --edit

2014-08-18 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`. To cater for
the different pick behaviours (like `reword`), `do_pick` accepts
several options not only from the git-cherry-pick but also the
git-commit interface. Add the common option `--edit` to let the user
edit the log message of the named commit.

Loop over `$@` to parse the `do_pick` arguments. Assign the local
variable `edit` if one of the options is `--edit` so that the
remainder of `do_pick` can easily check whether the client code asked
to edit the commit message. If one of the options is unknown, mention
it on the console and `die`. Break the loop on the first non-option
and do some sanity checking to ensure that there exactly two
non-options, which are interpreted by the remainder as `commit` and
`title` like before.

`do_pick` ought to act as a wrapper around `cherry-pick`.
Unfortunately, it cannot just forward `--edit` to the `cherry-pick`
command line. The assembled command line is executed within a command
substitution for controlling the verbosity of `rebase--interactive`.
Passing `--edit` would either hang the terminal or clutter the
substituted command output with control sequences. Execute the
`reword` code from `do_next` instead if the option `--edit` is
specified.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 570c4e9..8a89ced 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -461,7 +461,42 @@ record_in_rewritten() {
esac
 }
 
+# Apply the changes introduced by the given commit to the current head.
+#
+# do_pick [--edit] commit title
+#
+# Wrapper around git-cherry-pick.
+#
+# -e, --edit
+# After picking commit, open an editor and let the user edit the
+# commit message. The editor contents becomes the commit message of
+# the new head. This creates a fresh commit.
+#
+# commit
+# The commit to cherry-pick.
+#
+# title
+# The commit message title of commit. Used for information
+# purposes only.
 do_pick () {
+   edit=
+   while test $# -gt 0
+   do
+   case $1 in
+   -e|--edit)
+   edit=y
+   ;;
+   -*)
+   die do_pick: unrecognized option -- $1
+   ;;
+   *)
+   break
+   ;;
+   esac
+   shift
+   done
+   test $# -ne 2  die do_pick: wrong number of arguments
+
if test $(git rev-parse HEAD) = $squash_onto
then
# Set the correct commit message and author info on the
@@ -483,6 +518,14 @@ do_pick () {
pick_one $1 ||
die_with_patch $1 Could not apply $1... $2
fi
+
+   if test -n $edit
+   then
+   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
+   warn Could not amend commit after successfully picking 
$1... $2
+   exit_with_patch $1 1
+   }
+   fi
 }
 
 do_next () {
-- 
2.0.1

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


[PATCH v3 12/27] rebase -i: log the replay of root commits

2014-08-18 Thread Fabian Ruch
The command line used to recreate root commits specifies the option
`-q` which suppresses the commit summary message. However,
git-rebase--interactive tends to tell the user about the commits it
creates in the final history, if she wishes (cf. command line option
`--verbose`). The code parts handling non-root commits and squash
commits all output commit summary messages. Do not make the replay of
root commits an exception. Remove the option to make the report of
the rebased history complete. Do not forget to wrap the git-commit
command line in `output` so that the summary is shown if git-rebase
is called with the `--verbose` option but suppressed otherwise.

It is OK that the commit summary is still suppressed when git-commit
is used to initialize the authorship of the sentinel commit because
this additional commit is an implementation detail hidden from the
final history. The removed `-q` option was probably introduced as a
copy-and-paste error stemming from that part of the root commit
handling code.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 2d768b3..f4bb822 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -510,8 +510,8 @@ do_pick () {
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
-   git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -q -C $1 \
+   output git commit --allow-empty --allow-empty-message \
+  --amend --no-post-rewrite -n -C $1 \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword

2014-08-14 Thread Fabian Ruch
Hi,

Michael Haggerty writes:
 On 08/07/2014 01:59 AM, Fabian Ruch wrote:
 Lift the general unknown option blockade for the pick and reword
 commands. If `do_cmd` comes across one of the options `--signoff` and
 `--reset-author` while parsing a to-do entry and the scheduled
 command is either `pick` or `reword`, relay the option to `do_pick`.
 
 The new user-exposed options should be documented in the git-rebase(1)
 manpage and probably also in the help text that is appended to every
 rebase -i todo list.

The next reroll will add the following paragraph to the git-rebase man
page right after the introduction of the 'reword' command in the section
INTERACTIVE MODE:

 The commands pick and reword understand some well-known options.
 To add a Signed-off-by line at the end of the commit message, pass
 the `--signoff` option. The authorship can be renewed by specifying
 the `--reset-author` option. For instance, before you decide to
 publish a heavily edited commit you might want to reset the
 authorship and add your signature. You can do so on a per line basis:
 
 ---
 pick deadbee The oneline of this commit
 pick --reset-author --signoff fa1afe1 The oneline of the next commit
 ...
 ---

By saying heavily edited commit I tried to describe a commit that has
been amended, reworded and reordered in such a way that the actual
author information has become meaningless.

The help text at the end of every to-do list would look like this:

 Commands:
  p, pick = use commit
  r, reword = use commit, but edit the commit message
  e, edit = use commit, but stop for amending
  s, squash = use commit, but meld into previous commit
  f, fixup = like squash, but discard this commit's log message
  x, exec = run command (the rest of the line) using shell
 
 Options:
  [pick | reword] --signoff = add a Signed-off-by line
  [pick | reword] --reset-author = renew authorship
 
 These lines can be re-ordered; they are executed from top to bottom.
 
 If you remove a line here THAT COMMIT WILL BE LOST.

New about this is the Options headline.

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


Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword

2014-08-12 Thread Fabian Ruch
Hi Thomas,

Thomas Rast writes:
 Fabian Ruch baf...@gmail.com writes:
 @@ -634,21 +644,24 @@ do_replay () {
  comment_for_reflog pick
  
  mark_action_done
 -do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
 $rest
 +eval do_pick $opts $sha1 \
 +|| die_with_patch $sha1 Could not apply $sha1... $rest
 
 You had me a little puzzled at the switch to 'eval' here.  That is
 necessary to match the quoting added in 20/23, not for any change in
 this commit.  This commit is simply the first one to trigger this.

This patch switches to 'eval' here because it is the first time
'opts' occurs. However, I agree that it might be confusing that
'opts' wasn't already added to the 'do_pick' lines by 20/23. By
trigger you mean that this commit is the first to actually fill
'opts' with contents? I will move these changes to 20/23 then.

 Also, are you sure $sha1 does not require quoting through an eval?

At least if we can assume that it is really a SHA-1 object name. As
such it does not contain characters interpreted by the shell, like
backslashes, quotes or whitespace.

 Please add tests to this patch.

The ones I had in mind are attached below the scissors line. The
current reroll fails the authorship checks and the 'git rebase
--continue' test cases. As the necessary changes would obfuscate this
sub-thread, they will be included in the next reroll.

   Fabian

-- 8 --
diff --git a/t/t3427-rebase-line-options.sh b/t/t3427-rebase-line-options.sh
index 5881162..a5a9e66 100755
--- a/t/t3427-rebase-line-options.sh
+++ b/t/t3427-rebase-line-options.sh
@@ -6,10 +6,32 @@ test_description='git rebase -i with line options'
 
 . $TEST_DIRECTORY/lib-rebase.sh
 
+commit_message () {
+   git cat-file commit $1 | sed '1,/^$/d'
+}
+
+commit_authorship () {
+   git cat-file commit $1 | sed -n '/^$/q;/^author /p'
+}
+
+authorship () {
+   echo author $GIT_AUTHOR_NAME $GIT_AUTHOR_EMAIL $GIT_AUTHOR_DATE
+}
+
+test_diff_file () {
+   if cmp $1 $2 /dev/null
+   then
+   echo '$1' and '$2' are the same
+   return 1
+   fi
+}
+
 test_expect_success 'Set up repository' '
test_commit Initial 
test_commit Commit1 
-   test_commit Commit2
+   test_commit Commit2 
+   git checkout -b branch Commit1 
+   test_commit Commit2_ Commit2.t
 '
 
 test_expect_success 'Unknown option' '
@@ -23,4 +45,137 @@ test_expect_success 'Unknown option' '
git rebase --continue
 '
 
+test_msg_author () {
+   set_fake_editor 
+   FAKE_LINES=1 $1 2 git rebase -i HEAD~2 
+   commit_message HEAD actual.msg 
+   commit_authorship HEAD actual.author 
+   test_cmp expected.msg actual.msg 
+   test_cmp expected.author actual.author
+}
+
+test_msg_author_misspelled () {
+   set_cat_todo_editor 
+   test_must_fail git rebase -i HEAD^ todo 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=1 $1-misspelled 2 git rebase -i HEAD~2 

+   set_fixed_todo_editor $(pwd)/todo 
+   FAKE_LINES=$1 1 git rebase --edit-todo 
+   git rebase --continue 
+   commit_message HEAD actual.msg 
+   commit_authorship HEAD actual.author 
+   test_cmp expected.msg actual.msg 
+   test_cmp expected.author actual.author
+}
+
+test_msg_author_conflicted () {
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=$1 1 git rebase -i master 
+   git checkout --theirs Commit2.t 
+   git add Commit2.t 
+   git rebase --continue 
+   commit_message HEAD actual.msg 
+   commit_authorship HEAD actual.author 
+   test_cmp expected.msg actual.msg 
+   test_cmp expected.author actual.author
+}
+
+test_expect_success 'Misspelled pick --signoff' '
+   git checkout -b misspelled-pick--signoff master 
+   cat expected.msg -EOF 
+   $(commit_message HEAD)
+
+   Signed-off-by: C O Mitter commit...@example.com
+   EOF
+   commit_authorship HEAD expected.author 
+   test_msg_author_misspelled pick_--signoff
+'
+
+test_expect_success 'Conflicted pick --signoff' '
+   git checkout -b conflicted-pick--signoff branch 
+   cat expected.msg -EOF 
+   $(commit_message HEAD)
+
+   Signed-off-by: C O Mitter commit...@example.com
+   EOF
+   commit_authorship HEAD expected.author 
+   test_msg_author_conflicted pick_--signoff
+'
+
+test_expect_success 'pick --signoff' '
+   git checkout -b pick--signoff master 
+   cat expected.msg -EOF 
+   $(commit_message HEAD)
+
+   Signed-off-by: C O Mitter commit...@example.com
+   EOF
+   commit_authorship HEAD expected.author 
+   test_msg_author pick_--signoff
+'
+
+test_expect_success 'reword --signoff' '
+   git checkout -b reword--signoff master 
+   cat expected.msg -EOF 
+   $(commit_message HEAD)
+
+   Signed-off-by: C O Mitter commit...@example.com
+   EOF
+   commit_authorship HEAD expected.author

Re: [PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints

2014-08-11 Thread Fabian Ruch
Hi Eric,

Eric Sunshine writes:
 On Wed, Aug 6, 2014 at 7:59 PM, Fabian Ruch baf...@gmail.com wrote:
 The to-do list commands `squash` and `fixup` apply the changes
 introduced by the named commit to the tree but instead of creating
 a new commit on top of the current head it replaces the previous
 commit with a new commit that records the updated tree. If the
 result is an empty commit git-rebase stops with the error message

You asked to amend the most recent commit, but doing so would make
it empty. You can repeat your command with --allow-empty, or you can
remove the commit entirely with git reset HEAD^.

 This message is not very helpful because neither does git-rebase
 support an option `--allow-empty` nor does the messages say how to
 resume the rebase. Firstly, change the error message to

The squash result is empty and --keep-empty was not specified.

You can remove the squash commit now with

  git reset HEAD^

Once you are down, run
 
 I guess you meant: s/down/done
 
 Same issue with the actually message in the code (below).

Fixed.

  git rebase --continue

 If the user wishes to squash a sequence of commits into one
 commit, f. i.

pick A
squash Revert A
squash A'

 , it does not matter for the end result that the first squash
 result, or any sub-sequence in general, is going to be empty. The
 squash message is not affected at all by which commits are created
 and only the commit created by the last line in the sequence will
 end up in the final history. Secondly, print the error message
 only if the whole squash sequence produced an empty commit.

 Lastly, since an empty squash commit is not a failure to rewrite
 the history as planned, issue the message above as a mere warning
 and interrupt the rebase with the return value zero. The
 interruption should be considered as a notification with the
 chance to undo it on the spot. Specifying the `--keep-empty`
 option tells git-rebase to keep empty squash commits in the
 rebased history without notification.

 Add tests.

 Reported-by: Peter Krefting pe...@softwolves.pp.se
 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
 Hi,

 Peter Krefting is cc'd as the author of the bug report Confusing
 error message in rebase when commit becomes empty discussed on the
 mailing list in June. Phil Hord and Jeff King both participated in
 the problem discussion which ended with two proposals by Jeff.

 Jeff King writes:
   1. Always keep such empty commits. A user who is surprised by them
  being empty can then revisit them. Or drop them by doing another
  rebase without --keep-empty.

   2. Notice ourselves that the end-result of the whole squash is an
  empty commit, and stop to let the user deal with it.

 This patch chooses the second alternative. Either way seems OK. The
 crucial consensus of the discussion was to silently throw away empty
 interim commits.

Fabian

  git-rebase--interactive.sh| 20 +++---
  t/t3404-rebase-interactive.sh | 62 
 +++
  2 files changed, 79 insertions(+), 3 deletions(-)

 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index 3222bf6..8820eac 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -549,7 +549,7 @@ do_next () {
 squash|s|fixup|f)
 # This is an intermediate commit; its message will 
 only be
 # used in case of trouble.  So use the long version:
 -   do_with_author output git commit 
 --allow-empty-message \
 +   do_with_author output git commit 
 --allow-empty-message --allow-empty \
 --amend --no-verify -F $squash_msg \
 ${gpg_sign_opt:+$gpg_sign_opt} ||
 die_failed_squash $sha1 $rest
 @@ -558,18 +558,32 @@ do_next () {
 # This is the final command of this squash/fixup 
 group
 if test -f $fixup_msg
 then
 -   do_with_author git commit 
 --allow-empty-message \
 +   do_with_author git commit 
 --allow-empty-message --allow-empty \
 --amend --no-verify -F $fixup_msg \
 ${gpg_sign_opt:+$gpg_sign_opt} ||
 die_failed_squash $sha1 $rest
 else
 cp $squash_msg $GIT_DIR/SQUASH_MSG || 
 exit
 rm -f $GIT_DIR/MERGE_MSG
 -   do_with_author git commit --amend 
 --no-verify -F $GIT_DIR/SQUASH_MSG -e \
 +   do_with_author git commit --allow-empty 
 --amend --no-verify -F $GIT_DIR/SQUASH_MSG -e \
 ${gpg_sign_opt:+$gpg_sign_opt

Re: [PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode

2014-08-11 Thread Fabian Ruch
Hi Thomas,

Thomas Rast writes:
 Fabian Ruch baf...@gmail.com writes:
 @@ -923,6 +923,8 @@ EOF
  ;;
  esac
  
 +mkdir -p $state_dir || die Could not create temporary $state_dir
 +
  git var GIT_COMMITTER_IDENT /dev/null ||
  die You need to set your committer info first
  
 @@ -938,7 +940,6 @@ then
  fi
  
  orig_head=$(git rev-parse --verify HEAD) || die No HEAD?
 -mkdir -p $state_dir || die Could not create temporary $state_dir
  
  :  $state_dir/interactive || die Could not mark as interactive
  write_basic_state
 
 Why this change?  I can't figure out how it relates to the output
 change.

Creating the state directory a few steps earlier into
'git_rebase__interactive' is necessary because the changed definition of
'output' needs it for 'editor.sh'. This change was triggered by a
failing test case that used the branch argument with git-rebase. The
'git checkout branch', which is executed if 'switch_to' is set to
branch, is wrapped into an 'output' line and 'output' failed because
it wasn't able to create 'editor.sh'.

The state directory (of git-rebase--interactive!) is now created
directly after the case expression that handles --continue, --skip and
--edit-todo. They all assume the existence of the state directory and
either jump into 'do_rest' or 'exit' immediately, that is creating the
directory earlier would make the options handling code somewhat
incorrect and would not change anything for the start sequence of
git-rebase--interactive.

The patch message now reads as follows (with the reference to 7725cb5 in
the second paragraph and the complete third paragraph added):

 rebase -i: hide interactive command messages in verbose mode
 
 git-rebase--interactive prints summary messages of the commits it
 creates in the final history only if the `--verbose` option is
 specified by the user and suppresses them otherwise. This behaviour
 is implemented by wrapping git-commit calls in a shell function named
 `output` which redirects stderr to stdout, captures stdout in a shell
 variable and ignores its contents unless the command exits with an
 error status.
 
 The command lines used to implement the to-do list commands `reword`
 and `squash` print diagnostic messages even in non-verbose mode. The
 reason for this inconsistency is that both commands launch the log
 message editor which usually requires a working terminal attached to
 stdin. Wrapping the `reword` and `squash` command lines in `output`
 would seemingly freeze the terminal (see commit 7725cb5, rebase -i:
 fix reword when using a terminal editor). Temporarily redirect the
 editor output to a third file descriptor in order to ship it around
 the capture stream. Wrap the remaining git-commit command lines in
 the new `output`.
 
 In order to temporarily redirect the editor output, the new
 definition of `output` creates a script in the state directory to be
 used as `GIT_EDITOR`. Make sure the state directory exists before
 `output` is called for the first time.
 
 fake_editor prints the to-do list before and after applying the
 `FAKE_LINES` rewrite rules to it. Redirect this debug output to
 stderr so that it does not interfere with the git-rebase status
 output. Add test.

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


Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit

2014-08-11 Thread Fabian Ruch
Hi Thomas,

Thomas Rast writes:
 Fabian Ruch baf...@gmail.com writes:
 Subject: Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on 
 interim commit
 
 I think the change makes sense, but can you reword the subjects that it
 describes the state after the commit (i.e. what you are doing), instead
 of before the commit?

The log message subject now reads as follows:

 rebase -i: do not verify reworded patches using pre-commit

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


Re: [PATCH v2 20/23] rebase -i: parse to-do list command line options

2014-08-11 Thread Fabian Ruch
Hi Thomas,

an updated patch is attached below.

Thomas Rast writes: Fabian Ruch baf...@gmail.com writes:
 [...]
 are not supported at the moment. Neither are options that contain
 spaces because the shell expansion of `args` in `do_next` interprets
 white space characters as argument separator, that is a command line
 like

 pick --author A U Thor fa1afe1 Some change

 is parsed as the pick command

 pick --author

 and the commit hash

 A

 which obviously results in an unknown revision error. For the sake of
 completeness, in the example above the message title variable `rest`
 is assigned the string 'U Thor fa1afe1 Some change' (without the
 single quotes).
 
 You could probably trim down the non-example a bit and instead give an
 example :-)

Done. The example reword --signoff is substituted for the
non-example and used for an error message example as well. I hope
that is not confusing.

 Print an error message for unknown or unsupported command line
 options, which means an error for all specified options at the
 moment.
 
 Can you add a test that verifies we catch an obvious unknown option
 (such as --unknown-option)?

Done. The test checks that git-rebase--interactive fails to execute
'pick --unknown-option' and that the rebase can be resumed after
removing the --unknown-option part.

 Cleanly break the `do_next` loop by assigning the special
 value 'unknown' to the local variable `command`, which triggers the
 unknown command case in `do_cmd`.
 [...]
  do_replay () {
  command=$1
 -sha1=$2
 -rest=$3
 +shift
 +
 +opts=
 +while test $# -gt 0
 +do
 +case $1 in
 +-*)
 +warn Unknown option: $1
 +command=unknown
 +;;
 +*)
 +break
 +;;
 
 This seems a rather hacky solution to me.  Doesn't this now print
 
   warning: Unknown option: --unknown-option
   warning: Unknown command: pick --unknown-option
 
 ?
 
 It shouldn't claim the command is unknown if the command itself was
 valid.

OK. do_replay now first checks for unknown commands and exits
immediately if that is the case, ignoring any options specified.

 Also, you speak of do_cmd above, but the unknown command handling seems
 to be part of do_replay?

Fixed.

   Fabian

-- 8 --
Subject: rebase -i: parse to-do list command line options

Read in to-do list lines as

command args

instead of

command sha1 rest

so that to-do list command lines can specify additional arguments
apart from the commit hash and the log message title, which become
the non-options in `args`. Loop over `args`, put all options (an
argument beginning with a dash) in `opts`, stop the loop on the first
non-option and assign it to `sha1`. For instance, the to-do list

reword --signoff fa1afe1 Some change

is parsed as `command=reword`, `opts= '--signoff'` (including the
single quotes and the space for evaluation and concatenation of
options), `sha1=fa1afel` and `rest=Some change`. The loop does not
know the options it parses so that options that take an argument
themselves are not supported at the moment. Neither are options that
contain spaces because the shell expansion of `args` in `do_next`
interprets white space characters as argument separator.

Print an error message for unknown or unsupported command line
options, which means an error for all specified options at the
moment. Cleanly break the `do_next` loop by assigning a reason to the
local variable `malformed`, which triggers the unknown command code
in `do_replay`. Move the error code to the beginning of `do_replay`
so that unknown commands are reported before bad options are as only
the first error we come across is reported. For instance, the to-do
list from above produces the error

Unknown 'reword' option: --signoff
Please fix this using 'git rebase --edit-todo'.

The to-do list is also parsed when the commit hashes are translated
between long and short format before and after the to-do list is
edited. Apply the same procedure as in `do_replay` with the exception
that we only care about where the options stop and the commit hash
begins. Do not reject any options when transforming the commit
hashes.

Enable the specification of to-do list command line options in
`FAKE_LINES` the same way this is accomplished for command lines
passed to `exec`. Define a new `fake_editor.sh` that edits a static
to-do list instead of the one passed as argument when invoked by
git-rebase. Add a test case that checks that unknown options are
refused and can be corrected using `--edit-todo`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 80 --
 t/lib-rebase.sh| 20 +--
 t/t3427-rebase-line-options.sh | 26 ++
 3 files changed, 105 insertions(+), 21 deletions(-)
 create mode 100755 t/t3427-rebase-line-options.sh

diff --git a/git-rebase

[PATCH v2 21/23] rebase -i: teach do_pick the option --reset-author

2014-08-06 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement many of the to-do list commands.
Eventually, the complete `do_pick` interface will be exposed to the
user in some form or another and those commands will become simple
aliases for the `do_pick` options now used to implement them.

Add the git-commit option `--reset-author` to the options pool of
`do_pick`. It rewrites the author date and name of the picked commit
to match the committer date and name.

If `--reset-author` is passed to `do_pick`, set the `rewrite` flag
and relay the option to the git-commit command line which creates the
final commit. If `--amend` is not passed as well, the fresh
authorship effect is achieved by the mere fact that we are creating a
new commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index da435cb..d6c99ea 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,18 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--file file] [--edit] commit
+# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --reset-author
+# Pretend the changes were made for the first time. Declare that the
+# authorship of the resulting commit now belongs to the committer.
+# This also renews the author timestamp. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # --amend
 # After picking commit, replace the current head commit with a new
 # commit that also introduces the changes of commit.
@@ -502,6 +510,10 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   --reset-author)
+   rewrite=y
+   rewrite_author=y
+   ;;
--amend)
if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse -q --verify HEAD /dev/null
then
@@ -564,6 +576,14 @@ do_pick () {
pick_one ${rewrite:+-n} $1 || return 1
fi
 
+   if test -n $rewrite_author  test -z $rewrite_amend
+   then
+   # keep rewrite flag to create a new commit, rewrite
+   # without --reset-author though because it can only be
+   # used with -C, -c or --amend
+   rewrite_author=
+   fi
+
if test -n $rewrite
then
output git commit --allow-empty --no-post-rewrite -n --no-edit \
@@ -571,6 +591,7 @@ do_pick () {
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
   ${rewrite_message:+--file $rewrite_message} \
+  ${rewrite_author:+--reset-author} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 }
-- 
2.0.1

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


[PATCH v2 11/23] rebase -i: log the replay of root commits

2014-08-06 Thread Fabian Ruch
The command line used to recreate root commits specifies the option
`-q` which suppresses the commit summary message. However,
git-rebase--interactive tends to tell the user about the commits it
creates in the final history, if she wishes (cf. command line option
`--verbose`). The code parts handling non-root commits and squash
commits all output commit summary messages. Do not make the replay of
root commits an exception. Remove the option to make the report of
the rebased history complete. Do not forget to wrap the git-commit
command line in `output` so that the summary is shown if git-rebase
is called with the `--verbose` option but suppressed otherwise.

It is OK that the commit summary is still suppressed when git-commit
is used to initialize the authorship of the sentinel commit because
this additional commit is an implementation detail hidden from the
final history. The removed `-q` option was probably introduced as a
copy-and-paste error stemming from that part of the root commit
handling code.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8e1730c..91ef0f7 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -510,8 +510,8 @@ do_pick () {
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
-   git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -q -C $1 \
+   output git commit --allow-empty --allow-empty-message \
+  --amend --no-post-rewrite -n -C $1 \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


[PATCH v2 17/23] rebase -i: prepare for squash in terms of do_pick --amend

2014-08-06 Thread Fabian Ruch
Rewrite `squash` and `fixup` handling in `do_next` using the sequence

pick_one
commit

in order to test the correctness of a single `do_squash` or
parameterised `do_pick` and make the subsequent patch reimplementing
`squash` in terms of such a single function more readable.

Do not call `rm -f $GIT_DIR/MERGE_MSG` since it has no effect on
the state after git-rebase--interactive terminates. The option `-F`
makes git-commit ignore `MERGE_MSG` for the log message. If
git-commit succeeds, `MERGE_MSG` is removed, and if it fails,
`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.
In summary, removing `MERGE_MSG` neither influences the squash commit
message nor the file state after git-commit returns.

Moreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch
`$squash_msg` so that it is correct to execute `pick_one` immediately
before git-commit.

Might be squashed into the subsequent commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 21 +++--
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 0fbf773..601a2ff 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -623,15 +623,15 @@ do_next () {
author_script_content=$(get_author_ident_from_commit HEAD)
echo $author_script_content  $author_script
eval $author_script_content
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 $rest
-   fi
case $(peek_next_command) in
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not apply 
$sha1... $rest
+   fi
do_with_author output git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
@@ -641,13 +641,22 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
do_with_author output git commit 
--allow-empty-message --allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   rm -f $GIT_DIR/MERGE_MSG
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
do_with_author output git commit --allow-empty 
--amend --no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
-- 
2.0.1

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


[PATCH v2 22/23] rebase -i: teach do_pick the option --signoff

2014-08-06 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is currently used to implement most of the to-do list commands
and offers additional options that will eventually find their way
onto to-do lists.

To extend the repertoire of available options, add the git-commit and
git-cherry-pick option `--signoff` to the `do_pick` interface. It
appends a Signed-off-by: line using the committer identity to the log
message of the picked commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index d6c99ea..a22459f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,15 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
+# do_pick [--signoff] [--reset-author] [--amend] [--file file]
+# [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# -s, --signoff
+# Insert a Signed-off-by: line using the committer identity at the
+# end of the commit log message. This creates a fresh commit.
+#
 # --reset-author
 # Pretend the changes were made for the first time. Declare that the
 # authorship of the resulting commit now belongs to the committer.
@@ -510,6 +515,10 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   -s|--signoff)
+   rewrite=y
+   rewrite_signoff=y
+   ;;
--reset-author)
rewrite=y
rewrite_author=y
@@ -588,6 +597,7 @@ do_pick () {
then
output git commit --allow-empty --no-post-rewrite -n --no-edit \
   ${allow_empty_message:+--allow-empty-message} \
+  ${rewrite_signoff:+--signoff} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
   ${rewrite_message:+--file $rewrite_message} \
-- 
2.0.1

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


[PATCH v2 10/23] rebase -i: implement reword in terms of do_pick

2014-08-06 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If one thinks of `pick`
entries as scheduled `cherry-pick` command lines, then `reword`
becomes an alias for the command line `cherry-pick --edit`. The
porcelain `rebase--interactive` defines a function `do_pick` for
processing the `pick` entries on to-do lists. Reimplement `reword` in
terms of `do_pick --edit`.

If the user picks a commit using the to-do list line

reword fa1afe1 Some change

execute the command `do_pick --edit fa1afe1 Some change` which
carries out exactly the same steps as the case arm for `reword` in
`do_next` so far.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index aed2f93..8e1730c 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -546,11 +546,7 @@ do_next () {
comment_for_reflog reword
 
mark_action_done
-   do_pick $sha1 $rest
-   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
-   warn Could not amend commit after successfully picking 
$sha1... $rest
-   exit_with_patch $sha1 1
-   }
+   do_pick --edit $sha1 $rest
record_in_rewritten $sha1
;;
edit|e)
-- 
2.0.1

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


[PATCH v2 12/23] rebase -i: root commits are replayed with an unnecessary option

2014-08-06 Thread Fabian Ruch
The command line used to recreate root commits uses `-C` to suppress
the log message editor. This is unnecessarily confusing, though,
because that suppression is a secondary effect of the option. The
main purpose of `-C` is to pull the metadata from another commit, but
here we know that this is a noop, since we are amending a commit just
created from the same data.

At the time `-C` was introduced, git-commit did not yet have a
documented `--no-edit`, and this was a reasonable way to get the
desired behavior. Switch it to use `--no-edit` to make the intended
effect more obvious.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 91ef0f7..71571c8 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -511,7 +511,7 @@ do_pick () {
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
output git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -C $1 \
+  --amend --no-post-rewrite -n --no-edit \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


[PATCH v2 07/23] rebase -i: squash skips commit-msg hook

2014-08-06 Thread Fabian Ruch
Using the to-do list command `squash` the user can specify two or
more commits and git-rebase creates one commit that introduces all
their changes combined. The authorship for the created commit is
taken from the first commit specified and the user can edit the log
message. There is a variant of `squash` available named `fixup` which
also takes the first log message without asking for user input.

While it is reasonable to not verify replayed changes twice or
rejecting some other author's changes in her name, it is insufficient
to not verify the user input used as log message in the case of
`squash`. Specify the git-commit option `--commit-msg` when
committing the squash result to execute the commit-msg hook and
verify the new log message. For the same reasons the pre-commit hook
is disabled in all replay modes, the commit-msg hook gets disabled in
`fixup` mode.

Add tests. In addition to the existing test checking that the
pre-commit hook is disabled when simply picking a commit, provide a
test checking that the commit-msg hook is disabled as well.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 78 +++
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3ee13c2..97386aa 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -562,7 +562,7 @@ do_next () {
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author output git commit --allow-empty 
--amend --no-verify -F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author output git commit --allow-empty 
--amend --no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index c6578c3..bc2dda1 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -655,6 +655,84 @@ test_expect_success 'rebase a commit violating pre-commit' 
'
 
 '
 
+test_expect_success 'setup failing pre-commit' '
+   HOOKDIR=$(git rev-parse --git-dir)/hooks 
+   mkdir -p $HOOKDIR 
+   PRE_COMMIT=$HOOKDIR/pre-commit 
+   cat $PRE_COMMIT -EOF 
+   #!/bin/sh
+   echo running failing pre-commit...
+   exit 1
+   EOF
+   chmod +x $PRE_COMMIT 
+   git checkout -b violating-pre-commit master 
+   test_must_fail test_commit pre-commit-violated-1 
+   test_commit --no-verify pre-commit-violated-1 
+   test_must_fail test_commit pre-commit-violated-2 
+   test_commit --no-verify pre-commit-violated-2
+'
+
+test_expect_success 'squash a commit violating pre-commit' '
+   git checkout -b squash-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=1 squash 2 git rebase -i master
+'
+
+test_expect_success 'fixup a commit violating pre-commit' '
+   git checkout -b fixup-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=1 fixup 2 git rebase -i master
+'
+
+test_expect_success 'clean up failing pre-commit' '
+   rm $PRE_COMMIT
+'
+
+test_expect_success 'setup failing commit-msg' '
+   HOOKDIR=$(git rev-parse --git-dir)/hooks 
+   mkdir -p $HOOKDIR 
+   COMMIT_MSG=$HOOKDIR/commit-msg 
+   cat $COMMIT_MSG -EOF 
+   #!/bin/sh
+   echo running failing commit-msg...
+   exit 1
+   EOF
+   chmod +x $COMMIT_MSG 
+   git checkout -b violating-commit-msg master 
+   test_must_fail test_commit commit-msg-violated-1 
+   test_commit --no-verify commit-msg-violated-1 
+   test_must_fail test_commit commit-msg-violated-2 
+   test_commit --no-verify commit-msg-violated-2 
+   test_must_fail test_commit commit-msg-violated-3 
+   test_commit --no-verify commit-msg-violated-3
+'
+
+test_expect_success 'rebase a commit violating commit-msg' '
+   git checkout -b rebase-violating-commit-msg violating-commit-msg 
+   set_fake_editor 
+   FAKE_LINES=1 git rebase -i master
+'
+
+test_expect_success 'squash a commit violating commit-msg' '
+   git checkout -b squash-violating-commit-msg violating-commit-msg 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=1 squash 2 fixup 3 git rebase -i master 

+   git commit --no-verify --amend 
+   git rebase --continue
+'
+
+test_expect_success 'fixup a commit violating commit-msg' '
+   git checkout -b fixup-violating-commit-msg violating-commit-msg 
+   set_fake_editor 
+   env FAKE_LINES=1 fixup 2 git rebase -i master

[PATCH v2 14/23] rebase -i: do not die in do_pick

2014-08-06 Thread Fabian Ruch
Since `do_pick` might be executed in a sub-shell (a modified author
environment for instance), calling `die` in `do_pick` has no effect
but exiting the sub-shell with a failure exit status. The
git-rebase--interactive script is not terminated. Moreover, if
`do_pick` is called while a squash or fixup is in effect,
`die_with_patch` will discard `$squash_msg` as commit message.
Lastly, after a `die` in `do_pick` `do_next` has no chance to
reschedule tasks that failed before changes could be applied.

Indicate an error in `do_pick` using return statements and properly
kill the script at the call sites. Although possible in principle,
the issued error messages are no more indicating whether `do_pick`
failed while applying or while committing the changes. This reduces
code complexity at the call site and does not matter from a user's
point of view because a glance at the index reveals whether there are
conflicts or not and in-depth troubleshooting is still possible using
the `--verbose` option.

Remove the commit message title argument from `do_pick`'s interface,
which has become unused.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 34 +++---
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b8c734e..d812bad 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit title
+# do_pick [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -476,9 +476,11 @@ record_in_rewritten() {
 # commit
 # The commit to cherry-pick.
 #
-# title
-# The commit message title of commit. Used for information
-# purposes only.
+# The return value is 1 if applying the changes resulted in a conflict
+# and 2 if the specified arguments were incorrect. If the changes could
+# be applied successfully but creating the commit failed, a value
+# greater than 2 is returned. No commit is created in either case and
+# the index is left with the (conflicting) changes in place.
 do_pick () {
allow_empty_message=y
rewrite=
@@ -493,7 +495,8 @@ do_pick () {
allow_empty_message=
;;
-*)
-   die do_pick: unrecognized option -- $1
+   warn do_pick: unrecognized option -- $1
+   return 2
;;
*)
break
@@ -501,7 +504,11 @@ do_pick () {
esac
shift
done
-   test $# -ne 2  die do_pick: wrong number of arguments
+   if test $# -ne 1
+   then
+   warn do_pick: wrong number of arguments
+   return 2
+   fi
 
if test $(git rev-parse HEAD) = $squash_onto
then
@@ -519,11 +526,9 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one -n $1 || return 1
else
-   pick_one ${rewrite:+-n} $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one ${rewrite:+-n} $1 || return 1
fi
 
if test -n $rewrite
@@ -532,8 +537,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_with_patch $1 Could not rewrite commit after 
successfully picking $1... $2
+  ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 }
 
@@ -548,21 +552,21 @@ do_next () {
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 $rest
+   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 $rest
+   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
record_in_rewritten $sha1
;;
edit|e)
comment_for_reflog edit
 
mark_action_done
-   do_pick $sha1 $rest
+   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
warn Stopped at $sha1... $rest
exit_with_patch $sha1 0
;;
-- 
2.0.1

--
To unsubscribe from this list: send the line unsubscribe

[PATCH v2 19/23] rebase -i: explicitly distinguish replay commands and exec tasks

2014-08-06 Thread Fabian Ruch
There are two kinds of to-do list commands available. One kind
replays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that
is) and the other executes a shell command (`exec`). We will call the
first kind replay commands.

The two kinds of tasks are scheduled using different line formats.
Replay commands expect a commit hash argument following the command
name and exec concatenates all arguments to assemble a command line.

Adhere to the distinction of formats by not trying to parse the
`sha1` field unless we are dealing with a replay command. Move the
replay command handling code to a new function `do_replay` which
assumes the first argument to be a commit hash and make no more such
assumptions in `do_next`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 42 --
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 29eca7e..6ecd4d7 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -575,13 +575,12 @@ do_pick () {
fi
 }
 
-do_next () {
-   rm -f $msg $author_script $amend || exit
-   read -r command sha1 rest  $todo
+do_replay () {
+   command=$1
+   sha1=$2
+   rest=$3
+
case $command in
-   $comment_char*|''|noop)
-   mark_action_done
-   ;;
pick|p)
comment_for_reflog pick
 
@@ -660,6 +659,28 @@ do_next () {
esac
record_in_rewritten $sha1
;;
+   *)
+   read -r command $todo
+   warn Unknown command: $command
+   fixtodo=Please fix this using 'git rebase --edit-todo'.
+   if git rev-parse --verify -q $sha1 /dev/null
+   then
+   die_with_patch $sha1 $fixtodo
+   else
+   die $fixtodo
+   fi
+   ;;
+   esac
+}
+
+do_next () {
+   rm -f $msg $author_script $amend || exit
+   read -r command sha1 rest $todo
+
+   case $command in
+   $comment_char*|''|noop)
+   mark_action_done
+   ;;
x|exec)
read -r command rest  $todo
mark_action_done
@@ -699,14 +720,7 @@ do_next () {
fi
;;
*)
-   warn Unknown command: $command $sha1 $rest
-   fixtodo=Please fix this using 'git rebase --edit-todo'.
-   if git rev-parse --verify -q $sha1 /dev/null
-   then
-   die_with_patch $sha1 $fixtodo
-   else
-   die $fixtodo
-   fi
+   do_replay $command $sha1 $rest
;;
esac
test -s $todo  return
-- 
2.0.1

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


[PATCH v2 13/23] rebase -i: commit only once when rewriting picks

2014-08-06 Thread Fabian Ruch
The options passed to `do_pick` determine whether the picked commit
will be rewritten or not. If the commit gets rewritten, because the
user requested to edit the commit message for instance, let
`pick_one` merely apply the changes introduced by the commit and do
not commit the resulting tree yet. If the commit is replayed as is,
leave it to `pick_one` to recreate the commit (possibly by
fast-forwarding the head). This makes it easier to combine git-commit
options like `--edit` and `--amend` in `do_pick` because
git-cherry-pick does not support `--amend`.

In the case of `--edit`, do not `exit_with_patch` but assign
`rewrite` to pick the changes with `-n`. If the pick conflicts, no
commit is created which we would have to amend when continuing the
rebase. To complete the pick after the conflicts are resolved the
user just resumes with `git rebase --continue`.

git-commit lets the user edit the commit log message by default. We
do not want that for the rewriting git-commit command line because
the default behaviour of git-rebase is exactly the opposite. Pass
`--no-edit` when rewriting a picked commit. An explicit `--edit`
passed to `do_pick` (for instance, when reword is executed) enables
the editor launch again. Similarly, pass `--allow-empty-message`
unless the log message is edited.

If `rebase--interactive` is used to rebase a complete branch onto
some head, `rebase` creates a sentinel commit that requires special
treatment by `do_pick`. Do not finalize the pick here either because
its commit message can be altered as for any other pick. Since the
orphaned root commit gets a temporary parent, it is always rewritten.
Safely use the rewrite infrastructure of `do_pick` to create the
final commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 35 ++-
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 71571c8..b8c734e 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -63,7 +63,8 @@ msgnum=$state_dir/msgnum
 author_script=$state_dir/author-script
 
 # When an edit rebase command is being processed, the SHA1 of the
-# commit to be edited is recorded in this file.  When git rebase
+# commit to be edited is recorded in this file.  The same happens when
+# rewriting a commit fails, for instance reword.  When git rebase
 # --continue is executed, if there are any staged changes then they
 # will be amended to the HEAD commit, but only provided the HEAD
 # commit is still the commit to be edited.  When any other rebase
@@ -479,12 +480,17 @@ record_in_rewritten() {
 # The commit message title of commit. Used for information
 # purposes only.
 do_pick () {
-   edit=
+   allow_empty_message=y
+   rewrite=
+   rewrite_amend=
+   rewrite_edit=
while test $# -gt 0
do
case $1 in
-e|--edit)
-   edit=y
+   rewrite=y
+   rewrite_edit=y
+   allow_empty_message=
;;
-*)
die do_pick: unrecognized option -- $1
@@ -499,6 +505,10 @@ do_pick () {
 
if test $(git rev-parse HEAD) = $squash_onto
then
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+
# Set the correct commit message and author info on the
# sentinel root before cherry-picking the original changes
# without committing (-n).  Finally, update the sentinel again
@@ -509,22 +519,21 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 
-   output git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n --no-edit \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
+   pick_one -n $1 ||
die_with_patch $1 Could not apply $1... $2
else
-   pick_one $1 ||
+   pick_one ${rewrite:+-n} $1 ||
die_with_patch $1 Could not apply $1... $2
fi
 
-   if test -n $edit
+   if test -n $rewrite
then
-   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
-   warn Could not amend commit after successfully picking 
$1... $2
-   exit_with_patch $1 1
-   }
+   output git commit --allow-empty --no-post-rewrite -n --no-edit \
+  ${allow_empty_message:+--allow-empty-message} \
+  ${rewrite_amend:+--amend

[PATCH v2 18/23] rebase -i: implement squash in terms of do_pick

2014-08-06 Thread Fabian Ruch
The to-do list command `squash` and its close relative `fixup` replay
the changes of a commit like `pick` but do not recreate the commit.
Instead they replace the previous commit with a new commit that also
introduces the changes of the squashed commit. This is roughly like
cherry-picking without committing and using git-commit to amend the
previous commit.

The to-do list

pick   a Some changes
squash b Some more changes

gets translated into the sequence of git commands

git cherry-pick a
git cherry-pick -n b
git commit --amend

and if git-cherry-pick supported `--amend` this would look even more
like the to-do list it is based on

git cherry-pick a
git cherry-pick --amend b.

Since `do_pick` takes care of `pick` entries and the above suggests
`squash` as an alias for `pick --amend`, reimplement `squash` in
terms of `do_pick --amend`. Introduce `$squash_msg` as the commit
message via the `--file` option. When the last commit of a squash
series is processed, the user is asked to review the log message.
Pass `--edit` as additional option in this case. The only difference
in the options passed to git-commit and `do_pick` is the omitted
`--no-verify`. However, `do_pick` does not execute the verification
hooks anyway because it solely replays commits and assumes that they
have been verified before.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 32 ++--
 1 file changed, 6 insertions(+), 26 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 601a2ff..29eca7e 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -627,39 +627,19 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not apply 
$sha1... $rest
-   fi
-   do_with_author output git commit --allow-empty-message 
--allow-empty \
-   --amend --no-verify -F $squash_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F $squash_msg $sha1 \
+   || die_failed_squash $sha1 $rest
;;
*)
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   do_with_author output git commit 
--allow-empty-message --allow-empty \
-   --amend --no-verify -F $fixup_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F $fixup_msg 
$sha1 \
+   || die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   do_with_author output git commit --allow-empty 
--amend --no-pre-commit -F $GIT_DIR/SQUASH_MSG -e \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F 
$GIT_DIR/SQUASH_MSG -e $sha1 \
+   || die_failed_squash $sha1 $rest
fi
rm -f $squash_msg $fixup_msg
if test -z $keep_empty  is_empty_commit HEAD
-- 
2.0.1

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


[PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword

2014-08-06 Thread Fabian Ruch
pick and reword are atomic to-do list commands in the sense that they
open a new task which is closed after the respective command is
completed. squash and fixup are not atomic. They create a new task
which is not completed until the last squash or fixup is processed.

Lift the general unknown option blockade for the pick and reword
commands. If `do_cmd` comes across one of the options `--signoff` and
`--reset-author` while parsing a to-do entry and the scheduled
command is either `pick` or `reword`, relay the option to `do_pick`.

The `do_pick` options `--gpg-sign` and `--file` are not yet supported
because `do_cmd` cannot handle option arguments and options with
spaces at the moment. It is true that edit is one of the atomic
commands but it displays hash information when the rebase is stopped
and some options rewrite the picked commit which alters that
information. squash and fixup still do not accept user options as the
interplay of `--reset-author` and the author script are yet to be
determined.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 19 ---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index a22459f..4c05734 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -614,6 +614,16 @@ do_replay () {
while test $# -gt 0
do
case $1 in
+   --signoff|--reset-author)
+   case $command in
+   pick|reword)
+   ;;
+   *)
+   warn Unsupported option: $1
+   command=unknown
+   ;;
+   esac
+   ;;
-*)
warn Unknown option: $1
command=unknown
@@ -634,21 +644,24 @@ do_replay () {
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   eval do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
+   eval do_pick --edit $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
edit|e)
comment_for_reflog edit
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   eval do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
warn Stopped at $sha1... $rest
exit_with_patch $sha1 0
;;
-- 
2.0.1

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


Re: [PATCH v1 09/19] rebase -i: commit only once when rewriting picks

2014-08-06 Thread Fabian Ruch
Hi Jeff,

Jeff King writes:
 On Tue, Jul 29, 2014 at 01:18:09AM +0200, Fabian Ruch wrote:
 The options passed to `do_pick` determine whether the picked commit
 will be rewritten or not. If the commit gets rewritten, because the
 user requested to edit the commit message for instance, let
 `pick_one` merely apply the changes introduced by the commit and do
 not commit the resulting tree yet. If the commit is replayed as is,
 leave it to `pick_one` to recreate the commit (possibly by
 fast-forwarding the head). This makes it easier to combine git-commit
 options like `--edit` and `--amend` in `do_pick` because
 git-cherry-pick does not support `--amend`.

 In the case of `--edit`, do not `exit_with_patch` but assign
 `rewrite` to pick the changes with `-n`. If the pick conflicts, no
 commit is created which we would have to amend when continuing the
 rebase. To complete the pick after the conflicts are resolved the
 user just resumes with `git rebase --continue`.
 
 Hmm. So does this mean the user will actually see a different state
 during such a conflict?
 
 E.g., if I have instructions like:
 
   pick A
   squash B
   squash C
 
 and there is a conflict picking C, then what state do I see? Right now I
 see a commit with the A+B squash prepared. But your description sounds
 to me like we would avoid the squash for B, and the user would see a
 different state.

The squash state will not be different. squash sequences are still taken
care of one line after the other: committing A, committing A+B,
committing A+B+C. If there is a conflict picking C, HEAD will point to
A+B and the index will record the conflicting changes.

 However, I couldn't trigger that behavior in a few experiments. Am I
 misunderstanding, or is there some case where the user-visible state
 will be different?

The user-visible state will be different for rewords. For instance,
let's consider

pick A
reword B.

The verbose log used to show two commits for B (with ff disabled), one
after picking and one after editing. Now the log will show a single
commit in connection with 'reword B' which might be less confusing.

Thanks for raising your eyebrows. I noticed now that the last paragraph
is plainly wrong. The described amend situation did not arise if the
pick conflicted but if the edited commit did not verify. There will
be no after the conflicts are resolved but the user can either commit
manually and circumvent log message verification if she knows what she's
doing, or provide a corrected log message in the editor launched by 'git
rebase --continue'. The _incomplete_ 'git commit --amend' tip which used
to be displayed after a failed verification hook could become
unnecessary and this would possibly spare us including correct GPG sign
options for instance.

However, this patch is mostly motivated by the unification of how
commits are rewritten. Before, rewords and squashes went about this
differently, now both fail with an uncommitted index if there are
conflicts or the log message is ill-formatted.

The log message must be corrected and the following bug, which was
noticed after PATCH v2, must be fixed.

cat .git/hooks/commit-msg -EOF
#!/bin/sh
exit 1
EOF
chmod +x .git/hooks/commit-msg
test_must_fail env FAKE_LINES=reword 1 git rebase -i
test_must_fail git rebase --continue
# the last command succeeds because --continue does not verify

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


[PATCH v2 00/23] Enable options --signoff, --reset-author for pick, reword

2014-08-06 Thread Fabian Ruch
Hi List,

this is the second reroll of the patch series fixing corner-case bugs
regarding empty commits, commits with no log message and root
commits, providing a uniform implementation of the to-do list
commands using the `do_pick` interface.

This reroll includes the following list of changes to PATCH v1 from
last week, mostly induced by Jeff's comments. However, I didn't get
around the most recent discussion from tonight yet.

 - new tests: allow replaying commits with empty log messages
 - coverage of all to-do list commands
 - new patch: allow squashing empty commits without complaints
 - do not complain about an empty squash commit unless it is the
   final one and --keep-empty is not specified on the command line
 - new tests: allow rewording empty commits without complaints
 - coverage of all to-do list commands
 - new patch: hide interactive command messages in verbose mode
 - make it possible to launch an editor inside 'output'
 - new patch: allow disabling pre-commit and commit-msg separately
 - add options --no-pre-commit and --no-commit-msg to git-commit
 - redefine --no-verify as synonym for the above two
 - new patch: squash skips commit-msg hook
 - run commit-msg hook for reworded _and_ squashed commits
 - a change to 'test_commit' options and 'fake_editor' debug output

Thanks for your time and reviews,
   Fabian

Fabian Ruch (23):
  rebase -i: allow replaying commits with empty log messages
  rebase -i: allow squashing empty commits without complaints
  rebase -i: allow rewording empty commits without complaints
  rebase -i: hide interactive command messages in verbose mode
  rebase -i: failed reword prints redundant error message
  commit: allow disabling pre-commit and commit-msg separately
  rebase -i: squash skips commit-msg hook
  rebase -i: reword executes pre-commit hook on interim commit
  rebase -i: teach do_pick the option --edit
  rebase -i: implement reword in terms of do_pick
  rebase -i: log the replay of root commits
  rebase -i: root commits are replayed with an unnecessary option
  rebase -i: commit only once when rewriting picks
  rebase -i: do not die in do_pick
  rebase -i: teach do_pick the option --amend
  rebase -i: teach do_pick the option --file
  rebase -i: prepare for squash in terms of do_pick --amend
  rebase -i: implement squash in terms of do_pick
  rebase -i: explicitly distinguish replay commands and exec tasks
  rebase -i: parse to-do list command line options
  rebase -i: teach do_pick the option --reset-author
  rebase -i: teach do_pick the option --signoff
  rebase -i: enable options --signoff, --reset-author for pick, reword

 Documentation/git-commit.txt  |   8 +-
 builtin/commit.c  |  32 -
 git-rebase--interactive.sh| 288 ++
 git-rebase.sh |  12 +-
 t/lib-rebase.sh   |   8 +-
 t/t3404-rebase-interactive.sh | 234 --
 t/t3406-rebase-message.sh |  18 +++
 t/t3412-rebase-root.sh|  16 +++
 t/t7503-pre-commit-hook.sh|  65 --
 t/t7504-commit-msg-hook.sh|  85 ++---
 t/test-lib-functions.sh   |  23 +++-
 11 files changed, 680 insertions(+), 109 deletions(-)

-- 
2.0.1

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


[PATCH v2 01/23] rebase -i: allow replaying commits with empty log messages

2014-08-06 Thread Fabian Ruch
git-rebase--interactive handles empty log messages inconsistently
between enabled and disabled fast-forwards. By default, commits with
empty log messages are rebased successfully like in non-interactive
mode. In contrast, the `--no-ff` option aborts the replay of such
commits.

In line with not verifying rebased commits and behaving like
git-rebase for `pick` lines, use the `--allow-empty-message` option
to replay commits. Root commits are replayed by recreating them in
`do_pick` using git-commit and all other commits are replayed using
git-cherry-pick in `pick_one`. Apply the option, understood by both
git-commit and git-cherry-pick, at the respective sites.

In case of `reword` and `squash`, continue to abort the rebase if the
_resulting_ commit would have no commit message. The rationale behind
this default is that patches and their log messages should be
verified at least once. For unchanged commits this is assumed to have
happened according to the author's standards when she created the
commits for the first time. While the empty log message can always be
kept in place by editing and resuming the aborted rebase, a debatable
alternative could be to teach git-rebase--interactive the option
`--allow-empty-message` for disabling complaints about empty log
messages even in changed commits.

The `fixup` case is different again because it throws away the second
commit's log message and uses the first log message for the changed
commit. Do not abort the rebase if that message is empty either since
it is assumed to have been verified already.

The remaining to-do list command `edit` is handled just like `pick`
for this matter, because git-rebase--interactive replays the named
commit without changes before the rebase is interrupted and the user
can make her changes to the replayed commit.

Add tests. In particular, design the `squash`-specific test case such
that it involves interim commits and `fixup` steps. Interim commits
should not trigger failures themselves and `fixup` steps should not
let git-rebase--interactive forget that it is still dealing with a
`squash` result.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 10 ++
 t/t3404-rebase-interactive.sh | 38 ++
 t/t3412-rebase-root.sh| 16 
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b64dd28..3222bf6 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -249,7 +249,7 @@ pick_one () {
 
test -d $rewritten 
pick_one_preserving_merges $@  return
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $empty_args $ff $@
 }
@@ -363,7 +363,7 @@ pick_one_preserving_merges () {
echo $sha1 $(git rev-parse HEAD^0)  
$rewritten_list
;;
*)
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $@ ||
die_with_patch $sha1 Could not pick $sha1
@@ -549,7 +549,8 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   do_with_author output git commit --amend --no-verify -F 
$squash_msg \
+   do_with_author output git commit --allow-empty-message \
+   --amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
;;
@@ -557,7 +558,8 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --amend --no-verify 
-F $fixup_msg \
+   do_with_author git commit --allow-empty-message 
\
+   --amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8197ed2..9c71835 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1039,4 +1039,42 @@ test_expect_success 'short SHA-1 collide' '
)
 '
 
+test_expect_success 'setup commits with empty commit log

[PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints

2014-08-06 Thread Fabian Ruch
The to-do list commands `squash` and `fixup` apply the changes
introduced by the named commit to the tree but instead of creating
a new commit on top of the current head it replaces the previous
commit with a new commit that records the updated tree. If the
result is an empty commit git-rebase stops with the error message

   You asked to amend the most recent commit, but doing so would make
   it empty. You can repeat your command with --allow-empty, or you can
   remove the commit entirely with git reset HEAD^.

This message is not very helpful because neither does git-rebase
support an option `--allow-empty` nor does the messages say how to
resume the rebase. Firstly, change the error message to

   The squash result is empty and --keep-empty was not specified.

   You can remove the squash commit now with

 git reset HEAD^

   Once you are down, run

 git rebase --continue

If the user wishes to squash a sequence of commits into one
commit, f. i.

   pick A
   squash Revert A
   squash A'

, it does not matter for the end result that the first squash
result, or any sub-sequence in general, is going to be empty. The
squash message is not affected at all by which commits are created
and only the commit created by the last line in the sequence will
end up in the final history. Secondly, print the error message
only if the whole squash sequence produced an empty commit.

Lastly, since an empty squash commit is not a failure to rewrite
the history as planned, issue the message above as a mere warning
and interrupt the rebase with the return value zero. The
interruption should be considered as a notification with the
chance to undo it on the spot. Specifying the `--keep-empty`
option tells git-rebase to keep empty squash commits in the
rebased history without notification.

Add tests.

Reported-by: Peter Krefting pe...@softwolves.pp.se
Signed-off-by: Fabian Ruch baf...@gmail.com
---
Hi,

Peter Krefting is cc'd as the author of the bug report Confusing
error message in rebase when commit becomes empty discussed on the
mailing list in June. Phil Hord and Jeff King both participated in
the problem discussion which ended with two proposals by Jeff.

Jeff King writes:
   1. Always keep such empty commits. A user who is surprised by them
  being empty can then revisit them. Or drop them by doing another
  rebase without --keep-empty.
 
   2. Notice ourselves that the end-result of the whole squash is an
  empty commit, and stop to let the user deal with it.

This patch chooses the second alternative. Either way seems OK. The
crucial consensus of the discussion was to silently throw away empty
interim commits.

   Fabian

 git-rebase--interactive.sh| 20 +++---
 t/t3404-rebase-interactive.sh | 62 +++
 2 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3222bf6..8820eac 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -549,7 +549,7 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   do_with_author output git commit --allow-empty-message \
+   do_with_author output git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
@@ -558,18 +558,32 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --allow-empty-message 
\
+   do_with_author git commit --allow-empty-message 
--allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author git commit --amend --no-verify 
-F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author git commit --allow-empty --amend 
--no-verify -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
rm -f $squash_msg $fixup_msg
+   if test -z $keep_empty  is_empty_commit HEAD
+   then
+   echo $sha1 $state_dir/stopped-sha

[PATCH v2 03/23] rebase -i: allow rewording empty commits without complaints

2014-08-06 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If `--keep-empty` is
passed as option to git-rebase--interactive, empty commits ought to
be replayed without complaints. However, if the users chooses to
reword an empty commit by changing the respective to-do list entry
from

pick fa1afe1 Empty commit

to

reword fa1afe1 Empty commit

, then git-rebase--interactive suddenly fails to replay the empty
commit. This is especially counterintuitive because `reword` is
thought of as a `pick` that alters the log message in some way but
nothing more and the unchanged to-do list entry would not fail.

Handle `reword` by cherry-picking the named commit and editing the
log message using

git commit --allow-empty --amend

instead of

git commit --amend.

Add test.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 24 
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8820eac..89ef5e2 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
warn This is most likely due to an empty commit 
message, or the pre-commit hook
warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a95cb2a..3e64280 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -75,6 +75,30 @@ test_expect_success 'rebase --keep-empty' '
test_line_count = 6 actual
 '
 
+test_expect_success 'rebase --keep-empty (reword)' '
+   git checkout -b reword-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 reword 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 6 actual
+'
+
+test_expect_success 'rebase --keep-empty (fixup)' '
+   git checkout -b fixup-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 fixup 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 5 actual
+'
+
+test_expect_success 'rebase --keep-empty (squash)' '
+   git checkout -b squash-emptybranch emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 squash 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 5 actual
+'
+
 test_expect_success 'rebase -i with the exec command' '
git checkout master 
(
-- 
2.0.1

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


[PATCH v2 05/23] rebase -i: failed reword prints redundant error message

2014-08-06 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If the edited log
message is empty or is found ill-formatted by one of the commit
hooks, git-rebase--interactive prints three error messages to the
console.

1. The git-commit output, which contains all the output from hook
   scripts.
2. A rebase diagnosis saying at which task on the to-do list it
   got stuck.
3. Generic presumptions about what could have triggered the
   error.

The third message contains redundant information and does not add any
enlightenment either, which makes the output unnecessarily longish
and different from the other command's output. For instance, this is
what the output looks like if the log message is empty (contains
duplicate Signed-off-by lines).

(1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by 
lines.)
(2.) Could not amend commit after successfully picking fa1afe1... Some 
change
(3.) This is most likely due to an empty commit message, or the pre-commit 
hook
 failed. If the pre-commit hook failed, you may need to resolve the 
issue before
 you are able to reword the commit.

Discard the third message.

It is true that a failed hook script might not output any diagnosis
but then the generic message is not of much help either. Since this
lack of information affects the built-in git commands for commit,
merge and cherry-pick first, the solution would be to keep track of
the failed hooks in their output so that the user knows which of her
hooks require improvement.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5dfdf13..3ee13c2 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -506,9 +506,6 @@ do_next () {
do_pick $sha1 $rest
output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
-   warn This is most likely due to an empty commit 
message, or the pre-commit hook
-   warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
-   warn you are able to reword the commit.
exit_with_patch $sha1 1
}
record_in_rewritten $sha1
-- 
2.0.1

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


[PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode

2014-08-06 Thread Fabian Ruch
git-rebase--interactive prints summary messages of the commits it
creates in the final history only if the `--verbose` option is
specified by the user and suppresses them otherwise. This behaviour
is implemented by wrapping git-commit calls in a shell function named
`output` which redirects stderr to stdout, captures stdout in a shell
variable and ignores its contents unless the command exits with an
error status.

The command lines used to implement the to-do list commands `reword`
and `squash` print diagnostic messages even in non-verbose mode. The
reason for this inconsistency is that both commands launch the log
message editor which usually requires a working terminal attached to
stdin. Temporarily redirect the editor output to a third file
descriptor in order to ship it around the capture stream. Wrap the
respective git-commit command lines in `output`.

fake_editor prints the to-do list before and after applying the
`FAKE_LINES` rewrite rules to it. Redirect this debug output to
stderr so that it does not interfere with the git-rebase status
output. Add test.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  9 +
 git-rebase.sh | 12 ++--
 t/lib-rebase.sh   |  8 
 t/t3404-rebase-interactive.sh | 18 ++
 t/t3406-rebase-message.sh | 18 ++
 5 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 89ef5e2..5dfdf13 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
warn This is most likely due to an empty commit 
message, or the pre-commit hook
warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
@@ -558,14 +558,14 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   do_with_author git commit --allow-empty-message 
--allow-empty \
+   do_with_author output git commit 
--allow-empty-message --allow-empty \
--amend --no-verify -F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
rm -f $GIT_DIR/MERGE_MSG
-   do_with_author git commit --allow-empty --amend 
--no-verify -F $GIT_DIR/SQUASH_MSG -e \
+   do_with_author output git commit --allow-empty 
--amend --no-verify -F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
fi
@@ -923,6 +923,8 @@ EOF
;;
 esac
 
+mkdir -p $state_dir || die Could not create temporary $state_dir
+
 git var GIT_COMMITTER_IDENT /dev/null ||
die You need to set your committer info first
 
@@ -938,7 +940,6 @@ then
 fi
 
 orig_head=$(git rev-parse --verify HEAD) || die No HEAD?
-mkdir -p $state_dir || die Could not create temporary $state_dir
 
 :  $state_dir/interactive || die Could not mark as interactive
 write_basic_state
diff --git a/git-rebase.sh b/git-rebase.sh
index 55da9db..f90541e 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -131,9 +131,17 @@ write_basic_state () {
 output () {
case $verbose in
'')
-   output=$($@ 21 )
+   cat $state_dir/editor.sh EOF
+#!/bin/sh
+$(git var GIT_EDITOR) \$@ 3
+EOF
+   chmod +x $state_dir/editor.sh
+   (
+   export GIT_EDITOR=\$state_dir/editor.sh\
+   $@ 31 $state_dir/output 21
+   )
status=$?
-   test $status != 0  printf %s\n $output
+   test $status != 0  cat $state_dir/output
return $status
;;
*)
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 6bd2522..0cd1193 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -41,8 +41,8 @@ set_fake_editor () {
test -z $FAKE_LINES  exit
grep -v '^#'  $1  $1.tmp
rm -f $1
-   echo 'rebase -i script before editing:'
-   cat $1.tmp
+   echo 'rebase -i script before editing:' 2
+   cat $1.tmp 2
action=pick

[PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit

2014-08-06 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. This happens in two
steps. Firstly, the named commit is cherry-picked. Secondly, the
commit created in the first step is amended using an unchanged index
to edit the log message. The pre-commit hook is meant to verify the
changes introduced by a commit (for instance, catching inserted
trailing white space). Since the committed tree is not changed
between the two steps and we do not verify rebased patches, do not
execute the pre-commit hook in the second step.

Specify the git-commit option `--no-pre-commit` to disable the
pre-commit hook when editing the log message. The commit-msg hook
will still be executed to verify the edited commit log message. As
before, if the hook finds the new log message ill-formatted, the
rebase will be interrupted with the unchanged commit replayed and the
new log message in `$GIT_DIR/COMMIT_EDITMSG`.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  2 +-
 t/t3404-rebase-interactive.sh | 14 ++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 97386aa..edc323d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   output git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
exit_with_patch $sha1 1
}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index bc2dda1..3dac022 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -672,6 +672,13 @@ test_expect_success 'setup failing pre-commit' '
test_commit --no-verify pre-commit-violated-2
 '
 
+test_expect_success 'reword a commit violating pre-commit' '
+   git checkout -b reword-violating-pre-commit violating-pre-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   env FAKE_LINES=reword 1 git rebase -i master
+'
+
 test_expect_success 'squash a commit violating pre-commit' '
git checkout -b squash-violating-pre-commit violating-pre-commit 
test_when_finished reset_rebase 
@@ -715,6 +722,13 @@ test_expect_success 'rebase a commit violating commit-msg' 
'
FAKE_LINES=1 git rebase -i master
 '
 
+test_expect_success 'reword a commit violating commit-msg' '
+   git checkout -b reword-violating-commit-msg violating-commit-msg 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=reword 1 git rebase -i master
+'
+
 test_expect_success 'squash a commit violating commit-msg' '
git checkout -b squash-violating-commit-msg violating-commit-msg 
set_fake_editor 
-- 
2.0.1

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


[PATCH v2 06/23] commit: allow disabling pre-commit and commit-msg separately

2014-08-06 Thread Fabian Ruch
Introduce the git-commit command line options `--no-pre-commit` and
`--no-commit-msg` to disable the pre-commit and commit-msg hooks,
respectively. Make `--no-verify` a synonym for specifying both at the
same time.

This change is motivated by an internal usage of git-commit in
git-rebase--interactive to disable pre-commit while keeping
commit-msg enabled when rewording a commit.

Make `test_commit` forward unknown options to git-commit instead of
teaching it all possible options. In order to support leading double
dashes in `message`, stop interpreting `test_commit` arguments
following a `--` argument as options. This wasn't a problem before
because the first unknown option would be used as `message`.

Allow disabling tag creation to avoid name clashes when using
`test_commit` with the same arguments several times from the same
test suite. By default, `test_commit` tags successful commits using
git-tag for easy reference. The `--notag` option skips this step.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 Documentation/git-commit.txt |  8 -
 builtin/commit.c | 32 ++---
 t/t7503-pre-commit-hook.sh   | 65 -
 t/t7504-commit-msg-hook.sh   | 85 ++--
 t/test-lib-functions.sh  | 23 
 5 files changed, 176 insertions(+), 37 deletions(-)

diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 0bbc8f5..28a2c5c 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -158,7 +158,7 @@ OPTIONS
 
 -n::
 --no-verify::
-   This option bypasses the pre-commit and commit-msg hooks.
+   A synonym for `--no-pre-commit --no-commit-msg`.
See also linkgit:githooks[5].
 
 --allow-empty::
@@ -238,6 +238,12 @@ You should understand the implications of rewriting 
history if you
 amend a commit that has already been published.  (See the RECOVERING
 FROM UPSTREAM REBASE section in linkgit:git-rebase[1].)
 
+--no-pre-commit::
+   This option bypasses the pre-commit hook.
+
+--no-commit-msg::
+   This option bypasses the commit-msg hook.
+
 --no-post-rewrite::
Bypass the post-rewrite hook.
 
diff --git a/builtin/commit.c b/builtin/commit.c
index 5ed6036..dfd354e 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -98,12 +98,27 @@ static char *edit_message, *use_message;
 static char *fixup_message, *squash_message;
 static int all, also, interactive, patch_interactive, only, amend, signoff;
 static int edit_flag = -1; /* unspecified */
-static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
+static int quiet, verbose, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
 static char *sign_commit;
 
 /*
+ * The verify variable is interpreted as a bitmap of enabled commit
+ * verification hooks according to the legend below.
+ *
+ * By default, the pre-commit and commit-msg hooks are enabled. This
+ * is represented by both the PRE_COMMIT and COMMIT_MSG bits being
+ * set.
+ *
+ * The bitmap is changed through the command line options
+ * --no-verify, --no-pre-commit and --no-commit-msg.
+ */
+#define PRE_COMMIT (10)
+#define COMMIT_MSG (11)
+static int verify = PRE_COMMIT | COMMIT_MSG;
+
+/*
  * The default commit message cleanup mode will remove the lines
  * beginning with # (shell comments) and leading and trailing
  * whitespaces (empty lines or containing only whitespaces)
@@ -661,7 +676,8 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
/* This checks and barfs if author is badly specified */
determine_author_info(author_ident);
 
-   if (!no_verify  run_commit_hook(use_editor, index_file, pre-commit, 
NULL))
+   if (verify  PRE_COMMIT 
+   run_commit_hook(use_editor, index_file, pre-commit, NULL))
return 0;
 
if (squash_message) {
@@ -962,7 +978,7 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
}
}
 
-   if (!no_verify 
+   if (verify  COMMIT_MSG 
run_commit_hook(use_editor, index_file, commit-msg, 
git_path(commit_editmsg), NULL)) {
return 0;
}
@@ -1590,7 +1606,9 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
OPT_BOOL(0, interactive, interactive, N_(interactively add 
files)),
OPT_BOOL('p', patch, patch_interactive, N_(interactively 
add changes)),
OPT_BOOL('o', only, only, N_(commit only specified files)),
-   OPT_BOOL('n', no-verify, no_verify, N_(bypass pre-commit 
hook)),
+   OPT_NEGBIT('n', no-verify, verify,
+  N_(synonym for --no-pre-commit --no-commit-msg),
+  PRE_COMMIT | COMMIT_MSG),
OPT_BOOL(0, dry-run, dry_run, N_(show what would be 
committed

[PATCH v2 09/23] rebase -i: teach do_pick the option --edit

2014-08-06 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`. To cater for
the different pick behaviours (like `reword`), `do_pick` accepts
several options not only from the git-cherry-pick but also the
git-commit interface. Add the common option `--edit` to let the user
edit the log message of the named commit.

Loop over `$@` to parse the `do_pick` arguments. Assign the local
variable `edit` if one of the options is `--edit` so that the
remainder of `do_pick` can easily check whether the client code asked
to edit the commit message. If one of the options is unknown, mention
it on the console and `die`. Break the loop on the first non-option
and do some sanity checking to ensure that there exactly two
non-options, which are interpreted by the remainder as `commit` and
`title` like before.

`do_pick` ought to act as a wrapper around `cherry-pick`.
Unfortunately, it cannot just forward `--edit` to the `cherry-pick`
command line. The assembled command line is executed within a command
substitution for controlling the verbosity of `rebase--interactive`.
Passing `--edit` would either hang the terminal or clutter the
substituted command output with control sequences. Execute the
`reword` code from `do_next` instead if the option `--edit` is
specified.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index edc323d..aed2f93 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -461,7 +461,42 @@ record_in_rewritten() {
esac
 }
 
+# Apply the changes introduced by the given commit to the current head.
+#
+# do_pick [--edit] commit title
+#
+# Wrapper around git-cherry-pick.
+#
+# -e, --edit
+# After picking commit, open an editor and let the user edit the
+# commit message. The editor contents becomes the commit message of
+# the new head. This creates a fresh commit.
+#
+# commit
+# The commit to cherry-pick.
+#
+# title
+# The commit message title of commit. Used for information
+# purposes only.
 do_pick () {
+   edit=
+   while test $# -gt 0
+   do
+   case $1 in
+   -e|--edit)
+   edit=y
+   ;;
+   -*)
+   die do_pick: unrecognized option -- $1
+   ;;
+   *)
+   break
+   ;;
+   esac
+   shift
+   done
+   test $# -ne 2  die do_pick: wrong number of arguments
+
if test $(git rev-parse HEAD) = $squash_onto
then
# Set the correct commit message and author info on the
@@ -483,6 +518,14 @@ do_pick () {
pick_one $1 ||
die_with_patch $1 Could not apply $1... $2
fi
+
+   if test -n $edit
+   then
+   output git commit --allow-empty --amend --no-post-rewrite 
--no-pre-commit ${gpg_sign_opt:+$gpg_sign_opt} || {
+   warn Could not amend commit after successfully picking 
$1... $2
+   exit_with_patch $1 1
+   }
+   fi
 }
 
 do_next () {
-- 
2.0.1

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


[PATCH v2 15/23] rebase -i: teach do_pick the option --amend

2014-08-06 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list commands `pick`, `reword`
and `edit`. To cater for the different pick behaviours (like
`squash`), `do_pick` accepts several options not only from the
git-cherry-pick but also the git-commit interface.

Add the option `--amend` from the git-commit interface to the options
pool of `do_pick`. It creates a new commit for the changes introduced
by the picked commit and the previous one. The previous commit is
then replaced with the new commit. If no other options are specified,
the log message of the previous commit is used.

Be careful when `--amend` is used to pick a root commit because HEAD
might point to the sentinel commit but there is still nothing to
amend. Be sure to initialize `amend` so that commits are squashed
even when git-rebase--interactive is interrupted for resolving
conflicts. It is not a mistake to do the initialization regardless of
any conflicts because `amend` is always cleared before the next to-do
item is processed.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index d812bad..0871302 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,16 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit
+# do_pick [--amend] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --amend
+# After picking commit, replace the current head commit with a new
+# commit that also introduces the changes of commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -489,6 +495,16 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   --amend)
+   if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse -q --verify HEAD /dev/null
+   then
+   warn do_pick: nothing to amend
+   return 2
+   fi
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
-- 
2.0.1

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


[PATCH v2 20/23] rebase -i: parse to-do list command line options

2014-08-06 Thread Fabian Ruch
Read in to-do list lines as

command args

instead of

command sha1 rest

so that to-do list command lines can specify additional arguments
apart from the commit hash and the log message title, which become
the non-options in `args`. Loop over `args`, put all options (an
argument beginning with a dash) in `opts`, stop the loop on the first
non-option and assign it to `sha1`. The loop does not know the
options it parses so that options that take an argument themselves
are not supported at the moment. Neither are options that contain
spaces because the shell expansion of `args` in `do_next` interprets
white space characters as argument separator, that is a command line
like

pick --author A U Thor fa1afe1 Some change

is parsed as the pick command

pick --author

and the commit hash

A

which obviously results in an unknown revision error. For the sake of
completeness, in the example above the message title variable `rest`
is assigned the string 'U Thor fa1afe1 Some change' (without the
single quotes).

Print an error message for unknown or unsupported command line
options, which means an error for all specified options at the
moment. Cleanly break the `do_next` loop by assigning the special
value 'unknown' to the local variable `command`, which triggers the
unknown command case in `do_cmd`.

The to-do list is also parsed when the commit hashes are translated
between long and short format before and after the to-do list is
edited. Apply the same procedure as in `do_cmd` with the exception
that we only care about where the options stop and the commit hash
begins. Do not reject any options when transforming the commit
hashes.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 49 ++
 1 file changed, 41 insertions(+), 8 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 6ecd4d7..da435cb 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -577,8 +577,26 @@ do_pick () {
 
 do_replay () {
command=$1
-   sha1=$2
-   rest=$3
+   shift
+
+   opts=
+   while test $# -gt 0
+   do
+   case $1 in
+   -*)
+   warn Unknown option: $1
+   command=unknown
+   ;;
+   *)
+   break
+   ;;
+   esac
+   opts=$opts $(git rev-parse --sq-quote $1)
+   shift
+   done
+   sha1=$1
+   shift
+   rest=$*
 
case $command in
pick|p)
@@ -675,7 +693,7 @@ do_replay () {
 
 do_next () {
rm -f $msg $author_script $amend || exit
-   read -r command sha1 rest $todo
+   read -r command args $todo
 
case $command in
$comment_char*|''|noop)
@@ -720,7 +738,7 @@ do_next () {
fi
;;
*)
-   do_replay $command $sha1 $rest
+   do_replay $command $args
;;
esac
test -s $todo  return
@@ -800,19 +818,34 @@ skip_unnecessary_picks () {
 }
 
 transform_todo_ids () {
-   while read -r command rest
+   while read -r command args
do
case $command in
$comment_char* | exec)
# Be careful for oddball commands like 'exec'
# that do not have a SHA-1 at the beginning of $rest.
+   newargs=\ $args
;;
*)
-   sha1=$(git rev-parse --verify --quiet $@ ${rest%% *}) 

-   rest=$sha1 ${rest#* }
+   newargs=
+   sha1=
+   for arg in $args
+   do
+   case $arg in
+   -*)
+   newargs=$newargs $arg
+   ;;
+   *)
+   test -z $sha1 
+   sha1=$(git rev-parse --verify 
--quiet $@ $arg) 
+   arg=$sha1
+   newargs=$newargs $arg
+   ;;
+   esac
+   done
;;
esac
-   printf '%s\n' $command${rest:+ }$rest
+   printf '%s\n' $command$newargs
done $todo $todo.new 
mv -f $todo.new $todo
 }
-- 
2.0.1

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


[PATCH v2 16/23] rebase -i: teach do_pick the option --file

2014-08-06 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`, `reword` and
`edit`. To cater for the different pick behaviours (like `squash`),
`do_pick` accepts several options not only from the git-cherry-pick
but also the git-commit interface.

Add the option `--file` from the git-commit interface to the options
pool of `do_pick`. It expects an argument itself which is interpreted
as a file path and takes the commit message from the given file. If
`--file` is passed to `do_pick`, assign the given file path to the
local variable `rewrite_message` and relay the option

--file $rewrite_message

to the git-commit command line which creates the commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 20 +++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 0871302..0fbf773 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--edit] commit
+# do_pick [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -474,6 +474,12 @@ record_in_rewritten() {
 #
 # _This is not a git-cherry-pick option._
 #
+# -F file, --file file
+# Take the commit message from the given file. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -492,6 +498,7 @@ do_pick () {
rewrite=
rewrite_amend=
rewrite_edit=
+   rewrite_message=
while test $# -gt 0
do
case $1 in
@@ -505,6 +512,16 @@ do_pick () {
rewrite_amend=y
git rev-parse --verify HEAD $amend
;;
+   -F|--file)
+   if test $# -eq 0
+   then
+   warn do_pick: option --file specified but no 
file given
+   return 2
+   fi
+   rewrite=y
+   rewrite_message=$2
+   shift
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
@@ -553,6 +570,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit --commit-msg} \
+  ${rewrite_message:+--file $rewrite_message} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 }
-- 
2.0.1

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


Re: [PATCH v1 00/19] Enable options --signoff, --reset-author for pick, reword

2014-08-04 Thread Fabian Ruch
Hi Peff,

Jeff King writes:
 On Tue, Jul 29, 2014 at 01:18:00AM +0200, Fabian Ruch wrote:
 this is a reroll of the patch series that enables rudimentary support
 of line options for git-rebase's to-do list commands and reimplements
 the well-known commands `reword` and `squash` in terms of a
 parameterised `do_pick`.
 
 I just finished reading over the whole series (which is my first real
 exposure to it). With the exception of the comments I already sent, it
 looks pretty reasonable to me.
 
 Thanks for splitting it and writing good commit messages; that made it
 relatively easy to follow what was going on.

Thanks a lot for taking the time.

Your review revealed more shortcomings of the patch series. Now that the
replay of root commits is logged, the log is dumped on the console even
in non-verbose mode. And, I must admit that the fact that `--no-edit`
hasn't been a (documented) feature of git-commit for all time didn't
struck me at all as a possible reason for using `-C`, which is a little
embarrassing.

I will include more details in separate replies to your comments later.

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


Re: [PATCH RFC v2 05/19] rebase -i: Implement reword in terms of do_pick

2014-08-04 Thread Fabian Ruch
Hi Matthieu,

thanks for taking a look at this patch series. I might have caused some
confusion by starting with version v1 again after removing the RFC tag.
The current reroll[1] is tagged with PATCH v1, not PATCH RFC v2.

I'm sorry if this is the reason why your reply appears on this sub-thread.

Your concerns below are of course noted.

   Fabian

[1] http://article.gmane.org/gmane.comp.version-control.git/254361

Matthieu Moy writes:
 Fabian Ruch baf...@gmail.com writes:
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -555,20 +555,7 @@ do_next () {
  comment_for_reflog reword
  
  mark_action_done
 -do_pick $sha1 $rest
 -# TODO: Work around the fact that git-commit lets us
 -# disable either both the pre-commit and the commit-msg
 -# hook or none. Disable the pre-commit hook because the
 -# tree is left unchanged but run the commit-msg hook
 -# from here because the log message is altered.
 -git commit --allow-empty --amend --no-post-rewrite -n 
 ${gpg_sign_opt:+$gpg_sign_opt} 
 -if test -x $GIT_DIR/hooks/commit-msg
 -then
 -$GIT_DIR/hooks/commit-msg 
 $GIT_DIR/COMMIT_EDITMSG
 -fi || {
 -warn Could not amend commit after successfully 
 picking $sha1... $rest
 -exit_with_patch $sha1 1
 -}
 +do_pick --edit $sha1 $rest
 
 I would have found this easier to review if squashed into the previous
 patch. My reaction reading the previous patch was Uh, why duplicate
 code?, and reading this one Ah, that's OK. A single patch doing both
 would have avoided the confusion.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit

2014-08-04 Thread Fabian Ruch
Hi,

Jeff King writes:
 On Tue, Jul 29, 2014 at 01:18:03AM +0200, Fabian Ruch wrote:
 
 Specify the git-commit option `--no-verify` to disable the pre-commit
 hook when editing the log message. Because `--no-verify` also skips
 the commit-msg hook, execute the hook from within
 git-rebase--interactive after the commit is created. Fortunately, the
 commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after
 git-commit terminates. Caveat: In case the commit-msg hook finds the
 new log message ill-formatted, the user is only notified of the
 failed commit-msg hook but the log message is used for the commit
 anyway. git-commit ought to offer more fine-grained control over
 which hooks are executed.
 
 Thanks for a nice explanation of the tradeoff. Have you looked at adding
 an option to git-commit? We already have --no-post-rewrite. I think you
 would just need:
 
 diff --git a/builtin/commit.c b/builtin/commit.c
 index 5ed6036..f7af220 100644
 --- a/builtin/commit.c
 +++ b/builtin/commit.c
 @@ -102,6 +102,7 @@ static int quiet, verbose, no_verify, allow_empty, 
 dry_run, renew_authorship;
  static int no_post_rewrite, allow_empty_message;
  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
  static char *sign_commit;
 +static int no_pre_commit;
  
  /*
   * The default commit message cleanup mode will remove the lines
 @@ -661,7 +662,8 @@ static int prepare_to_commit(const char *index_file, 
 const char *prefix,
   /* This checks and barfs if author is badly specified */
   determine_author_info(author_ident);
  
 - if (!no_verify  run_commit_hook(use_editor, index_file, pre-commit, 
 NULL))
 + if (!no_verify  !no_pre_commit 
 + run_commit_hook(use_editor, index_file, pre-commit, NULL))
   return 0;
  
   if (squash_message) {
 @@ -1604,6 +1606,7 @@ int cmd_commit(int argc, const char **argv, const char 
 *prefix)
N_(terminate entries with NUL)),
   OPT_BOOL(0, amend, amend, N_(amend previous commit)),
   OPT_BOOL(0, no-post-rewrite, no_post_rewrite, N_(bypass 
 post-rewrite hook)),
 + OPT_BOOL(0, no-pre-commit, no_pre_commit, N_(bypass 
 pre-commit hook)),
   { OPTION_STRING, 'u', untracked-files, untracked_files_arg, 
 N_(mode), N_(show untracked files, optional modes: all, normal, no. 
 (Default: all)), PARSE_OPT_OPTARG, NULL, (intptr_t)all },
   /* end commit contents options */
  
 
 though I would also not be opposed to some more uniform hook selection
 mechanism (e.g., --no-verify=pre-commit or something).

While the --no-verify= mechanism doesn't add a new option to the
git-commit interface but lets one refine the --no-verify option, users
might find it weird to have an argument to name disabled hooks but then
not be able to disable all hooks that way.

To have that uniform hook selection without duplicating code, we might
want to have something like --bypass-hook= right away. This would cover
--no-post-rewrite as well and add support for disabling
prepare-commit-msg and post-commit, whose execution cannot be controlled
via the git-commit interface at the moment.

Since the hook selection wouldn't have to change, the options parsing
code seems to be simpler (--bypass-hook= would have to support several
occurrences with different arguments which could be implemented as an
OPT_CALLBACK?) and git-commit decided to have --no- options for hook
selection so far, I would lean towards your patch from above.

I know you didn't say anything otherwise, I just wanted to expand a
little. You find an amended version of your patch below that documents
--no-verify as a synonym for --no-pre-commit and --no-commit-msg, and
adds tests.

 diff --git a/builtin/commit.c b/builtin/commit.c
 index 5e2221c..813aa78 100644
 --- a/builtin/commit.c
 +++ b/builtin/commit.c
 @@ -98,12 +98,27 @@ static char *edit_message, *use_message;
  static char *fixup_message, *squash_message;
  static int all, also, interactive, patch_interactive, only, amend, signoff;
  static int edit_flag = -1; /* unspecified */
 -static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 +static int quiet, verbose, allow_empty, dry_run, renew_authorship;
  static int no_post_rewrite, allow_empty_message;
  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
  static char *sign_commit;
  
  /*
 + * The verify variable is interpreted as a bitmap of enabled commit
 + * verification hooks according to the legend below.
 + *
 + * By default, the pre-commit and commit-msg hooks are enabled. This
 + * is represented by both the PRE_COMMIT and COMMIT_MSG bits being
 + * set.
 + *
 + * The bitmap is changed through the command line options
 + * --no-verify, --no-pre-commit and --no-commit-msg.
 + */
 +#define PRE_COMMIT (10)
 +#define COMMIT_MSG (11)
 +static int verify = PRE_COMMIT | COMMIT_MSG;
 +
 +/*
   * The default commit message cleanup mode will remove the lines

Re: [PATCH v1 07/19] rebase -i: log the replay of root commits

2014-08-04 Thread Fabian Ruch
Hi,

Jeff King writes:
 On Tue, Jul 29, 2014 at 01:18:07AM +0200, Fabian Ruch wrote:
 The command line used to recreate root commits specifies the option
 `-q` which suppresses the commit summary message. However,
 git-rebase--interactive tends to tell the user about the commits it
 creates in the final history, if she wishes (cf. command line option
 `--verbose`). The code parts handling non-root commits and squash
 commits all output commit summary messages. Do not make the replay of
 root commits an exception. Remove the option to make the report of
 the rebased history complete.

 It is OK that the commit summary is still suppressed when git-commit
 is used to initialize the authorship of the sentinel commit because
 this additional commit is an implementation detail hidden from the
 final history. The removed `-q` option was probably introduced as a
 copy-and-paste error stemming from that part of the root commit
 handling code.
 
 I'm confused. This implies that we should be seeing summaries for other
 commits, but not root commits, and this patch is bring them into
 harmony.  But if I have a repo like this:
 
   git init -q repo 
   cd repo 
   for i in one two; do
 echo $i file 
 git add file 
 git commit -q -m $i
   done
 
 then using stock git gives me this:
 
   $ GIT_EDITOR=true git rebase -i --root 21 | perl -pe 's/\r/\\r\n/g'
   Rebasing (1/2)\r
   Rebasing (2/2)\r
   Successfully rebased and updated refs/heads/master.
 
 but with your patch, I get:
 
   $ GIT_EDITOR=true git.compile rebase -i --root 21 | perl -pe 
 's/\r/\\r\n/g'
   Rebasing (1/2)\r
   [detached HEAD 60834b3] one
Date: Fri Aug 1 20:00:05 2014 -0400
1 file changed, 1 insertion(+)
create mode 100644 file
   Rebasing (2/2)\r
   Successfully rebased and updated refs/heads/master.
 
 Am I misunderstanding the purpose of the patch?

Thanks for laying out the differences in the user visible output. With
stock git we are seeing summaries for other commits, but not root
commits, _with the --verbose option_. It's the fault of my patch to show
the summary even in non-verbose mode. This is now fixed by wrapping the
relevant command in 'output', a shell function defined in git-rebase.sh
as follows:

 output=$($@ 21 )
 status=$?
 test $status != 0  printf %s\n $output
 return $status

The problem that git-rebase--interactive has is that the redirection of
stdin to a variable (or a file) does not work reliably with commands
that invoke the log message editor, that is 'reword' and 'squash'
produce their output both in verbose and non-verbose mode. I wouldn't
know how to fix this but

1) invoking $GIT_EDITOR from git-rebase--interactive.sh, but to make
this right there should be a built-in command for shell scripts and an
interface for git-commit that prepare the editor contents like
git-commit does now, or

2) forcing $GIT_EDITOR and git-commit to print on distinct file
descriptors, which would involve temporarily wrapping the $GIT_EDITOR
call in a shell script that redirects stdin to some other file
descriptor similar to what t/test-lib.sh does, or

 cat $state_dir/editor.sh EOF
 #!/bin/sh
 $(git var GIT_EDITOR) \$* 3
 EOF
 chmod +x $state_dir/editor.sh
 (
 export GIT_EDITOR=$state_dir/editor.sh
 $@ 31 $state_dir/output 21
 )

3) passing the --quiet option in non-verbose mode and omitting it in
verbose mode, which would cover the '$status != 0' above for if a
command fails, it should indicate its error status despite being asked
to be silent.

Options 2) and 3) seem attainable within this patch series and 3) sounds
like the cleanest option but I'm uncertain if I'm missing something
here. The only command line that is wrapped in 'output' and that doesn't
support a --quiet option seems to be a 'warn' line which could simply be
skipped in non-verbose mode. (Johannes Schindelin is cc'd as the
original author of git-rebase--interactive.sh and 'output' in particular).

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


Re: [PATCH v1 08/19] rebase -i: root commits are replayed with an unnecessary option

2014-08-04 Thread Fabian Ruch
Hi Jeff,

Jeff King writes:
 On Tue, Jul 29, 2014 at 01:18:08AM +0200, Fabian Ruch wrote:
 The command line used to recreate root commits specifies the
 effectless option `-C`. It makes git-commit reuse commit message and
 authorship of the named commit. However, the commit being amended
 here, which is the sentinel commit, already carries the authorship
 and log message of the commit being replayed. Remove the option.

 Since `-C` (in contrast to `-c`) does not invoke the editor and the
 `--amend` option invokes it by default, disable editor invocation
 again by specifying `--no-edit`.
 
 I found this description a little backwards. The -C does have an
 effect, as you noticed in the second paragraph.
 
 I think the reasoning is more like:
 
   The command line used to recreate root commits uses -C to
   suppress the commit editor. This is unnecessarily confusing,
   though, because that suppression is a secondary effect of the
   option. The main purpose of -C is to pull the metadata from
   another commit, but here we know that this is a noop, since we
   are amending a commit just created from the same data.
 
   At the time, commit did not yet know --no-edit, and this was a
   reasonable way to get the desired behavior. We can switch it to
   use --no-edit to make the intended effect more obvious.

Thanks again, I shamelessly copied your formulation but squeezed in an
undocumented because --no-edit had just been implemented (commit
ca1ba2010), though was then still missing from the git-commit manpage.

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


[PATCH] commit --amend: test specifies authorship but forgets to check

2014-07-30 Thread Fabian Ruch
The test case --amend option copies authorship specifies that the
git-commit option `--amend` uses the authorship of the replaced
commit for the new commit. Add the omitted check that this property
actually holds.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
Without the check, the test case succeeds even with nonsense in the
`expected` file. An `--amend` implementation which simply uses the
committer name and date as if it was not amending would have been
deemed correct. This is not the case, the implementation still passes
the test suite after the correction.

Quickly skimming over the rest of the file, I couldn't find the same
thing twice.

 t/t7509-commit.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh
index b61fd3c..9ac7940 100755
--- a/t/t7509-commit.sh
+++ b/t/t7509-commit.sh
@@ -77,6 +77,7 @@ test_expect_success '--amend option copies authorship' '
git commit -a --amend -m amend test 
author_header Initial expect 
author_header HEAD actual 
+   test_cmp expect actual 
 
echo amend test expect 
message_body HEAD actual 
-- 
2.0.1

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


[PATCH v1 00/19] Enable options --signoff, --reset-author for pick, reword

2014-07-28 Thread Fabian Ruch
Hi,

this is a reroll of the patch series that enables rudimentary support
of line options for git-rebase's to-do list commands and reimplements
the well-known commands `reword` and `squash` in terms of a
parameterised `do_pick`.

I tried to address all the issues raised by Junio in this reroll.
Here is a short summary.

 - Test that `reword` behaves like `pick` regarding the `pre-commit`
   hook and executes `commit-msg` for the new log message.

 - Instead of disallowing empty log messages for root commits allow
   empty log messages for all unchanged commits.

 - The patch root commits are replayed with an unnecessary option
   does not change the behaviour of git-rebase but it makes the
   subsequent patch easier to read.

   The hidden agenda is to have one git-commit command line in
   `do_pick` that takes care of rewriting commits as they are being
   replayed, be they parentless or not. The advantage of having one
   rewrite command instead of one for root commits and one for
   non-root commits is that changes to the rewrite mechanism entail
   less code changes. As more rewriting mechanisms are being added to
   `do_pick`, it becomes important that they compose well with each
   other to avoid having a series of amending commits. The `-C`
   option conflicts with other ways of substituting the log message,
   like files and strings, which is why it seems not to compose so
   well.

 - The patch explicitly distinguish replay commands and exec tasks
   does not change behaviour either but is again a separated
   refactoring patch.

   The distinction of the `exec` command and the replay commands,
   which all share the same line format `command args sha1 rest`,
   allows us to employ the positional parameters feature of the shell
   without introducing another indentation level in `do_pick`.

Thanks for your time,
   Fabian

Fabian Ruch (19):
  rebase -i: failed reword prints redundant error message
  rebase -i: allow rewording an empty commit without complaints
  rebase -i: reword executes pre-commit hook on interim commit
  rebase -i: teach do_pick the option --edit
  rebase -i: implement reword in terms of do_pick
  rebase -i: allow replaying commits with empty log messages
  rebase -i: log the replay of root commits
  rebase -i: root commits are replayed with an unnecessary option
  rebase -i: commit only once when rewriting picks
  rebase -i: do not die in do_pick
  rebase -i: teach do_pick the option --amend
  rebase -i: teach do_pick the option --file
  rebase -i: prepare for squash in terms of do_pick --amend
  rebase -i: implement squash in terms of do_pick
  rebase -i: explicitly distinguish replay commands and exec tasks
  rebase -i: parse to-do list command line options
  rebase -i: teach do_pick the option --reset-author
  rebase -i: teach do_pick the option --signoff
  rebase -i: enable options --signoff, --reset-author for pick, reword

 git-rebase--interactive.sh| 284 ++
 t/t3404-rebase-interactive.sh |  70 +++
 t/t3412-rebase-root.sh|  19 +++
 t/test-lib-functions.sh   |   6 +-
 4 files changed, 325 insertions(+), 54 deletions(-)

-- 
2.0.1

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


[PATCH v1 01/19] rebase -i: failed reword prints redundant error message

2014-07-28 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If the edited log
message is empty or is found ill-formatted by one of the commit
hooks, git-rebase--interactive prints three error messages to the
console.

1. The git-commit output, which contains all the output from hook
   scripts.
2. A rebase diagnosis saying at which task on the to-do list it
   got stuck.
3. Generic presumptions about what could have triggered the
   error.

The third message contains redundant information and does not add any
enlightenment either, which makes the output unnecessarily longish
and different from the other command's output. For instance, this is
what the output looks like if the log message is empty (contains
duplicate Signed-off-by lines).

(1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by 
lines.)
(2.) Could not amend commit after successfully picking fa1afe1... Some 
change
(3.) This is most likely due to an empty commit message, or the pre-commit 
hook
 failed. If the pre-commit hook failed, you may need to resolve the 
issue before
 you are able to reword the commit.

Discard the third message.

It is true that a failed hook script might not output any diagnosis
but then the generic message is not of much help either. Since this
lack of information affects the built-in git commands for commit,
merge and cherry-pick first, the solution would be to keep track of
the failed hooks in their output so that the user knows which of her
hooks require improvement.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 7e1eda0..e733d7f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -506,9 +506,6 @@ do_next () {
do_pick $sha1 $rest
git commit --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
-   warn This is most likely due to an empty commit 
message, or the pre-commit hook
-   warn failed. If the pre-commit hook failed, you may 
need to resolve the issue before
-   warn you are able to reword the commit.
exit_with_patch $sha1 1
}
record_in_rewritten $sha1
-- 
2.0.1

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


[PATCH v1 02/19] rebase -i: allow rewording an empty commit without complaints

2014-07-28 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If `--keep-empty` is
passed as option to git-rebase--interactive, empty commits ought to
be replayed without complaints. However, if the users chooses to
reword an empty commit by changing the respective to-do list entry
from

pick fa1afe1 Empty commit

to

reword fa1afe1 Empty commit

, then git-rebase--interactive suddenly fails to replay the empty
commit. This is especially counterintuitive because `reword` is
thought of as a `pick` that alters the log message in some way but
nothing more and the unchanged to-do list entry would not fail.

Handle `reword` by cherry-picking the named commit and editing the
log message using

git commit --allow-empty --amend

instead of

git commit --amend.

Add test.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 2 +-
 t/t3404-rebase-interactive.sh | 8 
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index e733d7f..689400e 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,7 +504,7 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
+   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
warn Could not amend commit after successfully picking 
$sha1... $rest
exit_with_patch $sha1 1
}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8197ed2..9931143 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -75,6 +75,14 @@ test_expect_success 'rebase --keep-empty' '
test_line_count = 6 actual
 '
 
+test_expect_success 'rebase --keep-empty' '
+   git checkout emptybranch 
+   set_fake_editor 
+   FAKE_LINES=1 reword 2 git rebase --keep-empty -i HEAD~2 
+   git log --oneline actual 
+   test_line_count = 6 actual
+'
+
 test_expect_success 'rebase -i with the exec command' '
git checkout master 
(
-- 
2.0.1

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


[PATCH v1 11/19] rebase -i: teach do_pick the option --amend

2014-07-28 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list commands `pick`, `reword`
and `edit`. To cater for the different pick behaviours (like
`squash`), `do_pick` accepts several options not only from the
git-cherry-pick but also the git-commit interface.

Add the option `--amend` from the git-commit interface to the options
pool of `do_pick`. It creates a new commit for the changes introduced
by the picked commit and the previous one. The previous commit is
then replaced with the new commit. If no other options are specified,
the log message of the previous commit is used.

Be careful when `--amend` is used to pick a root commit because HEAD
might point to the sentinel commit but there is still nothing to
amend. Be sure to initialize `amend` so that commits are squashed
even when git-rebase--interactive is interrupted for resolving
conflicts. It is not a mistake to do the initialization regardless of
any conflicts because `amend` is always cleared before the next to-do
item is processed.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 9f08f1b..22a8f7b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,16 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit
+# do_pick [--amend] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --amend
+# After picking commit, replace the current head commit with a new
+# commit that also introduces the changes of commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -489,6 +495,16 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   --amend)
+   if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse --verify HEAD
+   then
+   warn do_pick: nothing to amend
+   return 2
+   fi
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
-- 
2.0.1

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


[PATCH v1 09/19] rebase -i: commit only once when rewriting picks

2014-07-28 Thread Fabian Ruch
The options passed to `do_pick` determine whether the picked commit
will be rewritten or not. If the commit gets rewritten, because the
user requested to edit the commit message for instance, let
`pick_one` merely apply the changes introduced by the commit and do
not commit the resulting tree yet. If the commit is replayed as is,
leave it to `pick_one` to recreate the commit (possibly by
fast-forwarding the head). This makes it easier to combine git-commit
options like `--edit` and `--amend` in `do_pick` because
git-cherry-pick does not support `--amend`.

In the case of `--edit`, do not `exit_with_patch` but assign
`rewrite` to pick the changes with `-n`. If the pick conflicts, no
commit is created which we would have to amend when continuing the
rebase. To complete the pick after the conflicts are resolved the
user just resumes with `git rebase --continue`.

git-commit lets the user edit the commit log message by default. We
do not want that for the rewriting git-commit command line because
the default behaviour of git-rebase is exactly the opposite. Pass
`--no-edit` when rewriting a picked commit. An explicit `--edit`
passed to `do_pick` (for instance, when reword is executed) enables
the editor launch again. Similarly, pass `--allow-empty-message`
unless the log message is edited.

If `rebase--interactive` is used to rebase a complete branch onto
some head, `rebase` creates a sentinel commit that requires special
treatment by `do_pick`. Do not finalize the pick here either because
its commit message can be altered as for any other pick. Since the
orphaned root commit gets a temporary parent, it is always rewritten.
Safely use the rewrite infrastructure of `do_pick` to create the
final commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 58 --
 1 file changed, 36 insertions(+), 22 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 46f436f..96c24e8 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -63,7 +63,8 @@ msgnum=$state_dir/msgnum
 author_script=$state_dir/author-script
 
 # When an edit rebase command is being processed, the SHA1 of the
-# commit to be edited is recorded in this file.  When git rebase
+# commit to be edited is recorded in this file.  The same happens when
+# rewriting a commit fails, for instance reword.  When git rebase
 # --continue is executed, if there are any staged changes then they
 # will be amended to the HEAD commit, but only provided the HEAD
 # commit is still the commit to be edited.  When any other rebase
@@ -479,12 +480,17 @@ record_in_rewritten() {
 # The commit message title of commit. Used for information
 # purposes only.
 do_pick () {
-   edit=
+   allow_empty_message=y
+   rewrite=
+   rewrite_amend=
+   rewrite_edit=
while test $# -gt 0
do
case $1 in
-e|--edit)
-   edit=y
+   rewrite=y
+   rewrite_edit=y
+   allow_empty_message=
;;
-*)
die do_pick: unrecognized option -- $1
@@ -499,6 +505,10 @@ do_pick () {
 
if test $(git rev-parse HEAD) = $squash_onto
then
+   rewrite=y
+   rewrite_amend=y
+   git rev-parse --verify HEAD $amend
+
# Set the correct commit message and author info on the
# sentinel root before cherry-picking the original changes
# without committing (-n).  Finally, update the sentinel again
@@ -509,31 +519,35 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 
-   git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n --no-edit \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
+   pick_one -n $1 ||
die_with_patch $1 Could not apply $1... $2
else
-   pick_one $1 ||
+   pick_one ${rewrite:+-n} $1 ||
die_with_patch $1 Could not apply $1... $2
fi
 
-   if test -n $edit
+   if test -n $rewrite
then
-   # TODO: Work around the fact that git-commit lets us
-   # disable either both the pre-commit and the commit-msg
-   # hook or none. Disable the pre-commit hook because the
-   # tree is left unchanged but run the commit-msg hook
-   # from here because the log message is altered.
-   git commit --allow-empty --amend --no-post-rewrite -n 
${gpg_sign_opt:+$gpg_sign_opt} 
-   if test -x $GIT_DIR/hooks/commit-msg

[PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit

2014-07-28 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. This happens in two
steps. Firstly, the named commit is cherry-picked. Secondly, the
commit created in the first step is amended using an unchanged index
to edit the log message. The pre-commit hook is meant to verify the
changes introduced by a commit (for instance, catching inserted
trailing white space). Since the committed tree is not changed
between the two steps and we do not verify rebased patches, do not
execute the pre-commit hook in the second step.

Specify the git-commit option `--no-verify` to disable the pre-commit
hook when editing the log message. Because `--no-verify` also skips
the commit-msg hook, execute the hook from within
git-rebase--interactive after the commit is created. Fortunately, the
commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after
git-commit terminates. Caveat: In case the commit-msg hook finds the
new log message ill-formatted, the user is only notified of the
failed commit-msg hook but the log message is used for the commit
anyway. git-commit ought to offer more fine-grained control over
which hooks are executed.

Teach `test_commit` the `--no-verify` option and add test.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh| 17 +
 t/t3404-rebase-interactive.sh | 38 ++
 t/test-lib-functions.sh   |  6 +-
 3 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 689400e..b50770d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -504,10 +504,19 @@ do_next () {
 
mark_action_done
do_pick $sha1 $rest
-   git commit --allow-empty --amend --no-post-rewrite 
${gpg_sign_opt:+$gpg_sign_opt} || {
-   warn Could not amend commit after successfully picking 
$sha1... $rest
-   exit_with_patch $sha1 1
-   }
+   # TODO: Work around the fact that git-commit lets us
+   # disable either both the pre-commit and the commit-msg
+   # hook or none. Disable the pre-commit hook because the
+   # tree is left unchanged but run the commit-msg hook
+   # from here because the log message is altered.
+   git commit --allow-empty --amend --no-post-rewrite -n 
${gpg_sign_opt:+$gpg_sign_opt} 
+   if test -x $GIT_DIR/hooks/commit-msg
+   then
+   $GIT_DIR/hooks/commit-msg 
$GIT_DIR/COMMIT_EDITMSG
+   fi || {
+   warn Could not amend commit after successfully 
picking $sha1... $rest
+   exit_with_patch $sha1 1
+   }
record_in_rewritten $sha1
;;
edit|e)
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9931143..2da4b9c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -577,6 +577,44 @@ test_expect_success 'rebase a commit violating pre-commit' 
'
 
 '
 
+test_expect_success 'reword a commit violating pre-commit' '
+   test_when_finished rm -r .git/hooks 
+   mkdir -p .git/hooks 
+   PRE_COMMIT=.git/hooks/pre-commit 
+   cat $PRE_COMMIT EOF
+#!/bin/sh
+echo running pre-commit: exit 1
+exit 1
+EOF
+   chmod +x $PRE_COMMIT 
+   test_must_fail test_commit pre-commit-violated 
+   test_commit --no-verify pre-commit-violated 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   FAKE_LINES=pick 1 git rebase -i HEAD^ 
+   FAKE_LINES=pick 1 git rebase -i --no-ff HEAD^ 
+   FAKE_LINES=reword 1 git rebase -i HEAD^
+'
+
+test_expect_success 'reword a commit violating commit-msg' '
+   test_when_finished rm -r .git/hooks 
+   mkdir -p .git/hooks 
+   COMMIT_MSG=.git/hooks/commit-msg 
+   cat $COMMIT_MSG EOF
+#!/bin/sh
+echo running commit-msg: exit 1
+exit 1
+EOF
+   chmod +x $COMMIT_MSG 
+   test_must_fail test_commit commit-msg-violated 
+   test_commit --no-verify commit-msg-violated 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   FAKE_LINES=pick 1 git rebase -i HEAD^ 
+   FAKE_LINES=pick 1 git rebase -i --no-ff HEAD^ 
+   test_must_fail env FAKE_LINES=reword 1 git rebase -i HEAD^
+'
+
 test_expect_success 'rebase with a file named HEAD in worktree' '
 
rm -fr .git/hooks 
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 0377d3e..db65653 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -155,6 +155,7 @@ test_pause () {
 test_commit () {
notick= 
signoff= 
+   noverify= 
while test $# != 0
do
case $1 in
@@ -164,6 +165,9 @@ test_commit () {
--signoff

[PATCH v1 13/19] rebase -i: prepare for squash in terms of do_pick --amend

2014-07-28 Thread Fabian Ruch
Rewrite `squash` and `fixup` handling in `do_next` using the sequence

pick_one
commit

in order to test the correctness of a single `do_squash` or
parameterised `do_pick` and make the subsequent patch reimplementing
`squash` in terms of such a single function more readable.

Do not call `rm -f $GIT_DIR/MERGE_MSG` since it has no effect on
the state after git-rebase--interactive terminates. The option `-F`
makes git-commit ignore `MERGE_MSG` for the log message. If
git-commit succeeds, `MERGE_MSG` is removed, and if it fails,
`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.
In summary, removing `MERGE_MSG` neither influences the squash commit
message nor the file state after git-commit returns.

Moreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch
`$squash_msg` so that it is correct to execute `pick_one` immediately
before git-commit.

Might be squashed into the subsequent commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 21 +++--
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 5df1086..d85e55d 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -636,15 +636,15 @@ do_next () {
author_script_content=$(get_author_ident_from_commit HEAD)
echo $author_script_content  $author_script
eval $author_script_content
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 $rest
-   fi
case $(peek_next_command) in
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not apply 
$sha1... $rest
+   fi
do_with_author output git commit --amend --no-verify -F 
$squash_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
@@ -653,12 +653,21 @@ do_next () {
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
do_with_author git commit --amend --no-verify 
-F $fixup_msg \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   rm -f $GIT_DIR/MERGE_MSG
+   if ! pick_one -n $sha1
+   then
+   git rev-parse --verify HEAD $amend
+   die_failed_squash $sha1 Could not 
apply $sha1... $rest
+   fi
do_with_author git commit --amend --no-verify 
-F $GIT_DIR/SQUASH_MSG -e \
${gpg_sign_opt:+$gpg_sign_opt} ||
die_failed_squash $sha1 $rest
-- 
2.0.1

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


[PATCH v1 05/19] rebase -i: implement reword in terms of do_pick

2014-07-28 Thread Fabian Ruch
The to-do list command `reword` replays a commit like `pick` but lets
the user also edit the commit's log message. If one thinks of `pick`
entries as scheduled `cherry-pick` command lines, then `reword`
becomes an alias for the command line `cherry-pick --edit`. The
porcelain `rebase--interactive` defines a function `do_pick` for
processing the `pick` entries on to-do lists. Reimplement `reword` in
terms of `do_pick --edit`.

If the user picks a commit using the to-do list line

reword fa1afe1 Some change

execute the command `do_pick --edit fa1afe1 Some change` which
carries out exactly the same steps as the case arm for `reword` in
`do_next` so far.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 15 +--
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index e06d9b6..4c875d5 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -555,20 +555,7 @@ do_next () {
comment_for_reflog reword
 
mark_action_done
-   do_pick $sha1 $rest
-   # TODO: Work around the fact that git-commit lets us
-   # disable either both the pre-commit and the commit-msg
-   # hook or none. Disable the pre-commit hook because the
-   # tree is left unchanged but run the commit-msg hook
-   # from here because the log message is altered.
-   git commit --allow-empty --amend --no-post-rewrite -n 
${gpg_sign_opt:+$gpg_sign_opt} 
-   if test -x $GIT_DIR/hooks/commit-msg
-   then
-   $GIT_DIR/hooks/commit-msg 
$GIT_DIR/COMMIT_EDITMSG
-   fi || {
-   warn Could not amend commit after successfully 
picking $sha1... $rest
-   exit_with_patch $sha1 1
-   }
+   do_pick --edit $sha1 $rest
record_in_rewritten $sha1
;;
edit|e)
-- 
2.0.1

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


[PATCH v1 19/19] rebase -i: enable options --signoff, --reset-author for pick, reword

2014-07-28 Thread Fabian Ruch
pick and reword are atomic to-do list commands in the sense that they
open a new task which is closed after the respective command is
completed. squash and fixup are not atomic. They create a new task
which is not completed until the last squash or fixup is processed.

Lift the general unknown option blockade for the pick and reword
commands. If `do_cmd` comes across one of the options `--signoff` and
`--reset-author` while parsing a to-do entry and the scheduled
command is either `pick` or `reword`, relay the option to `do_pick`.

The `do_pick` options `--gpg-sign` and `--file` are not yet supported
because `do_cmd` cannot handle option arguments and options with
spaces at the moment. It is true that edit is one of the atomic
commands but it displays hash information when the rebase is stopped
and some options rewrite the picked commit which alters that
information. squash and fixup still do not accept user options as the
interplay of `--reset-author` and the author script are yet to be
determined.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 19 ---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 9324ed3..32fd047 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -627,6 +627,16 @@ do_replay () {
while test $# -gt 0
do
case $1 in
+   --signoff|--reset-author)
+   case $command in
+   pick|reword)
+   ;;
+   *)
+   warn Unsupported option: $1
+   command=unknown
+   ;;
+   esac
+   ;;
-*)
warn Unknown option: $1
command=unknown
@@ -647,21 +657,24 @@ do_replay () {
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   eval do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
+   eval do_pick --edit $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
record_in_rewritten $sha1
;;
edit|e)
comment_for_reflog edit
 
mark_action_done
-   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
+   eval do_pick $opts $sha1 \
+   || die_with_patch $sha1 Could not apply $sha1... $rest
warn Stopped at $sha1... $rest
exit_with_patch $sha1 0
;;
-- 
2.0.1

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


[PATCH v1 18/19] rebase -i: teach do_pick the option --signoff

2014-07-28 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is currently used to implement most of the to-do list commands
and offers additional options that will eventually find their way
onto to-do lists.

To extend the repertoire of available options, add the git-commit and
git-cherry-pick option `--signoff` to the `do_pick` interface. It
appends a Signed-off-by: line using the committer identity to the log
message of the picked commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3886a80..9324ed3 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,15 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
+# do_pick [--signoff] [--reset-author] [--amend] [--file file]
+# [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# -s, --signoff
+# Insert a Signed-off-by: line using the committer identity at the
+# end of the commit log message. This creates a fresh commit.
+#
 # --reset-author
 # Pretend the changes were made for the first time. Declare that the
 # authorship of the resulting commit now belongs to the committer.
@@ -510,6 +515,10 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   -s|--signoff)
+   rewrite=y
+   rewrite_signoff=y
+   ;;
--reset-author)
rewrite=y
rewrite_author=y
@@ -588,6 +597,7 @@ do_pick () {
then
git commit --allow-empty --no-post-rewrite -n --no-edit \
   ${allow_empty_message:+--allow-empty-message} \
+  ${rewrite_signoff:+--signoff} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit} \
   ${rewrite_message:+--file $rewrite_message} \
-- 
2.0.1

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


[PATCH v1 17/19] rebase -i: teach do_pick the option --reset-author

2014-07-28 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement many of the to-do list commands.
Eventually, the complete `do_pick` interface will be exposed to the
user in some form or another and those commands will become simple
aliases for the `do_pick` options now used to implement them.

Add the git-commit option `--reset-author` to the options pool of
`do_pick`. It rewrites the author date and name of the picked commit
to match the committer date and name.

If `--reset-author` is passed to `do_pick`, set the `rewrite` flag
and relay the option to the git-commit command line which creates the
final commit. If `--amend` is not passed as well, the fresh
authorship effect is achieved by the mere fact that we are creating a
new commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index ff4ba7f..3886a80 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,10 +464,18 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--file file] [--edit] commit
+# do_pick [--reset-author] [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
+# --reset-author
+# Pretend the changes were made for the first time. Declare that the
+# authorship of the resulting commit now belongs to the committer.
+# This also renews the author timestamp. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # --amend
 # After picking commit, replace the current head commit with a new
 # commit that also introduces the changes of commit.
@@ -502,6 +510,10 @@ do_pick () {
while test $# -gt 0
do
case $1 in
+   --reset-author)
+   rewrite=y
+   rewrite_author=y
+   ;;
--amend)
if test $(git rev-parse HEAD) = $squash_onto || ! 
git rev-parse --verify HEAD
then
@@ -564,6 +576,14 @@ do_pick () {
pick_one ${rewrite:+-n} $1 || return 1
fi
 
+   if test -n $rewrite_author  test -z $rewrite_amend
+   then
+   # keep rewrite flag to create a new commit, rewrite
+   # without --reset-author though because it can only be
+   # used with -C, -c or --amend
+   rewrite_author=
+   fi
+
if test -n $rewrite
then
git commit --allow-empty --no-post-rewrite -n --no-edit \
@@ -571,6 +591,7 @@ do_pick () {
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit} \
   ${rewrite_message:+--file $rewrite_message} \
+  ${rewrite_author:+--reset-author} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 
-- 
2.0.1

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


[PATCH v1 06/19] rebase -i: allow replaying commits with empty log messages

2014-07-28 Thread Fabian Ruch
git-rebase--interactive handles empty log messages inconsistently
between enabled and disabled fast-forwards. By default, commits with
empty log messages are rebased successfully like in non-interactive
mode. In contrast, the `--no-ff` option aborts the replay of such
commits.

In line with not verifying rebased commits and behaving like
git-rebase for `pick` lines, use the `--allow-empty-message` option
to replay commits. Root commits are replayed by recreating them in
`do_pick` using git-commit and commits with parents are replayed
using git-cherry-pick in `pick_one`. Apply the option, understood by
both git-commit and git-cherry-pick, at the respective sites.

In case of `reword` and `squash`/`fixup` continue to abort the rebase
if the resulting commit would have no commit message. The rationale
behind this default is that patches and their log messages should be
verified at least once. For unchanged commits this is assumed to have
happened according to the author's standards when she created the
commits the first time. While the empty log message can always be
kept in place by editing and resuming the aborted rebase, a debatable
alternative could be to teach git-rebase--interactive the option
`--allow-empty-message` for disabling complaints about empty log
messages in changed commits. The to-do list command `edit` is handled
just like `pick` for this matter, because git-rebase--interactive
replays the named commit without changes before the rebase is
interrupted and the user can make her changes to the replayed commit.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh|  4 ++--
 t/t3404-rebase-interactive.sh | 24 
 t/t3412-rebase-root.sh| 19 +++
 3 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 4c875d5..6e2c429 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -249,7 +249,7 @@ pick_one () {
 
test -d $rewritten 
pick_one_preserving_merges $@  return
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $empty_args $ff $@
 }
@@ -363,7 +363,7 @@ pick_one_preserving_merges () {
echo $sha1 $(git rev-parse HEAD^0)  
$rewritten_list
;;
*)
-   output eval git cherry-pick \
+   output eval git cherry-pick --allow-empty-message \
${gpg_sign_opt:+$(git rev-parse --sq-quote 
$gpg_sign_opt)} \
$strategy_args $@ ||
die_with_patch $sha1 Could not pick $sha1
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 2da4b9c..2e8fa27 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1085,4 +1085,28 @@ test_expect_success 'short SHA-1 collide' '
)
 '
 
+test_expect_success 'rebase commits with empty commit log messages' '
+   git checkout -b no-msg-commit 
+   test_commit no-msg-commit-1 
+   git commit --amend --allow-empty-message -m   
+   test_commit no-msg-commit-2 
+   git commit --amend --allow-empty-message -m   
+   EDITOR=true git rebase -i HEAD^ 
+   EDITOR=true git rebase -i --no-ff HEAD^
+'
+
+test_expect_success 'reword commit with empty commit log message' '
+   git checkout no-msg-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=reword 1 git rebase -i HEAD^
+'
+
+test_expect_success 'squash commits with empty commit log messages' '
+   git checkout no-msg-commit 
+   test_when_finished reset_rebase 
+   set_fake_editor 
+   test_must_fail env FAKE_LINES=1 squash 2 git rebase -i HEAD^^
+'
+
 test_done
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 0b52105..798c9f1 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -278,4 +278,23 @@ test_expect_success 'rebase -i -p --root with conflict 
(second part)' '
test_cmp expect-conflict-p out
 '
 
+test_expect_success 'rebase --root with empty root log message' '
+   git checkout --orphan no-msg-root-commit 
+   test_commit no-msg-root-commit 
+   git commit --amend -m   --allow-empty-message 
+   git rebase --root 
+   test_path_is_file no-msg-root-commit.t 
+   git rebase --root --no-ff 
+   test_path_is_file no-msg-root-commit.t
+'
+
+test_expect_success 'rebase --root with empty child log message' '
+   test_commit no-msg-child-commit 
+   git commit --amend -m   --allow-empty-message 
+   git rebase --root 
+   test_path_is_file no-msg-child-commit.t 
+   git rebase --root --no-ff 
+   test_path_is_file no-msg-child

[PATCH v1 04/19] rebase -i: teach do_pick the option --edit

2014-07-28 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`. To cater for
the different pick behaviours (like `reword`), `do_pick` accepts
several options not only from the git-cherry-pick but also the
git-commit interface. Add the common option `--edit` to let the user
edit the log message of the named commit.

Loop over `$@` to parse the `do_pick` arguments. Assign the local
variable `edit` if one of the options is `--edit` so that the
remainder of `do_pick` can easily check whether the client code asked
to edit the commit message. If one of the options is unknown, mention
it on the console and `die`. Break the loop on the first non-option
and do some sanity checking to ensure that there exactly two
non-options, which are interpreted by the remainder as `commit` and
`title` like before.

`do_pick` ought to act as a wrapper around `cherry-pick`.
Unfortunately, it cannot just forward `--edit` to the `cherry-pick`
command line. The assembled command line is executed within a command
substitution for controlling the verbosity of `rebase--interactive`.
Passing `--edit` would either hang the terminal or clutter the
substituted command output with control sequences. Execute the
`reword` code from `do_next` instead if the option `--edit` is
specified.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 52 ++
 1 file changed, 52 insertions(+)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b50770d..e06d9b6 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -461,7 +461,42 @@ record_in_rewritten() {
esac
 }
 
+# Apply the changes introduced by the given commit to the current head.
+#
+# do_pick [--edit] commit title
+#
+# Wrapper around git-cherry-pick.
+#
+# -e, --edit
+# After picking commit, open an editor and let the user edit the
+# commit message. The editor contents becomes the commit message of
+# the new head. This creates a fresh commit.
+#
+# commit
+# The commit to cherry-pick.
+#
+# title
+# The commit message title of commit. Used for information
+# purposes only.
 do_pick () {
+   edit=
+   while test $# -gt 0
+   do
+   case $1 in
+   -e|--edit)
+   edit=y
+   ;;
+   -*)
+   die do_pick: unrecognized option -- $1
+   ;;
+   *)
+   break
+   ;;
+   esac
+   shift
+   done
+   test $# -ne 2  die do_pick: wrong number of arguments
+
if test $(git rev-parse HEAD) = $squash_onto
then
# Set the correct commit message and author info on the
@@ -483,6 +518,23 @@ do_pick () {
pick_one $1 ||
die_with_patch $1 Could not apply $1... $2
fi
+
+   if test -n $edit
+   then
+   # TODO: Work around the fact that git-commit lets us
+   # disable either both the pre-commit and the commit-msg
+   # hook or none. Disable the pre-commit hook because the
+   # tree is left unchanged but run the commit-msg hook
+   # from here because the log message is altered.
+   git commit --allow-empty --amend --no-post-rewrite -n 
${gpg_sign_opt:+$gpg_sign_opt} 
+   if test -x $GIT_DIR/hooks/commit-msg
+   then
+   $GIT_DIR/hooks/commit-msg 
$GIT_DIR/COMMIT_EDITMSG
+   fi || {
+   warn Could not amend commit after successfully 
picking $1... $2
+   exit_with_patch $1 1
+   }
+   fi
 }
 
 do_next () {
-- 
2.0.1

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


[PATCH v1 12/19] rebase -i: teach do_pick the option --file

2014-07-28 Thread Fabian Ruch
`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive
that is used to implement the to-do list command `pick`, `reword` and
`edit`. To cater for the different pick behaviours (like `squash`),
`do_pick` accepts several options not only from the git-cherry-pick
but also the git-commit interface.

Add the option `--file` from the git-commit interface to the options
pool of `do_pick`. It expects an argument itself which is interpreted
as a file path and takes the commit message from the given file. If
`--file` is passed to `do_pick`, assign the given file path to the
local variable `rewrite_message` and relay the option

--file $rewrite_message

to the git-commit command line which creates the commit.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 20 +++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 22a8f7b..5df1086 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--amend] [--edit] commit
+# do_pick [--amend] [--file file] [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -474,6 +474,12 @@ record_in_rewritten() {
 #
 # _This is not a git-cherry-pick option._
 #
+# -F file, --file file
+# Take the commit message from the given file. This creates a fresh
+# commit.
+#
+# _This is not a git-cherry-pick option._
+#
 # -e, --edit
 # After picking commit, open an editor and let the user edit the
 # commit message. The editor contents becomes the commit message of
@@ -492,6 +498,7 @@ do_pick () {
rewrite=
rewrite_amend=
rewrite_edit=
+   rewrite_message=
while test $# -gt 0
do
case $1 in
@@ -505,6 +512,16 @@ do_pick () {
rewrite_amend=y
git rev-parse --verify HEAD $amend
;;
+   -F|--file)
+   if test $# -eq 0
+   then
+   warn do_pick: option --file specified but no 
file given
+   return 2
+   fi
+   rewrite=y
+   rewrite_message=$2
+   shift
+   ;;
-e|--edit)
rewrite=y
rewrite_edit=y
@@ -553,6 +570,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit} \
+  ${rewrite_message:+--file $rewrite_message} \
   ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 
-- 
2.0.1

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


[PATCH v1 08/19] rebase -i: root commits are replayed with an unnecessary option

2014-07-28 Thread Fabian Ruch
The command line used to recreate root commits specifies the
effectless option `-C`. It makes git-commit reuse commit message and
authorship of the named commit. However, the commit being amended
here, which is the sentinel commit, already carries the authorship
and log message of the commit being replayed. Remove the option.

Since `-C` (in contrast to `-c`) does not invoke the editor and the
`--amend` option invokes it by default, disable editor invocation
again by specifying `--no-edit`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 576e0b1..46f436f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -511,7 +511,7 @@ do_pick () {
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -C $1 \
+  --amend --no-post-rewrite -n --no-edit \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


[PATCH v1 10/19] rebase -i: do not die in do_pick

2014-07-28 Thread Fabian Ruch
Since `do_pick` might be executed in a sub-shell (a modified author
environment for instance), calling `die` in `do_pick` has no effect
but exiting the sub-shell with a failure exit status. The
git-rebase--interactive script is not terminated. Moreover, if
`do_pick` is called while a squash or fixup is in effect,
`die_with_patch` will discard `$squash_msg` as commit message.
Lastly, after a `die` in `do_pick` `do_next` has no chance to
reschedule tasks that failed before changes could be applied.

Indicate an error in `do_pick` using return statements and properly
kill the script at the call sites. Although possible in principle,
the issued error messages are no more indicating whether `do_pick`
failed while applying or while committing the changes. This reduces
code complexity at the call site and does not matter from a user's
point of view because a glance at the index reveals whether there are
conflicts or not and in-depth troubleshooting is still possible using
the `--verbose` option.

Remove the commit message title argument from `do_pick`'s interface,
which has become unused.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 37 -
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 96c24e8..9f08f1b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -464,7 +464,7 @@ record_in_rewritten() {
 
 # Apply the changes introduced by the given commit to the current head.
 #
-# do_pick [--edit] commit title
+# do_pick [--edit] commit
 #
 # Wrapper around git-cherry-pick.
 #
@@ -476,9 +476,11 @@ record_in_rewritten() {
 # commit
 # The commit to cherry-pick.
 #
-# title
-# The commit message title of commit. Used for information
-# purposes only.
+# The return value is 1 if applying the changes resulted in a conflict
+# and 2 if the specified arguments were incorrect. If the changes could
+# be applied successfully but creating the commit failed, a value
+# greater than 2 is returned. No commit is created in either case and
+# the index is left with the (conflicting) changes in place.
 do_pick () {
allow_empty_message=y
rewrite=
@@ -493,7 +495,8 @@ do_pick () {
allow_empty_message=
;;
-*)
-   die do_pick: unrecognized option -- $1
+   warn do_pick: unrecognized option -- $1
+   return 2
;;
*)
break
@@ -501,7 +504,11 @@ do_pick () {
esac
shift
done
-   test $# -ne 2  die do_pick: wrong number of arguments
+   if test $# -ne 1
+   then
+   warn do_pick: wrong number of arguments
+   return 2
+   fi
 
if test $(git rev-parse HEAD) = $squash_onto
then
@@ -519,11 +526,9 @@ do_pick () {
# rebase --continue.
git commit --allow-empty --allow-empty-message --amend \
   --no-post-rewrite -n -q -C $1 
-   pick_one -n $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one -n $1 || return 1
else
-   pick_one ${rewrite:+-n} $1 ||
-   die_with_patch $1 Could not apply $1... $2
+   pick_one ${rewrite:+-n} $1 || return 1
fi
 
if test -n $rewrite
@@ -532,8 +537,7 @@ do_pick () {
   ${allow_empty_message:+--allow-empty-message} \
   ${rewrite_amend:+--amend} \
   ${rewrite_edit:+--edit} \
-  ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_with_patch $1 Could not rewrite commit after 
successfully picking $1... $2
+  ${gpg_sign_opt:+$gpg_sign_opt} || return 3
fi
 
# TODO: Work around the fact that git-commit lets us
@@ -546,8 +550,7 @@ do_pick () {
if test -x $GIT_DIR/hooks/commit-msg
then
$GIT_DIR/hooks/commit-msg $GIT_DIR/COMMIT_EDITMSG
-   fi ||
-   die_with_patch $1 Could not rewrite commit after 
successfully picking $1... $2
+   fi || return 3
fi
 }
 
@@ -562,21 +565,21 @@ do_next () {
comment_for_reflog pick
 
mark_action_done
-   do_pick $sha1 $rest
+   do_pick $sha1 || die_with_patch $sha1 Could not apply $sha1... 
$rest
record_in_rewritten $sha1
;;
reword|r)
comment_for_reflog reword
 
mark_action_done
-   do_pick --edit $sha1 $rest
+   do_pick --edit $sha1 || die_with_patch $sha1 Could not apply 
$sha1... $rest
record_in_rewritten $sha1

[PATCH v1 16/19] rebase -i: parse to-do list command line options

2014-07-28 Thread Fabian Ruch
Read in to-do list lines as

command args

instead of

command sha1 rest

so that to-do list command lines can specify additional arguments
apart from the commit hash and the log message title, which become
the non-options in `args`. Loop over `args`, put all options (an
argument beginning with a dash) in `opts`, stop the loop on the first
non-option and assign it to `sha1`. The loop does not know the
options it parses so that options that take an argument themselves
are not supported at the moment. Neither are options that contain
spaces because the shell expansion of `args` in `do_next` interprets
white space characters as argument separator, that is a command line
like

pick --author A U Thor fa1afe1 Some change

is parsed as the pick command

pick --author

and the commit hash

A

which obviously results in an unknown revision error. For the sake of
completeness, in the example above the message title variable `rest`
is assigned the string 'U Thor fa1afe1 Some change' (without the
single quotes).

Print an error message for unknown or unsupported command line
options, which means an error for all specified options at the
moment. Cleanly break the `do_next` loop by assigning the special
value 'unknown' to the local variable `command`, which triggers the
unknown command case in `do_cmd`.

The to-do list is also parsed when the commit hashes are translated
between long and short format before and after the to-do list is
edited. Apply the same procedure as in `do_cmd` with the exception
that we only care about where the options stop and the commit hash
begins. Do not reject any options when transforming the commit
hashes.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 49 ++
 1 file changed, 41 insertions(+), 8 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8dde8e6..ff4ba7f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -590,8 +590,26 @@ do_pick () {
 
 do_replay () {
command=$1
-   sha1=$2
-   rest=$3
+   shift
+
+   opts=
+   while test $# -gt 0
+   do
+   case $1 in
+   -*)
+   warn Unknown option: $1
+   command=unknown
+   ;;
+   *)
+   break
+   ;;
+   esac
+   opts=$opts $(git rev-parse --sq-quote $1)
+   shift
+   done
+   sha1=$1
+   shift
+   rest=$*
 
case $command in
pick|p)
@@ -674,7 +692,7 @@ do_replay () {
 
 do_next () {
rm -f $msg $author_script $amend || exit
-   read -r command sha1 rest $todo
+   read -r command args $todo
 
case $command in
$comment_char*|''|noop)
@@ -719,7 +737,7 @@ do_next () {
fi
;;
*)
-   do_replay $command $sha1 $rest
+   do_replay $command $args
;;
esac
test -s $todo  return
@@ -799,19 +817,34 @@ skip_unnecessary_picks () {
 }
 
 transform_todo_ids () {
-   while read -r command rest
+   while read -r command args
do
case $command in
$comment_char* | exec)
# Be careful for oddball commands like 'exec'
# that do not have a SHA-1 at the beginning of $rest.
+   newargs=\ $args
;;
*)
-   sha1=$(git rev-parse --verify --quiet $@ ${rest%% *}) 

-   rest=$sha1 ${rest#* }
+   newargs=
+   sha1=
+   for arg in $args
+   do
+   case $arg in
+   -*)
+   newargs=$newargs $arg
+   ;;
+   *)
+   test -z $sha1 
+   sha1=$(git rev-parse --verify 
--quiet $@ $arg) 
+   arg=$sha1
+   newargs=$newargs $arg
+   ;;
+   esac
+   done
;;
esac
-   printf '%s\n' $command${rest:+ }$rest
+   printf '%s\n' $command$newargs
done $todo $todo.new 
mv -f $todo.new $todo
 }
-- 
2.0.1

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


[PATCH v1 14/19] rebase -i: implement squash in terms of do_pick

2014-07-28 Thread Fabian Ruch
The to-do list command `squash` and its close relative `fixup` replay
the changes of a commit like `pick` but do not recreate the commit.
Instead they replace the previous commit with a new commit that also
introduces the changes of the squashed commit. This is roughly like
cherry-picking without committing and using git-commit to amend the
previous commit.

The to-do list

pick   a Some changes
squash b Some more changes

gets translated into the sequence of git commands

git cherry-pick a
git cherry-pick -n b
git commit --amend

and if git-cherry-pick supported `--amend` this would look even more
like the to-do list it is based on

git cherry-pick a
git cherry-pick --amend b.

Since `do_pick` takes care of `pick` entries and the above suggests
`squash` as an alias for `pick --amend`, reimplement `squash` in
terms of `do_pick --amend`. Introduce `$squash_msg` as the commit
message via the `--file` option. When the last commit of a squash
series is processed, the user is asked to review the log message.
Pass `--edit` as additional option in this case. The only difference
in the options passed to git-commit and `do_pick` is the omitted
`--no-verify`. However, `do_pick` does not execute the verification
hooks anyway because it solely replays commits and assumes that they
have been verified before.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 30 ++
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index d85e55d..9307fa4 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -640,37 +640,19 @@ do_next () {
squash|s|fixup|f)
# This is an intermediate commit; its message will only 
be
# used in case of trouble.  So use the long version:
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not apply 
$sha1... $rest
-   fi
-   do_with_author output git commit --amend --no-verify -F 
$squash_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F $squash_msg $sha1 \
+   || die_failed_squash $sha1 Could not apply 
$sha1... $rest
;;
*)
# This is the final command of this squash/fixup group
if test -f $fixup_msg
then
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   do_with_author git commit --amend --no-verify 
-F $fixup_msg \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F $fixup_msg 
$sha1 \
+   || die_failed_squash $sha1 Could not 
apply $sha1... $rest
else
cp $squash_msg $GIT_DIR/SQUASH_MSG || exit
-   if ! pick_one -n $sha1
-   then
-   git rev-parse --verify HEAD $amend
-   die_failed_squash $sha1 Could not 
apply $sha1... $rest
-   fi
-   do_with_author git commit --amend --no-verify 
-F $GIT_DIR/SQUASH_MSG -e \
-   ${gpg_sign_opt:+$gpg_sign_opt} ||
-   die_failed_squash $sha1 $rest
+   do_with_author do_pick --amend -F 
$GIT_DIR/SQUASH_MSG -e $sha1 \
+   || die_failed_squash $sha1 Could not 
apply $sha1... $rest
fi
rm -f $squash_msg $fixup_msg
;;
-- 
2.0.1

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


[PATCH v1 15/19] rebase -i: explicitly distinguish replay commands and exec tasks

2014-07-28 Thread Fabian Ruch
There are two kinds of to-do list commands available. One kind
replays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that
is) and the other executes a shell command (`exec`). We will call the
first kind replay commands.

The two kinds of tasks are scheduled using different line formats.
Replay commands expect a commit hash argument following the command
name and exec concatenates all arguments to assemble a command line.

Adhere to the distinction of formats by not trying to parse the
`sha1` field unless we are dealing with a replay command. Move the
replay command handling code to a new function `do_replay` which
assumes the first argument to be a commit hash and make no more such
assumptions in `do_next`.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 42 --
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 9307fa4..8dde8e6 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -588,13 +588,12 @@ do_pick () {
fi
 }
 
-do_next () {
-   rm -f $msg $author_script $amend || exit
-   read -r command sha1 rest  $todo
+do_replay () {
+   command=$1
+   sha1=$2
+   rest=$3
+
case $command in
-   $comment_char*|''|noop)
-   mark_action_done
-   ;;
pick|p)
comment_for_reflog pick
 
@@ -659,6 +658,28 @@ do_next () {
esac
record_in_rewritten $sha1
;;
+   *)
+   read -r command $todo
+   warn Unknown command: $command
+   fixtodo=Please fix this using 'git rebase --edit-todo'.
+   if git rev-parse --verify -q $sha1 /dev/null
+   then
+   die_with_patch $sha1 $fixtodo
+   else
+   die $fixtodo
+   fi
+   ;;
+   esac
+}
+
+do_next () {
+   rm -f $msg $author_script $amend || exit
+   read -r command sha1 rest $todo
+
+   case $command in
+   $comment_char*|''|noop)
+   mark_action_done
+   ;;
x|exec)
read -r command rest  $todo
mark_action_done
@@ -698,14 +719,7 @@ do_next () {
fi
;;
*)
-   warn Unknown command: $command $sha1 $rest
-   fixtodo=Please fix this using 'git rebase --edit-todo'.
-   if git rev-parse --verify -q $sha1 /dev/null
-   then
-   die_with_patch $sha1 $fixtodo
-   else
-   die $fixtodo
-   fi
+   do_replay $command $sha1 $rest
;;
esac
test -s $todo  return
-- 
2.0.1

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


[PATCH v1 07/19] rebase -i: log the replay of root commits

2014-07-28 Thread Fabian Ruch
The command line used to recreate root commits specifies the option
`-q` which suppresses the commit summary message. However,
git-rebase--interactive tends to tell the user about the commits it
creates in the final history, if she wishes (cf. command line option
`--verbose`). The code parts handling non-root commits and squash
commits all output commit summary messages. Do not make the replay of
root commits an exception. Remove the option to make the report of
the rebased history complete.

It is OK that the commit summary is still suppressed when git-commit
is used to initialize the authorship of the sentinel commit because
this additional commit is an implementation detail hidden from the
final history. The removed `-q` option was probably introduced as a
copy-and-paste error stemming from that part of the root commit
handling code.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
 git-rebase--interactive.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 6e2c429..576e0b1 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -511,7 +511,7 @@ do_pick () {
   --no-post-rewrite -n -q -C $1 
pick_one -n $1 
git commit --allow-empty --allow-empty-message \
-  --amend --no-post-rewrite -n -q -C $1 \
+  --amend --no-post-rewrite -n -C $1 \
   ${gpg_sign_opt:+$gpg_sign_opt} ||
die_with_patch $1 Could not apply $1... $2
else
-- 
2.0.1

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


Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option

2014-07-19 Thread Fabian Ruch
Hi Junio,

Junio C Hamano writes:
 Fabian Ruch baf...@gmail.com writes:
 It makes the next patch easier to understand because the finalising
 command line git commit --allow-empty --amend --no-post-rewrite -n
 --no-edit seems to be simply moved to the end of do_pick. Substituting
 --no-edit for -C there would make that log message overly long ...
 
 And the reason why the same -C $1 is not used and --no-edit is used
 in the final version that is moved to the end of do_pick is...?

The finalising command line is executed by do_pick to rewrite $1 when it
is being replayed.

For instance, one purpose of rewriting is amending the current head with
the changes introduced by $1. In this case, we don't want the log
message of $1 to be the final log message. Another purpose of rewriting
is using a text file or a string as log message, which would be defeated
by -C $1 as well.

It's true that, by the time the next patch is introduced, do_pick
doesn't yet implement either rewriting mechanism (they are both used to
thread squash through do_pick later on) but these considerations
suggest that -C $1 might not be what we want to use to disable the log
message editor.

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


Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option

2014-07-18 Thread Fabian Ruch
Hi Junio,

Junio C Hamano writes:
 Fabian Ruch baf...@gmail.com writes:
 The command line used to recreate root commits specifies the
 effectless option `-C`. It is used to reuse commit message and
 authorship from the named commit but the commit being amended here,
 which is the sentinel commit, already carries the authorship and log
 message of the processed commit. Note that the committer email and
 commit date fields do not match the root commit either way. Remove
 the option. However, `-C` (other than `-c`) does not invoke the
 editor and the `--amend` option invokes it by default. Disable editor
 invocation again by specifying `--no-edit`.
 
 I'd say this is a no-value change, in the sense that it can be
 written either way for the same effect and if the original were
 written with --amend --no-edit then there would be no reason to
 change it to -C $1 because such a change would also be equally a
 no-value change.
 
 What exactly are we gaining?  Performance?  Correctness?

I submitted this change separately from the next (rebase -i: Commit
only once when rewriting picks) for the following reasons, at least I
thought they were.

It makes the next patch easier to understand because the finalising
command line git commit --allow-empty --amend --no-post-rewrite -n
--no-edit seems to be simply moved to the end of do_pick. Substituting
--no-edit for -C there would make that log message overly long and the
paragraph saying why this substitution is correct would be distracting
(it's a little unfortunate that there is this special case in the first
place). While the resulting history stays the same of course, it might
be confusing to someone reading the code that the log message gets
replaced with itself.

I know the last point is rather weak but aren't the two patches and log
messages easier to read?

   Fabian

 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
  git-rebase--interactive.sh | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index ff04d5d..17836d5 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -511,7 +511,7 @@ do_pick () {
 --no-post-rewrite -n -q -C $1 
  pick_one -n $1 
  git commit --allow-empty \
 -   --amend --no-post-rewrite -n -C $1 \
 +   --amend --no-post-rewrite -n --no-edit \
 ${gpg_sign_opt:+$gpg_sign_opt} ||
  die_with_patch $1 Could not apply $1... $2
  else
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v1] rebase -p: Command line option --no-ff is ignored

2014-07-16 Thread Fabian Ruch
Hi Marc,

I forgot to cc your mailbox when I posted this patch last week. Do you
still remember whether there was a particular reason why
pick_one_preserving_merges wasn't touched by the commit b499549 (Teach
rebase the --no-ff option.), by any chance?

Kind regards,
   Fabian

Fabian Ruch writes:
 The --no-ff option instructs git-rebase to always recreate commits as
 they are being replayed, even if fast-forwards are possible.
 
 However, if git-rebase is asked to recreate merge commits (via the -p
 option), it suddenly ignores the --no-ff option and fast-forwards
 both normal and merge commits whenever possible.
 
 git-rebase--interactive, which is responsible for recreating merge
 commits during a rebase, maintains a variable fast_forward to decide
 whether the current replay should be tried as a fast-forward.
 Previously, fast_forward was on by default and would get toggled only
 if a parent was rewritten or a squash was in effect. Also turn
 fast_forward off if --no-ff is in use, which is signalled by
 git-rebase through the variable force_rebase.
 
 If --no-ff is not in use, try to fast-forward HEAD using git-reset as
 before. In contrast, if --no-ff is in use, replay normal commits
 using git-cherry-pick and merge commits using git-merge. Note that
 git-rebase--interactive already provides this machinery for enabling
 and disabling fast-forwards, controlled by fast_forward being
 assigned either t (for boolean true) or f (for boolean false).
 
 As mentioned above, git-rebase--interactive needs to detect when a
 squash is in effect. If several commits are squashed into one, each
 of them is picked using the git-cherry-pick option -n and they get
 all rewritten to the same commit, the squash commit. Previously,
 fast_forward was assigned f if and only if -n was specified. This no
 longer holds for fast_forward might be turned off due to a use of
 --no-ff. To correctly notice squashes, explicitly check for -n.
 
 Add test.
 
 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
 Hi,
 
 The code checking force_rebase is copied from pick_one, although
 using a ternary operator to initialise fast_forward might be more
 readable. Moreover, the code snippet used to detect squash mode is
 copied from the f arm of the fast_forward case switch, although the
 code base prefers to spell out test(1).
 
 The test recreates a topic branch that merged a second topic branch.
 Therefore, the test case tests the recreation of both normal and
 merge commits.
 
 Commit b499549 first introduced the --no-ff option to git-rebase and
 since then force_rebase seems to respected only by pick_one but not
 by its sibling pick_one_preserving_merges. I couldn't find a reason
 why. Was pick_one_preserving_merges merely overlooked?
 
 Is it a usability issue that conflicting merges will have to be
 resolved again when being replayed now? The same applies to -p and
 the replay of merges with rewritten parents. Should the possibly
 required resolution be mentioned alongside git-rerere in the
 git-rebase manual page?
 
Fabian
 
  git-rebase--interactive.sh|  3 ++-
  t/t3409-rebase-preserve-merges.sh | 12 
  2 files changed, 14 insertions(+), 1 deletion(-)
 
 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index f267d8b..264a768 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -266,10 +266,11 @@ pick_one_preserving_merges () {
   ;;
   esac
   sha1=$(git rev-parse $sha1)
 + case $force_rebase in '') ;; ?*) fast_forward=f ;; esac
  
   if test -f $state_dir/current-commit
   then
 - if test $fast_forward = t
 + if [ $1 != -n ]
   then
   while read current_commit
   do
 diff --git a/t/t3409-rebase-preserve-merges.sh 
 b/t/t3409-rebase-preserve-merges.sh
 index 8c251c5..838937b 100755
 --- a/t/t3409-rebase-preserve-merges.sh
 +++ b/t/t3409-rebase-preserve-merges.sh
 @@ -81,6 +81,18 @@ test_expect_success 'setup for merge-preserving rebase' \
   git commit -a -m Modify B2
  '
  
 +test_expect_success '--no-ff records new commits' '
 + (
 + cd clone3 
 + test_when_finished 'cd clone3  git checkout topic' 
 + git checkout -b recreated-topic 
 + # recreate topic with merged topic2 (branching-off point A1)
 + git rebase -p --no-ff HEAD~2 
 + test $(git rev-parse new-topic^) != $(git rev-parse topic^) 
 + test $(git rev-parse new-topic) != $(git rev-parse topic)
 + )
 +'
 +
  test_expect_success '--continue works after a conflict' '
   (
   cd clone2 
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v1] rebase --root: sentinel commit cloaks empty commits

2014-07-16 Thread Fabian Ruch
git-rebase supports the option `--root` both with and without
`--onto`. In rebase root mode it replays all commits reachable from a
branch on top of another branch, including the very first commit. In
case `--onto` is not specified, that other branch is temporarily
provided by creating an empty commit. When the first commit on the
to-do list is being replayed, the so-called sentinel commit is
amended using the log message and patch of the replayed commit. Since
the sentinel commit is empty, this results in a replacement of the
sentinel commit with the new root commit of the rebased branch.

The combination of `--root` and no `--onto` implies an interactive
rebase. When `--preserve-merges` is not specified on the command
line, git-rebase--interactive uses `--cherry-pick` with git-rev-list
to put the initial to-do list together. The left side is given by the
fake base and the right side by the branch being rebased. What
happens now is that any empty commit on the original branch is
treated as a cherry-pick of the sentinel commit and subsequently
omitted from the to-do list. This is a bug if `--keep-empty` is
specified also.

Even without `--keep-empty`, using the sentinel commit as left side
with git-rev-list can result in a faulty rebased branch. Indeed, in
the unlikely case that the original branch consists solely of empty
commits, the bug crops up in the strangest fashion as all commits are
skipped and the sentinel commit is not replaced. As a result,
git-rebase produces a branch with a single empty commit.

To trigger the replacement of the sentinel commit, git-rebase assigns
the variable `squash_onto`. Special case a second time regarding
`squash_onto` and run git-rev-list without a left side if the
variable is assigned. The latter is the case if and only if `--root`
is used without `--onto`, that is `upstream` points to the sentinel
commit and `$upstream...$orig_head` would subtract a commit that is
not actually there from the original branch.

Fix a typo in `is_empty_commit`. It always found root commits
non-empty so that empty root commits were scheduled even without
`--keep-empty`. The POSIX specification states that command
substitutions are to be executed in sub-shells, which makes exit(1)
and variable assignments not affect the script execution state. That
was the reason why `ptree` was null for parentless commits and the
test `$tree = $ptree` always false for them.

Add tests.

Signed-off-by: Fabian Ruch baf...@gmail.com
---
Hi,

Three test cases were added to the bug report to account for the
additional cases in which the bug strikes (raised by Michael on the
other sub-thread). A bugfix is included now as well.

Concerning the bugfix: Obviously, the patch misuses the `squash_onto`
flag because it assumes that the new base is empty except for the
sentinel commit. The variable name does not imply anything close to
that. An additional flag to disable the use of the git-rev-list
option `--cherry-pick` would work and make sense again (for instance,
`keep_redundant`). However, the following two bugs, not related to
empty commits, seem to suggest that git-rebase--interactive cannot
work obliviously to non-existent bases.

 1) git-rebase--interactive when used with `--root` and the to-do
list `noop` results in the original branch's history being
rewritten to contain only the sentinel commit.

git-rebase--interactive correctly checkouts `$onto` and replays
no commits on top of it but git-rebase has forgotten that `$onto`
was fake.

 2) git-rebase--interactive when used with `--root` always creates a
fresh root commit, regardless of `--no-ff` being specified.

With the current meaning of `squash_onto`,
git-rebase--interactive cannot just reset the branch to the old
root commit. It is really the fault of git-rebase to start off
with a new commit.

Please take a closer look at the last two test cases that specify the
expected behaviour of rebasing a branch that tracks the empty tree.
At this point they expect the Nothing to do error (aborts with
untouched history). This is consistent with rebasing only empty
commits without `--root`, which also doesn't just delete them from
the history. Furthermore, I think the two alternatives adding a note
that all commits in the range were empty, and removing the empty
commits (thus making the branch empty) are better discussed in a
separate bug report.

Thanks for your time,
   Fabian

 git-rebase--interactive.sh | 20 ++-
 t/t3412-rebase-root.sh | 49 ++
 2 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index f267d8b..71ca0f0 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -201,10 +201,10 @@ has_action () {
 }
 
 is_empty_commit() {
-   tree=$(git rev-parse -q --verify $1^{tree} 2/dev/null ||
-   die $1: not a commit that can be picked)
-   ptree

Re: [PATCH RFC v2 03/19] rebase -i: reword executes pre-commit hook on interim commit

2014-07-13 Thread Fabian Ruch
Hi Junio,

Junio C Hamano writes:
 Fabian Ruch baf...@gmail.com writes:
 The to-do list command `reword` replays a commit like `pick` but lets
 the user also edit the commit's log message. This happens in two
 steps. Firstly, the named commit is cherry-picked. Secondly, the
 commit created in the first step is amended using an unchanged index
 to edit the log message. The pre-commit hook is meant to verify the
 changes introduced by a commit (for instance, catching inserted
 trailing white space). Since the committed tree is not changed
 between the two steps, do not execute the pre-commit hook in the
 second step.
 
 It is not like the second step is built as a child commit of the
 result from the first step, recording the same tree without any
 change.  Why is it a good thing not to run the pre-commit hook (or
 other hooks for that matter)?  After all, the result of the second
 step is what is recorded in the final history; it just feels wrong
 not to test that one, even if it were a good idea to test only once.

if I understand correctly, the tree of the (amended) commit isn't tested
at all by git-rebase--interactive because git-cherry-pick, and therefore
pick_one, commits with both the pre-commit and commit-msg hook disabled
(see the git commit -n command line being built in
sequencer.c#run_git_commit since revision 9fa4db5).

The commit --amend we are concerned with here amends using an
untouched tree so that the history ought to record exactly the same
trees as prior to commit --amend. If git-cherry-pick was testing the
tree, then it would be unnecessary to test the tree a second time. Since
git-cherry-pick is not testing as of yet, testing and possibly rejecting
a tree in the second step would actually be wrong. I totally neglected
to look for a test case when I submitted this patch, so I'd like to
supply one late now:

 test_expect_success 'reword a commit violating pre-commit' '
   mkdir -p .git/hooks 
   PRE_COMMIT=.git/hooks/pre-commit 
   cat $PRE_COMMIT EOF
 #!/bin/sh
 echo running pre-commit
 exit 1
 EOF
   chmod +x $PRE_COMMIT 
   test_must_fail test_commit file 
   test_commit --no-verify file 
   set_fake_editor 
   FAKE_LINES=pick 1 git rebase -i HEAD^ 
   FAKE_LINES=pick 1 git rebase -i --no-ff HEAD^ 
   FAKE_LINES=reword 1 git rebase -i HEAD^
 '

(This addition to t3404-rebase--interactive.sh is based on the test case
rebase a commit violating pre-commit; test_commit --no-verify will
be implemented the obvious way.)

In both cases, it's correct to disable the pre-commit hook when editing
the log message and it just makes sense to test changes where you make
them. Unfortunately, it is not obvious that git commit --amend merely
edits the log message rather than committing a new tree.

For what it's worth, if we were to create an empty child commit and
squash it into the parent instead of amending immediately, then
git-rebase--interactive would disable tree verification in the second
step as well. This behaviour was introduced by commit c5b09fe. Although
the change seems to have been triggered by something completely
different back then, the correctness criterion remains the same, i.e.
recording previously committed trees.

Best regards,
   Fabian

 Specify the git-commit option `--no-verify` to disable the pre-commit
 hook when editing the log message. Because `--no-verify` also skips
 the commit-msg hook, execute the hook from within
 git-rebase--interactive after the commit is created. Fortunately, the
 commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after
 git-commit terminates. Caveat: In case the commit-msg hook finds the
 new log message ill-formatted, the user is only notified of the
 failed commit-msg hook but the log message is used for the commit
 anyway. git-commit ought to offer more fine-grained control over
 which hooks are executed.

 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
  git-rebase--interactive.sh | 17 +
  1 file changed, 13 insertions(+), 4 deletions(-)

 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index 689400e..b50770d 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -504,10 +504,19 @@ do_next () {
  
  mark_action_done
  do_pick $sha1 $rest
 -git commit --allow-empty --amend --no-post-rewrite 
 ${gpg_sign_opt:+$gpg_sign_opt} || {
 -warn Could not amend commit after successfully picking 
 $sha1... $rest
 -exit_with_patch $sha1 1
 -}
 +# TODO: Work around the fact that git-commit lets us
 +# disable either both the pre-commit and the commit-msg
 +# hook or none. Disable the pre-commit hook because the
 +# tree is left unchanged but run the commit-msg hook
 +# from here because the log message is altered.
 +git commit --allow-empty --amend --no-post-rewrite -n 
 ${gpg_sign_opt

Re: [PATCH RFC v2 07/19] rebase -i: The replay of root commits is not shown with --verbose

2014-07-11 Thread Fabian Ruch
Hi Chris,

you're the original author of the code touched by this patch. Is the
second -q option really a simple copy-and-paste of the first or am I
overlooking something here? I'd like to confirm this as, in retrospect,
I feel a bit uncertain about the hasty claim in the log message.

Kind regards,
   Fabian

Fabian Ruch writes:
 The command line used to recreate root commits specifies the
 erroneous option `-q` which suppresses the commit summary message.
 However, git-rebase--interactive tends to tell the user about the
 commits it creates, if she wishes (cf. command line option
 `--verbose`). The code parts handling non-root commits or squash
 commits all output commit summary messages. Do not make the replay of
 root commits an exception. Remove the option.
 
 It is OK to suppress the commit summary when git-commit is used to
 initialize the authorship of the sentinel commit because the
 existence of this additional commit is a detail of
 git-rebase--interactive's implementation. The option `-q` was
 probably introduced as a copy-and-paste error stemming from that part
 of the root commit handling code.
 
 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
  git-rebase--interactive.sh | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index 0af96f2..ff04d5d 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -511,7 +511,7 @@ do_pick () {
  --no-post-rewrite -n -q -C $1 
   pick_one -n $1 
   git commit --allow-empty \
 ---amend --no-post-rewrite -n -q -C $1 \
 +--amend --no-post-rewrite -n -C $1 \
  ${gpg_sign_opt:+$gpg_sign_opt} ||
   die_with_patch $1 Could not apply $1... $2
   else
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages

2014-07-10 Thread Fabian Ruch
Hi Junio,

Junio C Hamano writes:
 Fabian Ruch baf...@gmail.com writes:
 The command line used to recreate root commits specifies the
 erroneous option `--allow-empty-message`. If the root commit has an
 empty log message, the replay of this commit should fail and the
 rebase should be interrupted like for any other commit that is on the
 to-do list and has an empty commit message. Remove the option.

 The option might have been introduced by copy-and-paste of the first
 part of the command line which initializes the authorship of the
 sentinel commit. Indeed, the sentinel commit has an empty log message
 and this should not trigger a failure, which is why the option
 `--allow-empty-message` is correctly specified here.
 
 The first commit --amend uses -C $1 to give the amended result
 not just the authorship but also the log message taken from $1.
 If we are allowing a commit without any message to be used as $1,
 I think --allow-empty-message needs to be there.  If $1 requires
 the option here, why doesn't the second one, that records the
 updated tree with the metainformation taken from the same commit
 $1 can successfully commit without the option?

(I realize now that the emptiness of the sentinel log message is
irrelevant to the success of the first commit --amend since we are
amending using -C. I'll rewrite the second paragraph of the patch
description.)

The first commit --amend requires --allow-empty-message because we do
not want to fail without the authorship or log message of $1 being in
place. It's not a matter of allowing or disallowing empty log messages yet.

git-rebase--interactive can come across an empty log message in three
different ways, which are, depicted as to-do list tasks, the following.

 1) pick --ff $1
 2) pick --no-ff $1
 3) reword $1

This patch is concerned with consistency in the second case.
git-rebase--root does not handle the first case yet and the third case
is handled somewhere else in the script independent of the first two.

The --root option handling was added to the script as a special case
later in the revision history. It's that option handling which
introduced the inconsistency that non-fast-forwards of commits with
empty log messages succeed if they are root commits but have always
failed otherwise.

Your reply suggests that git-rebase--interactive was wrong from the
beginning and that the replay of commits without any message should be
allowed. This would reconcile the first case with the second. In fact,
since neither of them alters the changes introduced by $1 or its log
message, it might be incorrect to complain about a missing message in
the first place.

Do you want me to replace this patch with a patch

rebase -i: Always allow picking of commits with empty log messages

that makes git-rebase--interactive cherry-pick commits using
--allow-empty-message? The script would still abort an empty reword with
the new patch and the user could then still force the empty log message
with git commit --amend --allow-empty-message.

   Fabian

 Puzzled...
 
 Add test.

 Signed-off-by: Fabian Ruch baf...@gmail.com
 ---
  git-rebase--interactive.sh |  2 +-
  t/t3412-rebase-root.sh | 39 +++
  2 files changed, 40 insertions(+), 1 deletion(-)

 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
 index 4c875d5..0af96f2 100644
 --- a/git-rebase--interactive.sh
 +++ b/git-rebase--interactive.sh
 @@ -510,7 +510,7 @@ do_pick () {
  git commit --allow-empty --allow-empty-message --amend \
 --no-post-rewrite -n -q -C $1 
  pick_one -n $1 
 -git commit --allow-empty --allow-empty-message \
 +git commit --allow-empty \
 --amend --no-post-rewrite -n -q -C $1 \
 ${gpg_sign_opt:+$gpg_sign_opt} ||
  die_with_patch $1 Could not apply $1... $2
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message

2014-07-10 Thread Fabian Ruch
Hi Andrew,

thanks for your review and sorry that I forgot to cc the bug fix to you.

Andrew Wong writes:
 On Tue, Jul 8, 2014 at 4:31 PM, Junio C Hamano gits...@pobox.com wrote:
 Fabian Ruch baf...@gmail.com writes:
 It is true that a failed hook script might not output any diagnosis...

 I think the message originally came from 0becb3e4 (rebase -i:
 interrupt rebase when commit --amend failed during reword,
 2011-11-30); it seems that the primary point of the change was to
 make sure it exits and the warning message may not have been well
 thought out, but before discarding the result of somebody else's
 work, it may not be a bad idea to ask just in case you may have
 overlooked something (Andrew Wong Cc'ed).

 but then the generic message is not of much help either. Since this
 lack of information affects the built-in git commands for commit,
 merge and cherry-pick first, the solution would be to keep track of
 the failed hooks in their output so that the user knows which of her
 hooks require improvement.
 
 Since git commit already prints out error messages for failing due
 to empty commit message, the third message is really about giving
 hints in the case where pre-commit fails. We could probably assume
 that pre-commit would also print out error messages. So I'd be fine
 with removing the third message. But I wonder if we need to explain
 that the user needs to run git rebase --continue to resume the
 rebase?

That is still taken care of by exit_with_patch here. When called in the
error case, it prints

You can amend the commit now, with

git commit --amend

Once you are satisfied with your changes, run

git rebase --continue

to standard error. I might have overlooked this in one of the later
patches though.

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


  1   2   >