Hacker News new | past | comments | ask | show | jobs | submit login
A Note About Git Commit Messages (tbaggery.com)
104 points by sant0sk1 on Jan 7, 2011 | hide | past | favorite | 54 comments

I find it unnatural to write commit messages in the present tense. To me, it seems like commit messages are a log of what work has been done, which would naturally be described in past tense. Nonetheless, I do write my commit logs in present tense for the sake of consistency.

Does anyone have a good explanation of why commit messages should be in the present tense? (Beyond what the article says: "This convention matches up with commit messages generated by commands like git merge and git revert.") Why do commands like git merge and git revert generate commit messages in the present tense? The best explanation that I can think of is an analogy to literature: literary analysis is written in the present tense, because any time you open a book, the story is happening now, in the present tense. I don't quite buy that, but it's the best explanation I've come up with.

My guess is that it's because it was designed from the point of view of someone looking at patches to be added, rather than from the point of view of someone who writes a bunch of code. Imagine you're looking at a patch and asking what it does. It's more natural to describe that this patch will "add support for feature X" than "added support for feature X".

When the message is supposed to describe what the patch does, shouldn't it then be written in the 3rd person singular: "adds support for feature X"?

Commits are like actions.

For example, think about the "fast-forwarding", "rewinding" and "replaying" that Git does. When you rebase, Git rewinds your divergent commits, fast-forwards the branch, and then replays your commits again. What happens when it replays those commits? Fix login bug. Update copyright year. Ignore log directory. Done!

I don't know it seems so weird to see it like that, fix login bug seems more like a todo than an action.

I could understand if it were in this format: Fixes login bug. Updates copyright year. Ignores log directory. Those seem so much more like actions than the other.

I also find writing commit messages in present tense unnatural.

Possible Explanation for present tense commit messages - Commit messages are treated as Instruction(s) to a third person, as if she is applying the patches one-by-one.

"Implement Feature A"

Now, "Fix the bug in the previously developed Feature A" etc.

A patch that changes X to Y will always change X to Y. Maybe you applied the patch in the past, but the patch itself will never stop changing X to Y.

You win the aerique Daily HN award for the best and most concise answer. From now on I will write my commit messages in the present tense.

Is "Fix bug" actually in the present tense? I would have thought present tense would be "Fixing bug", and that Fix bug is imperative.

That makes more sense (to me) for the example of rebasing - the applied diffs become a list of commands of what to do: Do this! Do that!

I hesitate to be this guy, but: If I'm not mistaken, strictly speaking, the mood/mode is imperative, but the tense is present. Imperative is not a tense. In English, there are only two true tenses: past and present.

To disclose fully, I had only a notion of this before resorting to Wikipedia to confirm and provide some clarity. http://en.wikipedia.org/wiki/Grammatical_tense and http://en.wikipedia.org/wiki/Grammatical_mood

They're both present tense:

- "Fix bug" is simple present

- "Fixing bug" is present progressive

I used to find it unnatural too. Recently, I changed my working habits so that I keep a running todo list of things I'm working on. When I complete a task, the todo becomes the commit message, and I leave it in present tense.

Other reasons to prefer it:

* It's generally shorter than the alternatives: "Implement" versus "Will implement", "implements", or "implemented".

* I think it's actually more accurate to say that commit messages should be in the imperative mood, not the present tense. The message is basically telling some unspecified agent to do something "Fix this bug." That lines up with the imperative form we use to write a lot of code.

Clearly there is an ordering between commits -- parents and children -- but I don't see commits as having much temporal value.

Branches and commits can be merged and rebased left and right, and it only seems to follow that commits have an intrinsic state that's (not to be cliché) timeless. Patches and commits, regardless of when they're written, provide changes and accomplish X Y and Z -- it's only when one runs the code that time comes into play.

Semantics, I suppose, or I have had too much coffee this morning.

The idea i get is that the log is not a history of your actions, but a description of what that particular revision does. So if i take the diff and apply it to my tree, the log tells me what it will do.

I write my commit messages in the present tense, but I have no idea why anyone would care about it in the slightest.

> wrapping your commit messages to 72 columns

> On an 80 column terminal

> Good email netiquette dictates we wrap our plain text emails (for) an 80 column terminal.

I think format should be separated from presentation and presuming people should use a particular display device is wrong. These are well established principles and Unix, although lacking a tradition of interface design, isn't some kind of exception.

* I use a modern email program (I use gmail but this would include, say, mutt).

* I sometimes use a wider terminal. Sometimes I use a narrower one. On my system (OS X default 10.6) less handles this just fine unless some 72-character-neckbeard screws it up.

* I sometimes use a GUI tool to examine messages, like github. These may be wider or narrower.

In all these cases forced 72 character wrappings look terrible.

I agree that ideally, you wouldn't wrap your text manually and your editor would do soft-wrapping, as well as any tools like `git log` or email programs that patches were read with, so the commit message would fit on any size screen.

In the real world, however, lots of people use editors that don't have good soft-wrap support turned on by default, meaning that they're going to be doing hard-wrapping at some width. `git log` does not do any wrapping of messages, so depending on your pager settings you either get the line going off the edge of the screen or being wrapped by your terminal with no regard for word breaks.

Furthermore, even when soft-wrap is supported, it sometimes makes text harder to read; if your window is wide, and it just uses the whole thing displaying 150 characters per line, it can make the text a lot harder to read than a nice narrow column of text. I have this problem on the web a lot; some sites use multiple columns which take up lots of horizontal space (under the assumption that everyone runs their browser full-screen), which makes me widen my window, but then I come across a site that just uses the whole width for one big block of text, which now has unreadably long lines.

Given that many of the tools in question don't support soft-wrapping usably, standardizing on 72-column hard wrapping is a reasonable approach. Lines don't come out unreadably long that way, they will be displayed reasonably in `git log` and other tools on standard-width terminals, and they will display well in 80-column email clients even with several levels of quoting.

I totally agree with this. Frankly, I don't think its too much to ask people to use modern software that is capable of very basic functionality like wrapping text. I find 72-column text with arbitrary (in the sense that the line breaks are at character-boundaries, not paragraph boundaries) line breaks incredibly hard to read.

For example:

  I guess it also depends on who your audience is. Most of the devs I've
  worked with use modern software, so long lines have never been an
  issue for me. I could see where some teams would have a culture of 
  using more basic tools that it would become more of an issue. Of 
  course, typography plays a role, too. I don't generally use a 
  monospace font for reading normal text, and proportional fonts seem 
  to work better with this outdated style.

Wrapping text really muddles code. Ideally commit messages should have a different interface than your code, but in some cases people are going to be looking at it through a tool that is in more of a code-oriented space.

Exactly. That's why you write it to the lowest common denominator, so that everyone can use it well.

And let's not forget where else where the text may end up later.

I'm sure this message was fine in their mail reader:

http://www.ietf.org/mail-archive/web/manet/current/msg11520.... (chosen only b/c I was reading through the list this morning)

But now I must horizontally scroll :(

To be fair, thats a problem with the way browsers render anything inside the <pre> tag. If anything, it is an example of what people should do, not force unnecessary restrictions on the way they write text. Lest you might end up with:

    > This is a short paragraph that I am quoting that 
    > someone
    > else sent to me.

Emacs has spoiled me. As soon as I saw your post, I felt a weird tingling urge to press M-q and fix it.

Indeed. We can fix all these systems... or stay at 72 columns.

Or door 3: Let bad software stay bad, use good software instead and format our text naturally. If somebody chooses to use software that can't wrap text, that's fine for them personally — but I shouldn't have to deal with their artificial limitations.

Right-click, Inspect Element `white-space: normal`

No more scrolling.

The problem is with the way the archive web site decided to render this text.

From a web standpoint, the author of this email did the right thing: introduce very little formatting (only paragraph breaks) and leave it up to style sheets to render his text the way the reader wants it.

That's how you get the same text to render perfectly on a twenty column display (e.g. an old phone), a 30' inch monitor and everything in-between.

Introducing manual newlines at arbitrary points (e.g. 80 columns) is a bad practice that assumes that everyone will read your text on the same device.

Relevant explanation:


Don't you mean:

  > Exactly. That's why you write it to the lowest common denominator, so
  > that everyone can use it well.
Reads great!

I didn't say that all text ever should always be 72 columns in length. A git commit message and a Hacker News comment are used in completely different ways.

Also, I probably would have moved the ', so' to the next line, so that it reads a bit better.

Agreed: re: making sure that everyone can use it well, but targeting LCD will break newer devices sometimes. As far as I can tell, using linebreaks for linebreaks will give you readable output on the widest variety of devices.

Some interesting data on how line-length affects readers exists here: http://www.codinghorror.com/blog/2006/06/text-columns-how-lo...

What's terrible with 72 char wrapping? 72 char wrapped text looks almost like an average printed book or pdf for example and reads perfectly well.

And people who have really large screens could use vertical splits or maybe tilling window managers to utilise their screen space more effectively.

The log messages are written for the 3rd person, not you. He may not use a modern email program, wider terminal or GUI tools, like you do.

It makes sense to write for the least common denominator.

This may be a mundane post, but it's sorely needed IMO. Way too many people create crappy commit messages. I've started kicking them back to the developer to fix.

How do you ask them to fix them? I'm imagining that you see the commit message after they've pushed it up somewhere. Are you asking them to reword/amend the commit--i.e., change the history of a pushed branch, with the little bit of extra work that involves?

This isn't really an issue. Contrary to what a lot of people will tell you, it is fine to change the history of a pushed branch -- especially for the most recent commit -- so long as other developers adopt a policy of rebasing after fetch. Here is a concrete example:

(bare repo): # Make sure receive.denyDeleteCurrent = ignore

(Dev A): git push

(Dev B): git pull --rebase # you can make this the default for a particular tracking branch so it is just "git pull"

(Dev B): # do some work

(Dev B): git commit

(Dev A): git commit --amend

(Dev A): git push origin :master # Deletes remote master. Not required for shared branches -- those can simply be replaced -- but "master" is usually the "current branch" for a repo, so it bears knowing.

(Dev A): git push origin master:master # And now we replace the remote's version with our local version.

(Dev B): git pull --rebase # Updates pointers and applies the new commit on top.

Yes, if you do even more devastating history changes than this, Dev B needs to dig a little further on why his rebase is going haywire. THIS is why people fear the history change; it is sometimes extra work for downstream developers to handle the rearrangements (and we developers like to be lazy and for everything to work smoothly the first time). Thankfully, downstream developers can solve these problems with a few git tools, including "rebase --onto" and cherry-picking. But in the case of a quick and simple commit amend, all is well.

Alternatively, you can code review, but sometimes people are in a rush, and you run into this situation. In most environments, I wager it will be okay, especially if there is communication on the changes and reasonable education on version control theory.

Interesting, thanks for the example, works exactly as you said.

There is a race when dev A deletes master though, right? What if someone else made a commit between when dev A last pulled and when dev A deletes master, wouldn't that commit be lost? In the process of testing this I managed to lose dev B's work a couple times, so I still think this kind of operation is too risky to be worthwhile.

In case anyone is interested I made a test script based on Xurinos's example: https://gist.github.com/769904

There is a race when dev A deletes master though, right?

Yes and no. I could say that this is where communication can help a little, and it depends entirely on your local group's policies, but that would be the easy cop-out. Let's say it really happened.

Dev B's git pull --rebase will also lose the change; it was assumed to be pushed up, and a git fetch means that you are reflecting exactly what is in the remote branch. But changes are never truly lost+++. Dev B can check his reflog, find his original commit, and cherry-pick it in, resubmitting it. Afterwards, he can bonk Dev A over the head for not pulling before pushing.

There is a danger that Dev B would not notice, but from a little test I just did, he is going to get some nasty messages during his git pull --rebase that should indicate that something interesting just happened.

I have not looked into this, but does anyone know if it is possible to lock a remote git repo (aside from the automatic push lock)? If one could manually lock the repo, the process would be to lock, pull, push-delete, push-for-real, and unlock.

+++ depending on your git configuration policy. I think you have 30 days before dangling commits are truly pruned permanently.

> I have not looked into this, but does anyone know if it is possible to lock a remote git repo (aside from the automatic push lock)? If one could manually lock the repo, the process would be to lock, pull, push-delete, push-for-real, and unlock.

Or maybe if Git could do a "test and set" on a ref? For example, instead of two step delete and recreate, how about "git push origin +master": forced update, but your Git sends "update master to 1234abcd iff your current master is 5678fedc" where 5678fedc is where origin/master points on your local Git. If someone had snuck in a new commit Git would then fail and you could deal with it. (Of course, on a busy shared repository "deal with it" could take a while if people keep sneaking in commits; but I suspect that kind of commit volume is very rare.)

Oh! I made a mistake. You do not have to delete or use the special config flag if you use --force for your push. I wondered why I remembered doing this on side branches. With --force, we do not have to do this. Also, I think you need to make sure you have -u on this kind of push so that you maintain your tracking connection, but I am not 100% positive.

Don't do this:

    git push origin :master
Do this:

    git push -u --force origin master:master

You do the review before the commit is pushed to the shared public branch. Lots of ways to do this. Here's three:

1. Use format-patch and review via email. 2. git push origin +HEAD:cr/js2

Now another developer can pull that branch and review it before it is merged to master.

3. Use Gerrit.

They push to an intermediate repo, where I can look at the changes. For some projects, we use gerrit, which makes this really easy (it's a review system from google).

And in case anyone needs negative examples (or a good laugh), check out http://whatthecommit.com/

The recent-ish vim syntax file for git commit message takes those recommendations into account - they don't do anything about the present vs. past tense obviously, but come up with color warnings, which helps a lot. That's actually how I learned about those preferences and the reasoning behind in the first place btw.

I believe that the syntax file is the work of Tim Pope - the author of the blog post we're talking about.


I consider "ability to write a good SCM commit message" one of the boxes to check on my "Is this person a good developer?" checklist.

Ever since reading that post, I've tried my best to adhere to similar guidelines. On a personal level, it kind of gives you a little 'retro' on what is was you just did, which is never a bad thing. I've also found myself making larger, more meaningful commits, which, I think, is a good thing.

Agreed. I've found that for me, to have meaningful commit messages, you have to have a meaningful amount of work complete. Otherwise you end up with a bunch of "more work on feature x" messages.

This is counter to a lot of the "commit often" mantra that so many git people have, but it's working better for me.

"commit often" is fine. It's "push often" that gets you into trouble. With an interactive rebase, you can polish up your commits and their messages before pushing them, presenting to your peers a finely crafted (readable, reviewable, maintainable) publication.

Indeed, I only discovered that recently and it makes git pretty cool.

It has the added advantage of being able to merge commits that fix intermediate bugs that you introduced yourself and fixed immediately. There is no reason to bore other people with those.

Commit often, fix them up. This is why I just can't side with the people who claim rebasing and rewriting your personal history is some sort of affront against nature. Take their argument and add it to the need for useful commits and what it unpacks to is that you should forgo all use of your source control until you have created a Perfect Patch, at which you are finally allowed to commit, until you create the next Perfect Patch. Of course that's not how they see it but it is what it actually translates to, inescapably. Really misses the point of the whole thing if you ask me; it really feels like accidentally raising old hacks to best practices.

72 character lines is unnatural to read for long sentences (especially in web browsers).

Also, less has line wrapping and who develops using 80 character terminals anymore? Maybe the author has a time machine back to 1981? I want access to that!

A lot of people still prefer work with revision control tools from a standard unix command line.... in an 80x25-ish window.....especially when it comes to debugging and investigating things (so we can use all our other nice shell text processing tools to make sense of things)

Something that fits nicely in that space is helpful in that case.

My favourite commit message this week:

"improve crapping"

(typo: should be cropping)

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact