[ImageJ-devel] Helper script for fixup commits
Johannes Schindelin
schindelin at wisc.edu
Mon Feb 4 17:55:29 CST 2013
Hi Curtis,
as promised, a little Perl script to help with fixup commits.
For everybody who wonders what I am talking about: my preferred workflow
involves topic branches for projects involving more than one commit
(single commits are not worth the hassle). For this, I start with
git checkout -b <name>
(Actually, very often I do have changes already, but that's okay, I can
still make a new branch from the current state.)
Then I make changes and commit and rewrite the topic branch frequently.
For example, when I find that I made a mistake in the first commit, but I
am already on the fourth commit in the topic branch, I commit a "fixup":
git commit --fixup HEAD^^^
This tells Git to look at the third-last commit, take the first line,
prepend it with "fixup! " and commit with that message. Such a
specially-crafted commit message is interpreted by "git rebase -i
--autosquash" to mean that it should reorder the commits so that the fixup
commit can amend the original one.
After a couple of commits, my topic branch would look a bit like this:
<hash> <first-line>
01234567 Fix typos in the README
cafebabe Format LICENSE
fedcba98 fixup! Fix typos in the README
223387ab Add another author
When calling "git rebase -i --autosquash origin/master" -- assuming that I
started my topic branch directly on origin/master -- Git would present me
with an "edit script" like this:
pick 01234567 Fix typos in the README
fixup fedcba98 fixup! Fix typos in the README
pick cafebabe Format LICENSE
pick 223387ab Add another author
The "fixup" means that the second commit will be applied, but these
changes will be merged into the first commit.
I could ask rebase for further changes, such as "reword"ing the rather
unhelpful commit message of the now-last commit, but usually I keep things
as they are with the autosquash'ed reordering.
If you grow tired -- as did I -- of having to type "--autosquash" all the
time: do what I did:
git config --global rebase.autosquash true
That will make that rather helpful behavior the default.
I try to document such things on the Fiji Wiki, of course:
http://fiji.sc/Topic_branches
Back to you Curtis: I did write that Perl script which finds out what
commit you should rebase onto, but the truth is that
git rebase -i --autosquash $(git merge-base HEAD origin/master)
would work just as well: interactive rebase is clever enough not to
rewrite the first commits when there is no need to. In other words, it
does not re-commit any commit when it would have the same parent.
Ciao,
Dscho
-------------- next part --------------
#!/usr/bin/perl
my $countdown = 100;
my %fixups = ();
my $commit = '';
open(my $in, '-|', 'git', 'log', '--format=%h:%s', 'origin/master..');
while (<$in>) {
s/\r*\n*$//;
if (/^([0-9a-f]*):(.*)$/) {
my $hash = $1;
my $oneline = $2;
if ($oneline =~ /^fixup! (.*)$/) {
$fixups{$1} = 1;
} elsif ($fixups{$oneline} ne undef) {
$commit = $hash;
delete $fixups{$oneline};
}
}
if (0 < keys(%fixups)) {
$countdown = 100;
} else {
$countdown--;
if ($countdown <= 0) {
last;
}
}
}
close($in);
if ($commit ne '') {
system('git', 'rebase', '-i', $commit . '^');
}
More information about the ImageJ-devel
mailing list