Maybe my workflow is broken, but I often have the problem that I need to swap the last two commits I did to my git repository. That is due to the fact that my last commit is usually what I’m really working on. I know I could use more branches, but still. When I’m cleaning up this commit, e.g. to get it past all the static (Findbugs, Checkstyle) checks bevore publishing it, I sometimes come along stuff that is broken or ugly but has nothing to do what I’m currently doing. Not beeing able to leave wrong code untouched I fix it and commit it away. But now the last commit is not what I’m “–amend“ing to anymore. What I always wanted to do is “git swap“, to just swap the commit before the last one to the top of my chain. I know that I can do a combination of git rebase –i or git reset, but I like stuff to be simple. I opted to write a script that rewrites the git-rebase-todo in order to make handling of conflicts more straight forward. So now I can do this:
$ mkdir git_swap_test $ cd git_swap_test/ $ git init Initialized empty Git repository in /tmp/git_swap_test/.git/ $ echo 'foo' > file1 $ git add file1 $ git commit -m 'First Commit' [master (root-commit) 14b55a7] First Commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file1 $ echo 'bar' > file2 $ git add file2 $ git commit -m 'Second Commit' [master c9f97e4] Second Commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file2 $ echo 'baz' > file3 $ git add file3 $ git commit -m 'Third Commit' [master 40f98d8] Third Commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file3 $ git log --format=oneline 40f98d8bfbc4edaede576e18b7f4fa20dfde02bf Third Commit c9f97e42e2ecd0821e3edf45c4dd599540972b46 Second Commit 14b55a753ea9ed291ec511d42effdf190e44ad09 First Commit $ git swap Reversing all commits up to HEAD~2 Successfully rebased and updated refs/heads/master. $ git log --format=oneline 569fd69259bcf7ca8a4a25fe4c3e82e860e995d8 Second Commit 7414eee241877e0f0c0d4d317c4f06384bd27715 Third Commit 14b55a753ea9ed291ec511d42effdf190e44ad09 First Commit $ git swap Reversing all commits up to HEAD~2 Successfully rebased and updated refs/heads/master. $ git log --format=oneline 300c358d4d6e2b26a4f06c41e438068a7d6b630e Third Commit 87ac4cf567bcab51a57c1599de8b5faee1b7cfb7 Second Commit 14b55a753ea9ed291ec511d42effdf190e44ad09 First Commit
What I did to do this is first write a small Shellscript that basically overrides GIT_EDITOR with my own Perl implementation:
https://gist.github.com/1325749.js?file=git-swapThis is what makes it possible to call “git swap“. Acutally, you could call it with any commitish, in order to swap up to there, but that might not be what you want. It just defaults to the two topmost commits. The real work is done in the swapper.pl file:https://gist.github.com/1325749.js?file=swapper.pl
This reads the git-rebase-todo (which comes as the first command line parameter), reads all it’s lines and reverses the order. That is what git rebase -i uses to change the order of the commits. That’s it. Now I save at least 5 seconds per extra commit, because that is the time my Emacs needs to boot up ;).