Boris K
Boris K

Reputation: 1552

Edit an old commit message with git filter-branch

In a case I want to fully edit a particular commit, I use the following command:

git filter-branch --env-filter \
"if test \$GIT_COMMIT = '5b740c488f0e4251a6e534cab79da8b05de7a195'
then
    export GIT_AUTHOR_NAME='John Doe'
    export GIT_COMMITTER_NAME='John Doe'
    export GIT_AUTHOR_EMAIL='[email protected]'
    export GIT_COMMITTER_EMAIL='[email protected]'
    export GIT_AUTHOR_DATE='1493100264'
    export GIT_COMMITTER_DATE='1493100264'
fi"

Is there a way to edit the commit message too ?

I'm aware I can mix --msg-filter with sed, but if multiple commits have the same commit message, that could be a problem.

What I'd like is a way to tell "For this SHA, set the commit message as X", similar to the way I edit author and commit date

Thanks a lot!

Upvotes: 4

Views: 1738

Answers (2)

Boris K
Boris K

Reputation: 1552

So, if anyone is looking for a working command, here is the one I use:

git filter-branch --msg-filter \
"if test \$GIT_COMMIT = '5b740c488f0e4251a6e534cab79da8b05de7a195'
then 
    echo 'New commit message!\nOn multiple lines'; else cat
fi"

Upvotes: 1

torek
torek

Reputation: 488103

You already know how to test in an --env-filter. All you need to realize, then, is that --msg-filter is used in the very same place as --env-filter:1

    eval "$filter_env" < /dev/null ||
            die "env filter failed: $filter_env"
    ...
    {
            while IFS='' read -r header_line && test -n "$header_line"
            do
                    # skip header lines...
                    :;
            done
            # and output the actual commit message
            cat
    } <../commit |
            eval "$filter_msg" > ../message ||
                    die "msg filter failed: $filter_msg"

The default value of $filter_env is empty, but this is replaced by your --env-filter argument. The default value of $filter_msg is cat; this is similarly replaced by your --msg-filter argument.

Both are evaled directly, in an environment in which $GIT_COMMIT, $GIT_AUTHOR_EMAIL, and so on are all set. Since filter_msg is eval-ed on the right hand side of a pipeline, changes to the environment variables are lost (so you must make any desired changes in the other filter), but you can still inspect them. Since $filter_env is run first, you must consider that any changes you made there are in effect by the time your $filter_msg gets run.

Hence:

What I'd like is a way to tell "For this SHA, set the commit message as X", similar to the way I edit author and commit date.

translates into:

--msg-filter 'if test $GIT_COMMIT = 5b740c488f0e4251a6e534cab79da8b05de7a195;
     then cat >/dev/null && cat $HOME/tmp/prepared-msg; else cat; fi'

or similar. (The cat >/dev/null is a bit of paranoia here to discard stdin to avoid broken pipe errors. If you use sed to edit the message, don't discard stdin.)


1I am not sure why the git-filter-branch.sh code uses a { while ... } loop to strip the headers from the commit, when sed -e '1,/^$/d' would suffice. ... Ah, I may remember why: some seds demand that messages end with a final newline, perhaps. Yes, that's why: see commit df0620108b9710a06d5a2d9c125d43b97590cce6)

Upvotes: 2

Related Questions