How to write a Git commit message (2014)
cbea.ms
cbea.ms
As a greybeard I've gone file-based backups, then SCCS, CVS, SVN, and now git for what seems like forever (git was 2005 according to wikipedia), though probably the late 00s. And migrating from one to the next (yes, quant code from the 90s is still running in 2022, and we have the commit messages to prove it).
Some people commenting above/below above the PR being the source of in depth information. As far as PRs are concerned, it's just another issue tracker, and I've been through the lot, also including various git hosting services). The commits travel with the repository. The PR discussions don't.
feat: support new line chart
fix: update props for new line chart
chore: bump dependency version
What's also cool is there are tools (semantic release) that will then handle automatically the versioning and publishing of your module based on these commits using the commit type (feat, fix, chore etc) to determine the next appropriate version [1].
Since then I've been obsessed with the conventional commit format everywhere for my own projects. Even if the commits aren't parsed for versioning, it just gets you into the habit of thinking about the scope of the commits.
The laughable part about building that full paved road pipeline is that the biggest friction point was always when devs didn't use semantic commits. At the time when I implemented it I didn't have checks for the commit format at the pr phase. I DID have a commitizen cli option as well but that was "Too much friction". Oh boy did I get bit. As someone who was working on DX I was constantly surprised by how many questions I got about something as seemingly simple as the conventional commit format from a crowd of enginerds.
also, +1 on fully paved road approach!
You might want to check out this GitHub Action to enforce PR title matches the spec: https://github.com/amannn/action-semantic-pull-request
I'm not. Writing code and writing git commit messages take entirely different types of thinking. With code you are having to think logically and problem solve to tell the computer what to do. Git messages are more analogous to writing a term paper (though shorter). You have to think about the what you are trying to communicate, how best to describe what this commit is all about, maybe trying to figure out if this counts as a fix or something else, etc. Writing code is fairly easy for me. Writing git commit messages is extremely difficult for me. I sometimes go days without commiting because I'm dreading having to write a commit message.
https://github.com/synek/git-plan
One feature I wanted to add was for it to parse your source code for comments with a specific format (e.g. `# git-plan feat xyz` or `# git-plan fix xyz`) and then stitch all the hunks together into commits for you. So all you'd have to do is comment your code and then run `git plan commit` and it would generate commits for you to confirm with y/n.
I built a prototype of that here:
https://github.com/synek/codeline
I haven't worked these for a while unfortunately :(
The commit messages are meant to be read by humans
It helps get everyone using it familiar quickly despite being annoying as you get used to it.
[1] https://github.com/github-changelog-generator/github-changel...
Personally I don't see much value in these half-automatted changelogs over just giving git history. It also raises the bar for contributions because contributors have to figure out a non standard commit message format.
Do I want to clean my house? Yes. Is it still a chore? Do some thinking for yourself.
I honestly have no idea what the heck you are talking about; hence my comment. Do you seriously perceive any chores as not worth doing? That sounds unhealthy.
> Do I want to clean my house? Yes. Is it still a chore?
> Do you seriously perceive any chores as not worth doing?
None of these are relevant as to whether 'chore' has negative connotations.
It clearly does to me and I'm baffled at the opposition. Do I want to clean my house? No of course not, and you don't either. If your house cleaned itself automatically would you still wish to do it? No, you do it because you need to, not because you want to.
Just about every dictionary definition mentions chores as at least possibly considered negative:
> a hard or unpleasant task: Solving the problem was quite a chore.
([1])
> A chore is a task that you must do but that you find unpleasant or boring.
> She sees exercise primarily as an unavoidable chore.
> Making pasta by hand with a rolling pin can be a real chore.
([2])
An entire article that wouldn't exist if chores were fun activities: [3].
> “Chore” can have a negative connotation and feel like a burden to a child.
[1]: https://www.dictionary.com/browse/chore
[2]: https://www.collinsdictionary.com/dictionary/english/chore
[3]: https://www.nspt4kids.com/parenting/take-the-chore-out-of-do...
If I didn’t do them, my life would be worse than if I didn’t! It’s pretty easy stuff! Embrace the chore, clean up after yourself! It’s worth doing.
Same with bumping versions on dependencies. If I didn’t have to do it I’d love to just get the new features in a non-breaking way. But I can’t, so I do, and it’s a chore.
> Chore: A routine or minor duty or task
Rather than
> Chore: An unpleasant or burdensome task
So "update". Attaching emotionally charged words like "chore" does nobody any favors, and in fact has negative consequences.
What's emotionally charged about this? It seems neutral to me.
Marking it as a simple chore sounds like the impact has not been fully analyzed.
I understand the practice and if done meticulously by all contributors, it should at least signal a well organized project but most of the time, it just shovels your entire commit log as a release notes. It's OK to have it, but I much prefer projects that takes time to summarize the impacts to their users.
chore: resolve a merge conflict
chore: fix code formatting
chore: update dependency type definitions library
Each of these things is nice to have tracked as their own commit so they don’t show up in other more impactful or isolated commits. They don’t add a lot to the code but are rather little house keeping actions that help keep a codebase clean and up to date.
This should never be a standalone commit! A merge conflict is solved by the merge commit, and if you were to override the automatic commit message, this seems like a very information-poor text to replace it with.
This is probably more appropriate for private projects rather than public contributed projects perhaps where the benefit of conventional style is to be able to easily create changelogs of large number of commits.
The other thing is that in an internal context, what does knowing whether it's a feature or a bugfix do for you? If it's such a big issue, then it'd be integrated into the issue prefix
BUG-001
FEA-002 < less likely as each feature epic will probably have it's own code, so it'll be more XXXX-001 XXXX-002
Now you have a nice short log that aligns nicely, and you can figure out mostly where your merge points were anyway, so no need for merge commits, rebase works mostly fine.
- BUG-001 fix for this thing
- FEA-005 initial commit
- FEA-005 unit tests
- FEA-005 implement this thing
- FEA-005 implement that thing
- FEA-005 fixes for code review
- BUG-002 fix for another thing
- BUG-002 revert fix did not work
- BUG-003 fix for that annoying thing
Of course, just my 2c and my limited personal experience.
* [feature] -> a new feature, can be incomplete, but should be a contained unit of work that's usable to the enduser in some way.
* [code] -> everything that improves the code, could be refactoring, library-updates or preparations for a feature
* [bugfix] -> minimal commit only for fixing a bug, should (almost) always include a test to reproduce the bug.
Sometimes I also use:
* [build] -> for build-improvements
* [performance] -> for performance-improvements
Specifically, I'm quite fond of https://gitmoji.dev
- Commit messages are shorter, even with ticket IDs.
- Commit log is easy to read
- Less prone to typos (chroe vs chore)
- Easy to enforce with push rules
- Easy to generate changelogs/release notes
- Easy to measure (metrics)
- Helpful IDE integrations
- It's a bit more fun than conventional commits
See https://github.com/tiangolo/fastapi for an example
For example:
----------------
improve Buffer Cache Management & logging
- change 'tryDrop()' to skip immediately, if lock unavailable
- move BufferCache logging to a separate logger
- attach BufferTrim.Unsuccessful -> Preemptive Flush of oldest buffers
--------------------------------
Having worked in many codebases & internal docs, I've found narrative significantly less efficient to read & write.
In commit messages, far too many developers skip almost any detail as to what they're changing & why -- the slowness of narrative formats may substantially contribute to this. In docs (Wiki etc), narrative encourages developers to ramble about minor technical details while omitting all high-level context.
Headline + bullet-points bypass a lot of struggles with narrative by allowing a simple headline and then, well, cutting to the point.
This also illustrates a informed personal preference -- studies find lowercase English words faster to scan/ comprehend.
See: http://literatejava.com/git/how-to-write-a-good-git-commit-m...
Ideally, commit messages should at least briefly explain what was changed (e.g., Add feature X, Fix bug Y) in addition to why it was done. When people look at git log output, they won't always show the associated diff for each log message. Also, when running git blame, they'll see the commit id and title, but not the entire change.
That doesn't mean that one can't run other commands to see the associated diff, or even getting the overall branch diff from the commit ids recorded in the merge commit, but having that what was done in the commit message allows one get an understanding before looking into it in more detail.
Yes, sorry didn't mention it explicitly, but that's normally what the first line of the commit message is for.
Not sure why the quicker qualification, here. Your example follows the article's guidelines exactly. (Except, as a minor point, the initial character is upper-case).
In fact, if each of the bullets were its own commit, this would be the default message of the squash-commit to master.
Don't ask me if I practice what I pushed there
In a more mature area, pace of work could often be slower and commits more granular. Until it's necessary to refactor/ reengineer things -- then commits are often larger again.
That's been my experience anyway, YMMV.
That wouldn't be important in itself, but Github trims your message at 50 characters as well. Because of that "feature" alone it's annoying to pass that limit.
But in the general case I find that if commits are not themselves concise and simple changes, they often should be broken up so that the moving pieces can be better tracked when looking back at the history.
The only other thing I'll say is don't be weird. I knew a guy who would prepend his commits with a [tag] saying what part of the repo his commit was touching. This was a mixed sw/hw project and every single commit of his started with [sw]. It's like, ok thanks, firstly, you're a software engineer working the ../sw/ folder, secondly no one was confused that your 17 changes to a C++ file were going to be a hardware change.
In practice, there often is not a very strict process around commits, so specific advice is often not very useful either.
This post describes a widespread standard practice. People never complain about my commit messages and they don't have trouble understanding them.
https://news.ycombinator.com/item?id=13889155 2017, 118 comments
https://news.ycombinator.com/item?id=10212582 2015, 90 comments
I was skeptical at first. For instance, the given reason for using imperative mode is not strong, in my opinion (the default git message on merge and revert is imperative is not a good reason, because other default git messages do not use the imperative). But, there are other good reasons for using it, not least of which is arbitrary consistency lowers cognitive load.
Now, it's my go-to if there isn't a good reason otherwise.
How you write your commit messages should be driven by whatever you use them for afterwards.
A change driven by a business decision? Don't see how it won't work.
A change specific to a component? Try conventional commits with scopes.
Code change? You shouldn't use commit messages. Use e.g. `-G`, `-S`, `-L`, etc. instead.
By the way if you are not using fzf already, you should.
Nowadays, you can easily enforce that the ultimate commit log looks rather nice by doing this:
1. Make it so the only merge strategy allowed on a repo is "Squash and Merge", so each PR = 1 commit in main branch
2. Have engineers care about the pull request quality rather than commit messages
It's easier to be more expressive in a pull request, and intermediate changes while working on a PR aren't super interesting to me.
git reset --soft <target>
Which will undo all commits and leave all modified files in the staging area. Then you can make one commit and force push it to replace your branch @ remote.
The interactive rebase is a completely normal operation and intended for exactly this situation. It is also much easier to craft more than one commit, and last minute fixes of spelling errors and such things.
To be safe, you can do:
git reset $(git merge-base <target> HEAD)
Which puts HEAD at the last commit in common between your branch and <target>… which, if target is already a parent/ancestor of your commit, is the same thing. But if target has had changed since you branched from it, this prevents you from undoing any recent commits.An arbitrarily large number of file changes can be packed into a single commit, sometimes for review purposes it makes sense to purposefully isolate different groups of changes in a manner that doesn't mesh with how the dev work was actually done - sometimes I just don't want to have an ugly commit history. I'm allowed to be OCD about my work and sweep the commit where I added print __LINE_NUM__ between each LOC to track down a bug one time that I was too lazy to use gdb under the rug.
I can't speak for everybody, but if GitHub goes down completely and I only had access to my git logs, I'd struggle to recreate ~20% of the information scattered across issues and PRs. This issue is external to merging preferences, but it's definitely not solved by squash-merges and descriptive merge messages.
`git commit --allow-empty` may be sufficient for that "there is a new commit" trigger in many cases. If so, that may be preferable to whitespace changes as those clutter up the blame.
As an aside, my initial commit on a repo is an empty one so that I can branch from a completely empty repo to do radical rewrites and yet maintain a history relationship with that initial empty commit (which I feel is preferable to an orphan branch and then a merge with unrelated histories ... though those tell slightly different stories in the log).
Oh cool, I thought I was literally the only person on the planet to do this lol. I'd do it for branchpoints too except git rebase by default acts very poorly with empty commits in the edited history (deletes them). I wish this was normalized (ie. there was a flag to `git init` to add a commit message for a root commit).
The frustrating thing about this is that this "omg minor commits on a merged branch clutter up the log!" is entirely a UI problem created by github's naive view of history where it shows things in a bafflingly obtuse linear order instead of letting you do something like `--first-parent` like the command line client lets you do.
Git itself has more than enough tools to give you that 'squashed' view without actually squashing anything, github just has no interest in providing it to you for whatever reason.
Also yes to the sibling comment that if you want to make something happen with a commit use `--allow-empty` and not "bump number" or "add random whitespace". Please.
Rebasing is a really nice tool, though I think the UI is really lacking. A simple GUI for interactive rebasing would help a lot. Most clients I've used (which isn't a ton since I generally prefer the CLI) don't even have an option for rebasing at all.
This hits home, it pretty much describes how I visualize logs in my head (compared to the visualizations I see that are more 2-D, branching off and merging together, etc.). I have a hard time working with some of the more advanced features because of this, and it'll probably always be an uphill battle to shift my thinking from linear to not-so-linear ...
git log --oneline --graph
Seeing the --graph output really helps in understanding the branch history. The lack of a view similar to --graph on Github drives me bananas.I don't like typing "git log --oneline --graph" all the time, so in my profile I have a `git slog` alias which is similar but adds date and author, plus truncates each line at 100 columns so it doesn't wrap:
slog = log --pretty=tformat:'%C(bold blue)%h %C(bold red)%ad %C(bold blue)%aN%C(auto)%d %<|(100,trunc)%s%C(reset)' --date=short --graph
My terminal has a light background. If you prefer a dark background, I suggest changing "bold blue" to "bold green" and "bold red" to "bold yellow": slog = log --pretty=tformat:'%C(bold green)%h %C(bold yellow)%ad %C(bold green)%aN%C(auto)%d %<|(100,trunc)%s%C(reset)' --date=short --graphBecause there's a bunch of PRs that were being operated on in parallel, and some probably that are even kind of old, the view you wind up with is likely a large streak of "PR merged" commits and then all the commits from those PRs jumbled together in an incoherent mess. Likely you'd have to scroll a few pages to even find some of those PR's commits (Note: git-log also has this as its default order, but you have some choices like --topo-order).
That said, I really really recommend you look at git's native --first-parent output, as I mentioned. That is likely the linear history you really want and it's right there in the client. It's the exact same thing as you get from a squashing strategy, except the history isn't gone it's just hidden.
I agree that the interactive tree views are chaotic and incoherent in their own ways. I don't use them either. I use --first-parent usually to find what I want and then I might dig in deeper if I need to.
But leaving that history there underneath means tools like git bisect can actually work, or if you need to narrow down onto a small change you actually can.
It doesn't always work (on a big project like Swift it would be a lost cause), but because I care a lot about presenting my work as a sequence of commits optimized for reviewability, I try.
> Because there's a bunch of PRs that were being operated on in parallel, and some probably that are even kind of old, the view you wind up with is likely a large streak of "PR merged" commits and then all the commits from those PRs jumbled together in an incoherent mess.
Oh yes, I've just run into this problem myself: I had to backport a large set of commits. While they're of course roughly chronological, they're not strictly so, and so the result in Github's UI is a giant mess.
I’ve been using Concourse to run my CI for years and years and just sort of assumed that “build again” was such basic functionality that every other CI system would also have it.
What is at my fingertips though? All the git commits of every repository that we still have. Which means that the only thing that's actually endured has been the commits. So, on behalf of folks 5-20 years from now who'll be scrutinizing your work, please put the context into the repo directly since it's the only thing that'll stick around.
I'm speaking of code that others will read. Maybe it is free software, maybe it is proprietary but shared by a larger team, maybe you are writing for customers... any way about it, if the code is to be maintained and read again over time the development history should be captured by a revision management tool like git.
I've been using bitbucket (not the shiny nice new bitbucket) at work for years and its PR search is so abysmally bad that anything in the PR message but not in the commit message may as well not exist once its merged. `git log` is forever, bitbucket search is /dev/null
I'm curious what other affordances or lack of affordances encourage what git behavior.
How many times do you actually change the default squashed message? If you write a series of garbage commit messages, I don't particularly trust that you'll write a very good squashed message, either. How many times do people skip updating the PR description with new information or features from comments? If your commit messages are good, the auto-squash message will be good and one will have a network dependency on GitHub to figure out what decisions went into that change.
In general I agree with your goal of a great commit log: 1 PR = 1 commit in the main branch. But I feel like GitHub is just the wrong tool to use if you want that. I used to use Gerrit, where commit messages _are_ your PR description. Sure, it makes you interact with git in some unfortunate ways, but the tradeoff is enforced commit cleanliness.
I've since started policing PRs whose commit messages reference things inside of our GitHub. At least provide a summary of what you're linking, for the worst case future.
1. The PR itself becomes a single giant commit. To adequately explain the diff in a single message would require writing an essay instead of a few paragraphs. It is also now hard to tell which part of the PR message is associated with which part of the massive diff.
2. If something breaks, you can't dissect into which part of the diff caused the problem.
3. It's harder to document your work as you go. I may be working on a PR for days or weeks. Commits give me an opportunity to document each part of my change _at the time I make the change_. It's a chance for me to record how and why at the time it's fresh in my head. If I wait to do this until the PR is ready, I likely will have forgotten some bit of context I wanted to record about the commit.
4. It encourages sloppy commits, making a large PR harder to review. Ideally, I should be able to review a large PR by looking through each commit.
If your reply to all this is to say you should just submit smaller and more frequent PRs, fine, but then why ever have PRs that consist of more than one commit?
This is a bad idea unless it works well for your specific company workflows and you don't care about the future possibility of changing platforms.
Git repos are designed to be self contained, decentralised, and offline-first. If you only care about how things look on github, then the repo will have poor usability outside of github - ie. on your workstation, in your local git tools, on a repo mirror, etc.
Git commits can be a powerful tool for understanding code if the messages are useful. They are immediately accessible through local tools and can quickly add context to a block of code without breaking immersion. But that immersion is broken as soon as you hit a commit messages like "Merge pull request #123" or "fix bugs".
Please don't do this. It erases history that's really useful for tracking down the cause of bugs.
There's plenty of ways to use git log to filter commits if a pretty history is your goal.
This probably seems like a whole lot of work for no benefit. However, I can’t tell you he number of times I’ve been on crappy plane wifi, hit `git blame` on some line and been able to comprehend my state of mind making a change years in the past.
Git history is a form of communication.
By doing that, you lock yourself into relying on Github in order to get the context behind a change rather than looking at the commit messages for a particular branch. That means, you cannot easily get that information just using git on the command line. On the other hand, if you put the context in a series of well formatted commit messages, you can get that context by reading through the commit log, either on the command line, or in Github by clicking on each commit.
> 1. Make it so the only merge strategy allowed on a repo is "Squash and Merge", so each PR = 1 commit in main branch
This leads to very large commits which cannot easily be reverted once any other commits that update the same files are added to the base branch. Also, in this case, the merge commits are essentially redundant, so why have them? There's nothing that prevents one from amending their commit to reference the PR number and eliminate the merge commit entirely.
> It's easier to be more expressive in a pull request, and intermediate changes while working on a PR aren't super interesting to me.
It really comes down to how those changes are presented. For example, if the change is one commit that adds a new method, and a second commit that adds calls to that method, that makes the change easier to review. Also, if a bug is found in the method, you can make a revert commit to remove all the calls to the new method, another commit to demonstrate the bug with one or more tests, another commit to fix the bug and update the tests to reflect that the fix works as expected.
If the commit was just a single PR commit, and another PR was merged, then one would have to craft a commit to undo the changes pertaining to that bug and then make a new commit in another PR to add the updated implementation. This makes it harder to see what the fix was since you essentially remove the entire feature and then commit a new version of that feature.
Having a well written commit history is in the spirit of the tool and is the more professional approach.
That's where the long-form back and forth arguments happen over the edge conditions.
Periodically a few days after a PR has been merged I'll have a discussion with someone and realize some context was never captured, so I'll just add it at the bottom of the closed+merged PR for posterity.
Yeah that means all the important information is in GH but if you migrate to GitLab or bitbucket or whatever they've got tools to pull all that info along with you when you migrate.
I don't really care about individuals commits other than to find the gitsha to find the PR that they were merged into in order to find the full context.
(Of course more often than not people have empty/useless linked work items, and PRs with useless titles and descriptions but that’s a whole different kind of problem.)
The PR commit can have sooo much good information, that can be used by so many teams. Loom videos for a quick demo of the feature. A concise description of the impact on customers, support teams. Deployment and feature rollout considerations.
I do try to make the individual commits somewhat presentable within the PR... a few extra minutes polishing the subjects lines. But nowhere near what this article, which seems to be suited for non-PR workflows such as mailing lists+patches, or workflows where every PR is squashed?
There's even a pitfall in putting too much "why" in the commit messages -- some programmers will be tempted to keep it out of the code, ie never comment their code.
Smashing commit history via squash makes debugging harder. Provided you have the interactive rebase chops to pull off crafting a decent granular history, you'll reap significant dividends down the road if you keep that history intact. Because it's right there for you to use with `git blame`, etc.
And then why not have proper discussions in the pull request with reviewers? Sometimes important stuff comes up in review. Sometimes you might close the PR and start anew. Sometimes the PR gets incredibly lengthy. Maybe the result is a commit history which condenses some abominably lengthy PR.
There's no need to choose between them. You can have both!
> "The Not Rocket Science Rule Of Software Engineering: automatically maintain a repository of code that always passes all the tests"
https://graydon2.dreamwidth.org/1597.html
Intermediate commits to produce a pretty history while not passing the tests reduce their usefulness to about zero.
I also like the approach where tests are performed in a temporary integration branch, then the main branch gets fast-forwarded to the tip of that integration branch only after the tests pass.
But the idea that intermediate commits must always pass tests forces you into some nasty contortions.
Say that you have to move files around, after which the tests fail, and then make a few minor changes to accommodate the new locations so the tests pass once agian. If you combine those two operations into a single step, troubleshooting that commit is a pain because the diff is gigantic.
For this reason, I prefer a less strict rule: all PRs get a merge commit and merge commits must always pass tests.
Well, our current issue tracker was migrated from Jira and I can still see all the ancient Jira tickets just fine (I mean what's important: the comments).
In any case, something is better than nothing at all.
That place used JIRA where the typical ticket ID was around 10 characters. That wasted a lot of prime real estate, e.g. in my email inbox, in history views (tig, gitk, and so on).
I also don't see the claimed benefit for git blame. In a real code base with significant history, it happens often enough that the first blame is an unrelated refactoring and you need to dig deeper. Therefore, I find that best practice is to look at the blamed commit first instead of the ticket. That gives you the full commit message, which can still contain a reference to an issue.
Putting footer lines like "Fixes: <issue>" into commit messages works much better. It's just as easily visible in git log etc. and doesn't waste space.
>That place used JIRA where the typical ticket ID was around 10 characters. That wasted a lot of prime real estate
Interesting, just for the sake of it, I measured how much screen space the issue ID takes up on my monitor with my current font settings - around 5% (of monitor width, of course). Never been a problem for me.
As for screen space, one of the standard email client layouts has a vertical split, with message titles on the left and bodies on the right. This generally fits well with 16:9 screens, but the line width for titles is limited. Having e.g. the affected component or subsystem up front is much more useful when skimming.
The other stuff about using consistent tense, capitalization, punctuation, etc... is important, but secondary.
> Use the imperative mood in the subject line
The only rationales I've seen for using imperative ("fix bug") over the indicative ("fixed bug") are that it's what git does by default anyways.
Is it really that big of a deal to use the indicative sometimes and imperative other times?
For what it's worth, I always write commit messages in the imperative, out of habit. When others write commit messages in the indicative tense, part of me notices, but I move on because I can still understand the message if it adheres to the other guidelines.
Anyone who gets up in arms over "fixed" vs "fix" needs to get a life.
> Is it really that big of a deal to use the indicative sometimes and imperative other times?
'big', don't know, but wouldn't be surprised if there's an objectively provable higher cognitive load for having to read a mix of both (or, god forbid, other styles thrown in there as well) vs one consistent style. Just like there is for code etc. And some people are affected by striving for consistency more than others, so for them lack of consisteny might cause some extra friction.
So for me, it's not about the commit message itself, but the communication style says something about the developer and how I best approach them.
My take on this requirement is that it helps developers let go of their attachment to the code they've written.
Suppose you're working on software for which patches will not be sent to FOSS mailing lists that are anti-HTML, anti-MIME, anti-long-line, ... why would you wrap the body of commit messages to 72 columns?
Because if the commit is performance related, including regression test results may be mandatory. Test results will be in some fixed format e.g. tabular, commonly exceed 72 columns, and become gibberish if wrapped.
If I have 200 column wide regression test results in a nice tabular format, maybe that's the way it should stay in the commit message.
Example commit on the React repo [1]. It just seems like a lot to type in the command line.
[1] https://github.com/facebook/react/commit/ec52a5698e2dfea7050...
Should be set by default from here: https://github.com/vim/vim/blob/2f0936cb9a2eb026acac03e6a8fd...
Edit: never mind, it's auto wrapped at some number
I guess you could stuff multiple -m in there and git will format it nicely, but the editor is for writing and is best used for that.
I spend my entire workday day in Vim.
This way it's somewhat easier to follow the reasoning of the committed changes.
Another detail is to prefix a subsystem affected, that's in case of modular or complex application. Also help focus the attention.
My preference in general is to write single line messages (shorter ok, longer - ok too), unless it's something very non-trivial and source-code policy discourages lengthy comments.
Lots at our place solely use the GitHub UI to edit Markdown files mainly and their messages are typically the least useful for that reason.
I rarely pay much attention to git commit messages. I would very much rather look at the diffs and see where/what it changed.
>Capitalize the subject line
Does this really matter? Really?
I must admit I don't like that PEP rule. Camel case in some places, no capitals in other places. I just whatever I want really.
It's simple and worked well for us so far. Less rules, more information, and developers are free to use their words to express intention of changes instead of nonsense (feat, fix,....)
Point being, in a few years all your [external references] will be useless. Can your commit messages explain the commit context on their own?
A ticket reference gives you all you need. You see it in every line of code, from there you know the reason for that code to be written, it could include a reference to slack discussion url,...
skip a line
more thorough description if needed. You don't need 7 rules to remember. KISS
PRs matter a lot more than commit messages, especially if you're squashing + merging / rebasing.
I'd rather see a commit saying "fix bug" when bisecting or reading a commit history than ":heart:"
For example, I pulled up one of your projects and the history (https://github.com/transitive-bullshit/kwote/commits/main) is less than meaningless, compared to i.e. using emojis as a shorthand (https://github.com/tiangolo/fastapi/commits/master)
Edit: apparantly HN blocks emojis. Love this feature.
[0] -- https://gitmoji.dev/
You mean the entire developer's thought process behind a change will be represented by a single 12x16 picture? Even hieroglyphs were more expressive than that.
No, look at the log of FastAPI (or even gitmoji itself: https://github.com/carloscuesta/gitmoji) and you'll see that i.e. the bug emoji serves *only* to replace "bugfix: " at the beginning of the commit message, not the entirety.