git interactive rebase: reword without confirming each commit

113 Views Asked by At

I want to reword multiple (a lot) of commits in a git repository.

When I execute the following command:

git rebase --interactive HEAD~200

I get the following 'ui' in vim:

  1 pick 0c511d9 foo
  2 pick da36f6f bar
  3 ...

I might edit the vim buffer to look like this:

  1 reword 0c511d9 foo_changed
  2 reword da36f6f bar_changed_too
  3 ...

Now, when I confirm using :wq, git will pull up each individual commit in a new vim buffer. Worse than that, it will not even remember the modifications I did to the messages but show only the original messages.


Is there a way to just reword in the initial vim buffer the way I did, without having to reconfirm everything again?

I'm was hoping for some magical flag like git rebase -i --inline-no-confirm.

I saw this question, but that's not quite what I want, because I still need the editor initially.

2

There are 2 best solutions below

3
ChrisB On BEST ANSWER

I ended up writing the following convenience script which does what I described:

I called this git-batch-reword.sh. While it worked great for me, it's obviously a bit dangerous, so make sure to have a backup before blindly using this.

This currently drops everything after the first line of all shown commit messages because of the head -n 1 in the filter. If anybody knows a nice trick to work around that, please leave a comment.

#!/bin/bash
set -Eeuo pipefail

if [ $# -lt 1 ] || [[ "$1" =~ ^--?h ]]; then
    echo "usage: $0 <git-ref>"
    exit 1
fi

commit_ref="$1"

buffer=`mktemp`

git log --format="%H %s" "$commit_ref"..HEAD > "$buffer"

sed -i "s/^/keep /" "$buffer"

vim "$buffer"
result="$?"

if [ "$result" -ne 0 ]; then 
    rm "$buffer"
    exit "$result"
fi

filter_cmd='(sed -n "s/^\\(reword\\|r\\)\\s\\+$GIT_COMMIT\\s\\+\\(.*\\)/\\2/p" "'$buffer'"; cat) | head -n 1'

FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --msg-filter "$filter_cmd" HEAD

rm "$buffer"
0
eftshift0 On

If you have like a bunch of commits you would like to adjust in a single shot without going into each one of them, you could pull it off by writing a script that would be used in GIT_EDITOR. Mark the commits you want to edit as reword. Your script will be called with the path to a file that has the comment of the current commit being edited, right?

Well... create a file with the commit id and a single line with the commit comment you want for it:

0c511d9 foo_changed
da36f6f bar_changed_too

Then, every time your script gets called, you could know which commit is being worked on at the moment by using git rev-parse --short REBASE_HEAD... then you can read from the file I said before what should be written as the comment for that commit.... then you can replace the content of the file that you got as the argument to your script with that content....... so, the script could be something like this:

#!/bin/bash

COMMENT_FILE=$1

commit_id=$( git rev-parse --short REBASE_HEAD ) # check first that this is correct, that you get the commit ID that is being reworded and not another commit

comment=$( grep $commit_id file-with-new-comments | sed 's/$commit_d //' )
echo $comment > $1

That is a rough concept.... there might be details to take care of but it should work. The biggest question is if git rev-parse --short REBASE_HEAD gives you the commit being reworded.