threads / discuss / 23231

RFC - "git editlog" feature for fixing up local commit messages

Subject: RFC - "git editlog" feature for fixing up local commit messages

## tl;dr

8 messages between Mar 29, 2010 and Mar 30, 2010.

replies: 7people: 7as markdown or json

Eric Raymond· Mar 29, 2010, 13:31 UTC · lore

I'm quite prone to typos in my commit comments - sufficiently so that that when I was using Subversion for GPSD I wrote a script to ssh to the repo server and edit the comment property of a specified revision. That way, when I noticed a typo in the output of SVN log, I could fix it.

I don't have that liberty in the DVCS world of chained commit hashes, unless the commit is only local and hasn't been pushed. But that exception is important. Since switching GPSD to git, I've developed a workflow that looks like this:

(1) I develop, test, and commit a bunch of changes.
(2) Before pushing them to rigin, I eyeball the git log.
(3) If I spot typos in past revisions, I fix them locally.
(4) Only then do I push upstream.

Now, about step 3. The official git command set only directly supports amending the tip commit. There is a semi-documented procedure for amending previous commits using an interactive rebase, but trying to understand it makes my brain hurt. Don't want to go there.

Instead, following a suggestion by thiago on #git, I've written a script I call editcomment (enclosed). It takes a revision spec as argument, then checks to see if that ref has any remote references; it it does, the script warns the user that he will discombobulate the order of the universe if he continues and requests confrmation.

If the commit is local only, or the user confirms he want to shoot self in foot, the script then runs a filter-branch operation using a filter that no-ops all other commits through but fires up an editor on the contents of the matching one as presented on stdin, writing the modified version to stdout on editor exit.

The overall effect is the commit comment gets edited and all hashes there and afterwards change, but if they were all local that's OK. I don't have to think about rebases or amends or reverts, and that;s exactly the way I want it. When I need to edit a comment, *I desire the luxury of ignorance about how it's done*.

My editcomment script, as it exists, has a technical problem...the editor needs to be something like emacsclient that actually invokes in a different X window, otherwise whatever it writes to stdout will end up stuffed in the comment along with the text I actually wanted to put there. The underlying problem is that git-filter-branch is sort of a nuclear-powered chainsaw - gets the job done, but in a way that is prone to messy side effects. A more elegant implementation would probably need to tie deeper into the plumbing.

Here's what I think any git user should be able to do: call "git editlog <commit>" and have it either

(1) refuse with an error message because the commit has remote references
    and the user didn't specify -f, or
(2) fire up an editor of the user's choice, accepting the edited result as
    a replacement for the commit comment. It should no-op if the
    comment is not changed.

For my own purposes, my editcomment script would be good enough, since I never really want to be able to use anything but emacsclient anyway -- vi not working is at best a very minor inconvenience for me.

But I'm advocating for this feature to be in git anyway, because I think it addresses a common need for which the existing interface is needlessly painful and difficult to understand. In the local case, I think this is not an operation that should require the user to care that DAG surgery is implied. git would be better art if users could ignore that.

Accordingly, I want to open a discussion on this...
* Do others agree that git editlog would be a desirable feature?
* Supposing it is, what would be the best way to implement it?
* Are there issues with this proposal that I haven't noticed?
-- 
		<a href="http://www.catb.org/~esr/">Eric S. Raymond</a>


#!/bin/sh
# Give this a commit-ID specification.  It will edit the associated comment.
# Usual caveats apply; the edited one and all commits after will change IDs,
# and pushing them to a repo with the old commits will wreak havoc.
# Note also that this cavalierly overwrites refs/original.
#
# This script by Eric S. Raymond, March 2010, all rites perverted.
# It's based on an idea by thiago from #git, but debugged and with a safety.
# It contains porcelain and porcelain byproducts.

topdir=`git rev-parse --show-cdup`
test -n "$topdir" && cd "$topdir"

my_commit=`git rev-parse $1` || exit $?

# Run a safety check before edits that could hose remotes.
if test -n "`git branch -r --contains $mycommit`"
then
    echo -n "Commit has been pushed.  Really edit? "
    read yn
    if test "$yn" != 'y'
    then
	exit 0
    fi
fi

my_file=COMMIT_EDITMSG
test -d .git && myfile=.git/COMMIT_EDITMSG

# This effort to invoke the user's normal editor fails.
# the problem is that anything the editor writes to stdout on the
# controlling terminal becomes part of the commit message.  So
# the editor needs to actually run inside another window.
#test -z "$GIT_EDITOR" && GIT_EDITOR=$EDITOR
#test -z "$GIT_EDITOR" && GIT_EDITOR=vi
#my_editor=$GIT_EDITOR

# xterm -e vi should also work.
my_editor=emacsclient

export my_file my_commit my_editor

exec git filter-branch -f --msg-filter '
if test "$GIT_COMMIT" = "$my_commit"; then
    cat > $my_file;
    $my_editor $my_file >/dev/null;
    cat $my_file
else
    cat
fi' "$1~.."

# End
Sverre Rabbelier· Mar 29, 2010, 13:41 UTC · re: Eric Raymond · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

Heya,
On Mon, Mar 29, 2010 at 07:31, Eric Raymond <esr@thyrsus.com> wrote:
> Now, about step 3.  The official git command set only directly supports
> amending the tip commit.  There is a semi-documented procedure for
> amending previous commits using an interactive rebase, but trying to
> understand it makes my brain hurt.  Don't want to go there.

Go there anyway. These days it's as simple as changing "pick" to "reword" on the appropriate commit. Really, give it a try.

$ git rebase -i origin/master
-- 
Cheers,

Sverre Rabbelier
Nicolas Pitre· Mar 29, 2010, 15:08 UTC · re: Sverre Rabbelier · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

On Mon, 29 Mar 2010, Sverre Rabbelier wrote:
Show 10 quoted lines
> Heya,
> 
> On Mon, Mar 29, 2010 at 07:31, Eric Raymond <esr@thyrsus.com> wrote:
> > Now, about step 3.  The official git command set only directly supports
> > amending the tip commit.  There is a semi-documented procedure for
> > amending previous commits using an interactive rebase, but trying to
> > understand it makes my brain hurt.  Don't want to go there.
> 
> Go there anyway. These days it's as simple as changing "pick" to
> "reword" on the appropriate commit. Really, give it a try.

While the 'git rebase -i' solution has its place (and I do use it myself), it essentially deals with only one branch while having a filter-branch based solution allows for such changes to be applied globally i.e. to all branches in the presence of history fork points.

Nicolas
Avery Pennarun· Mar 29, 2010, 20:14 UTC · re: Eric Raymond · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

On Mon, Mar 29, 2010 at 9:31 AM, Eric Raymond <esr@thyrsus.com> wrote:
Show 8 quoted lines
> My editcomment script, as it exists, has a technical problem...the
> editor needs to be something like emacsclient that actually invokes in
> a different X window, otherwise whatever it writes to stdout will end
> up stuffed in the comment along with the text I actually wanted to put
> there.  The underlying problem is that git-filter-branch is sort of a
> nuclear-powered chainsaw - gets the job done, but in a way that is
> prone to messy side effects.  A more elegant implementation would
> probably need to tie deeper into the plumbing.

It ought to be easy to work around this; simply extract the log message *before* filter-branch using something like

       git cat-file commit HEAD | tail -n +6 >msg.tmp

(I'm sure someone will correct me by providing a less revolting way to extract the commit message, but it's somehow not coming to me right now.)

Then launch $EDITOR to edit the message, then inside the filter-branch, just use that file instead of launching the editor.

Alternatively, in case you want the option of editing *multiple* commit messages at once, you could just redirect stdin/stdout to /dev/tty.

A further option would be to extend git-rebase--interactive.sh (yes, it's just a shell script) to take an option that makes a given commit (or commits) 'reword' by default instead of 'pick'. And maybe another option to make git-rebase--interactive.sh not actually pop up an editor before it starts running. Then your editcommit script could just be a thin wrapper around rebase with those options.

<insert obligatory wistful reference to git-sequencer> (I don't actually know anything about git-sequencer.)

Have fun,
Avery
Michael J Gruber· Mar 30, 2010, 08:52 UTC · re: Avery Pennarun · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

Avery Pennarun venit, vidit, dixit 29.03.2010 22:14:
Show 32 quoted lines
> On Mon, Mar 29, 2010 at 9:31 AM, Eric Raymond <esr@thyrsus.com> wrote:
>> My editcomment script, as it exists, has a technical problem...the
>> editor needs to be something like emacsclient that actually invokes in
>> a different X window, otherwise whatever it writes to stdout will end
>> up stuffed in the comment along with the text I actually wanted to put
>> there.  The underlying problem is that git-filter-branch is sort of a
>> nuclear-powered chainsaw - gets the job done, but in a way that is
>> prone to messy side effects.  A more elegant implementation would
>> probably need to tie deeper into the plumbing.
> 
> It ought to be easy to work around this; simply extract the log
> message *before* filter-branch using something like
> 
>        git cat-file commit HEAD | tail -n +6 >msg.tmp
> 
> (I'm sure someone will correct me by providing a less revolting way to
> extract the commit message, but it's somehow not coming to me right
> now.)
> 
> Then launch $EDITOR to edit the message, then inside the
> filter-branch, just use that file instead of launching the editor.
> 
> Alternatively, in case you want the option of editing *multiple*
> commit messages at once, you could just redirect stdin/stdout to
> /dev/tty.
> 
> A further option would be to extend git-rebase--interactive.sh (yes,
> it's just a shell script) to take an option that makes a given commit
> (or commits) 'reword' by default instead of 'pick'.  And maybe another
> option to make git-rebase--interactive.sh not actually pop up an
> editor before it starts running.  Then your editcommit script could
> just be a thin wrapper around rebase with those options.

I think the OP's point was that filter-branch is better at keeping merges in place; I'm not sure if this is true when rebase-i is used with reword only.

> <insert obligatory wistful reference to git-sequencer> (I don't
> actually know anything about git-sequencer.)
Oh yeah:)
Michael
Avery Pennarun· Mar 30, 2010, 18:36 UTC · re: Michael J Gruber · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

On Tue, Mar 30, 2010 at 4:52 AM, Michael J Gruber <git@drmicha.warpmail.net> wrote:

Show 11 quoted lines
> Avery Pennarun venit, vidit, dixit 29.03.2010 22:14:
>> A further option would be to extend git-rebase--interactive.sh (yes,
>> it's just a shell script) to take an option that makes a given commit
>> (or commits) 'reword' by default instead of 'pick'.  And maybe another
>> option to make git-rebase--interactive.sh not actually pop up an
>> editor before it starts running.  Then your editcommit script could
>> just be a thin wrapper around rebase with those options.
>
> I think the OP's point was that filter-branch is better at keeping
> merges in place; I'm not sure if this is true when rebase-i is used with
> reword only.

I've never actually tried the "--preserve-merges" option to git rebase -i, but the description sounds as if it's supposed to not have this problem. Can anyone confirm/deny?

Thanks,
Avery
Jonathan Nieder· Mar 30, 2010, 23:11 UTC · re: Avery Pennarun · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

Avery Pennarun wrote:
> On Tue, Mar 30, 2010 at 4:52 AM, Michael J Gruber
Show 7 quoted lines
>> I think the OP's point was that filter-branch is better at keeping
>> merges in place; I'm not sure if this is true when rebase-i is used with
>> reword only.
>
> I've never actually tried the "--preserve-merges" option to git rebase
> -i, but the description sounds as if it's supposed to not have this
> problem.  Can anyone confirm/deny?

preserve-merges is in bad shape. I’d recommend not using it unless you’re willing to hack on it.

Example issues: interacts poorly with merge.log, reordering commits produces very confusing results.

Example of why it is not necessarily the tool for all seasons: requires a diff+apply cycle. If you are tracking large or binary files or amending a very old commit message, it makes more sense to avoid this overhead. See http://thread.gmane.org/gmane.comp.version-control.git/143426 for example.

Hope that helps, Jonathan

Miles Bader· Mar 30, 2010, 05:46 UTC · re: Eric Raymond · lore

Re: RFC - "git editlog" feature for fixing up local commit messages

Eric Raymond <esr@thyrsus.com> writes:
> There is a semi-documented procedure for amending previous commits
> using an interactive rebase, but trying to understand it makes my
> brain hurt.  Don't want to go there.

I'd recommend becoming familiar with rebase -i anyway -- it's just plain useful, and really almost trivial to use once you've tried it.

Fixing comment typos is simple using the "r"/"reword" directive, but the ability to rearrange, drop, and merge commits, is also very handy and easy using rebase -i.

-Miles
-- 
In New York, most people don't have cars, so if you want to kill a person, you
have to take the subway to their house.  And sometimes on the way, the train
is delayed and you get impatient, so you have to kill someone on the subway.
  [George Carlin]

← back to recent threads