Untangling Commits with Git GUI

If you are anything like me (and I hope, for your own well being, you’re not), you’re probably constantly changing frameworks, even programming languages, and you’re writing code as if every line’s an experiment. Sometimes it’s just curiosity, sometimes it’s just ‘being noob’, but I’m always writing more lines of code than the atomicity limit.

Git GUI in action: selecting what to stage

When working with source control systems like Git, you must keep commits atomic, so that merges and bisecting don’t give you too much headache. My rule of thumb is to commit individual functions and class methods. If I’m writing docs, I try to commit the whole sections only the first time I write them, and then every change I make, I try to commit on paragraph level. Finally, I never ever commit changes across multiple files at once, even when they are logically connected. It’s enough if the commits for such changes are in a sequence. There is absolutely no need to keep them all shoved in a single commit.

But that’s under ideal circumstances. I’m mostly self-taught and inexperienced when it comes to programming. So I do a lot of what I call ‘coding ahead’ – trying to code something up to see if it works before fully understanding the problem. It usually works in the end. The more I mess around, the better I understand the problem. This creates another problem, though, and that’s managing commits when I’m finally done.

Messing around sometimes mean invalidating previous 10 commits. “Yeah, I was wrong all the time, now what do I do?” Most of the time I go by this rule: it makes no sense to keep the coding-ahead-in-progress code in the repository. So I basically just discard whatever commits are bad. To do that, first run:

git log

Note the last commit that contains whatever last change that’s worth keeping and copy the commit hash. Then paste the commit hash into this command:

git reset [your commit hash]

What this does is revert to whatever commit you’ve specified and leave all changes since then in your actual files (this marks them as modified).

Some of you might say that this is unforgivable practice, and that it’s dirty. And I understand. If you’re a purist, or a firm believer in immutable history, you may be outright aggravated by how I manage my code. But this works for me. For me, having a functional history of only what’s worth keeping is more important than having an immaculate record of my every keystroke.

And now the hard part. Structuring your commits. I don’t know if you knew about this (and I’ve learned it just a few hours ago), you can actually stage changes for commit line by line. Using the Git GUI, you have perfect control over what gets committed in what order. So, start it up.

git gui

Now, the top-left is the list of changed files. bottom-left is the list of files that have staged code. top-right (large area) shows your code, and the bottom-right has the buttons for committing and the area for your commit message.

Pick a file you want to commit first. You can right-click the code, and say “Stage Hunk For Commit” which stages all changes in that hunk (from one @@ to the next). Or you can right-click the line and say “Stage Line For Commit”. If your hunk seems too large, just remove lines by selecting the file in the staged files section (bottom-left file list), and right-clicking them, selecting “Unstange Line From Commit”.

Once you’re done staging, you can compose your commit message and hit “Commit”.

Although there are definitely those who might frown upon this practice, I find this the most effective way of keeping a neat repository, and having useful commits that are not hard to merge or bisect. YMMV, of course. By the way, if you find a way to stage entire sections, please let me know. Drop me a line or a comment.

Comments

The Best Git UI for Vim: Fugitive

Tim Pope, known to many Vim (and Rails) users as just tpope, very well known for his many vim- projects (including the infamous pathogen plugin), has this to say about his Fugitive plugin for Vim:

I’m not going to lie to you; fugitive.vim may very well be the best Git wrapper of all time. Check out these features: […]

And he didn’t lie. Fugitive is so awesome it may well be the reason for you to switch to Vim right fucking now. But of course, you are already using Vim, aren’t you? Oh and if you’re not using Git, you absolutely suck. :P

[ read more... >

Comments