Max Max - 6 months ago 19
Bash Question

Appending string to git revert commit message without opening editor

We use an internal tool on the commandline to trigger reverts on our master branch. A typical call is like

$ supertool revert SOME-TICKET


Internally this PHP tool runs

...
$result = shell_exec("git revert -m1 --no-commit <COMMIT HASH>");
...


for all commits associated with
SOME-TICKET
.

I'm fine with the default commit message of the revert commit

Revert "<MESSAGE>"

This reverts commit <COMMIT HASH>.


What I now need to do is to append a line to that message, to make it look like:

Revert "<MESSAGE>"

This reverts commit <COMMIT HASH>.

<ADDING A LINE HERE>


If I execute
git revert
in a terminal, an editor opens and I can manually edit the commit message. But how can i pass in a message to
git revert
in an interactive environment, when the
revert
command is issued by another program?

Ideally our tool could
shell_exec
this command:

$result = shell_exec("git revert -message='...' -m1 --no-commit <COMMIT HASH>");


But I couldn't find such a parameter in the
git revert
docs https://git-scm.com/docs/git-revert

Is there any workaround for this?

Answer

When you use any of the sequencer based commands (revert and cherry-pick) and use --no-commit, these leave their default message in .git/MERGE_MSG, where git commit will pick it up for further editing. It's therefore possible to simply append to that file, then git commit --no-edit the result.

This is, as you've noticed, not documented anywhere and hence it might break in the future. To avoid that you might want to just generate your own commit message. For instance, as a shell script, if you want to revert commit $H, adding extra text $extra:

git revert --no-commit $H
[pause for user interaction as needed/desired]
tmpfile=$(mktemp)
printf >$tmpfile 'Revert %s\n\nThis reverts commit %s.\n\n%s' \
    "$(git log --no-walk --pretty=format:%s $H)" \
    $H \
    "$extra"
git commit -F $tmpfile
rm $tmpfile

(fancy this up more as needed, e.g., add trap code to remove the temp file on exit and/or signal; a -t argument to mktemp; and so on).

Note that when reverting a merge, the sequencer.c code produces more than just the usual This reverts ... message:

    if (opts->action == REPLAY_REVERT) {
            base = commit;
            base_label = msg.label;
            next = parent;
            next_label = msg.parent_label;
            strbuf_addstr(&msgbuf, "Revert \"");
            strbuf_addstr(&msgbuf, msg.subject);
            strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
            strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));

            if (commit->parents && commit->parents->next) {
                    strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
                    strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid));
            }
            strbuf_addstr(&msgbuf, ".\n");
    } else {

You can, of course, follow this as well, if you choose not to rely on .git/MERGE_MSG.

(Incidentally, for all occurrences of .git, use git rev-parse --git-dir.)