Subject: Re: Ability to edit message from git rebase --interactive.

From: "Marcel M. Cary" <[email-masked]>
Date: Wed, 18 Mar 2009 14:02:08 -0700

Marcel M. Cary wrote:
> Michael J Gruber wrote:
>> Sverre Rabbelier venit, vidit, dixit 18.03.2009 06:42:
>>> Heya,
>>>
>>> On Wed, Mar 18, 2009 at 02:06, Junio C Hamano <[email-masked]> wrote:
>>>> Jeff King <[email-masked]> writes:
>>>> I am not quite sure what rephrase is buying us.  Do we also want to
>>>> introduce retree that allows you to muck with the tree object recorded
>>>> without giving you a chance to clobber the commit log message?
>>> Is that a common operation? Rephrase is, at least to me...
>>>
>> Rephrase for sure is common, and for sure can be done currently... It's
>> only that "commit --amend, save&quit, continue" could be shortened.
>>
>> OTOH: Most commonly one would want to rephrase a commit message or two
>> without actually rebasing anything. And the proposed change doesn't help
>> as much as it could, in two respects:
>>
>> 1) I want to be able to say "rephrase HEAD~2" without having to edit a
>> rebase action script. (That would be useful for rewriting a single
>> commit as well, and could be added easily.)
>>
>> 2) Currently, all rebasing operations have trouble with merges. But if
>> all I want to do is rephrasing a log message then no diff/apply is
>> necessary, no rewriting of trees, no change in the DAG structure (i.e.
>> connectivity; sha1s change, of course). So there should be a special
>> mode for DAG-preserving rewrites, where one can be sure that merges are
>> fully preserved.
>>
>> 2) seems to be the most important point to make rephrasing safe and
>> convenient.
> 
> Interesting points about skipping the action script and preserving
> structure.  I just tried to do something like that with filter-branch:
> 
> git filter-branch --msg-filter 'cat > tmp;  $EDITOR tmp < '$(tty)' >
> '$(tty)' 2>&1; cat tmp' ^HEAD^ HEAD
> 
> And discovered that it will neither accept "HEAD^^..HEAD^" nor "HEAD^"
> as a shortcut for a rev-list containing a single commit.  But if you're
> content to save and quit each message through the branch tip and specify
> the range, it seems to work.
> 
> I have no idea what it would take to make filter-branch support the
> additional kinds of rev and rev list specifications, or if that would be
> undesirable.
> 
> I'm assuming it accomplishes (2) because of the nature of filter-branch.

Ok, so I guess you have to explicity tell filter-branch all the commits 
that reach the ones you want to rewrite so it will know to fixup their 
parents.  Below is a rough way of doing that, but sometimes it will find 
too many commits, and it's rather slow, even on a git.git.

git-rephrase:
#!/bin/sh

if [ -z "$EDITOR" ]; then
     export EDITOR=vim
fi
# Does change tags
refs=$(git for-each-ref --format='%(refname)' 'refs/heads/*' |
     while read ref; do
         # This is the slow part
         if git rev-list $ref | grep -q $(git rev-parse --verify $1); then
             echo $ref
         else
             echo ^$ref
         fi;
     done
)
parents=$(git rev-list --max-count=1 --parents $1 | {
     read hash parents
     for hash in $parents; do
         echo ^$hash
     done
})
git filter-branch --msg-filter "
     if [ \$GIT_COMMIT = $(git rev-parse $1) ]; then
         cat > tmp
         \$EDITOR tmp < $(tty) > $(tty) 2>&1
         cat tmp
     else
         cat
     fi
" $refs $parents