Write good git commit messages
juffalow.com
juffalow.com
The git log is one of the main entry points to an open source (or closed source, in fact) project. Following them tells a story, and can help you understand decisions made.
Imagine you have two projects to bisect. One of them has clean, atomic and descriptive commits. The other has a git log that looks like this: https://github.com/pypa/pipenv/commits/master?after=d4d54eeb...
I know which one I'd want to debug. This is also the primary reason why I highly dislike merge commits: They make git logs extremely unreadable.
The thing is that writing clean commits is something that is extremely easy to do. Unlike docs and tests, it's not more work (it's less, in fact) and it's not something to continuously maintain as the code changes. It's an immediate improvement you can make to your development habits that will have a consequential improvement to your QOL. You will catch bugs doing this!
(Tip when writing atomic commits: Use `git add -p`. That lets you stage patch hunks.)
It was one of the few things left in git where I prefered IDE's over the plain command line.
I am new to git. You will have to merge eventually with somebody when you are collaborating. Can you really avoid merge commits?
I don't like how `git reflog` keeps track of which hash did I switch to. I only jump to hashes for a quick run. I don't want it actually tracking that in the log. Does anybody know how to avoid that as well?
(best used with --ff-only in your config to avoid unnecessary/unintentional merge commits)
> I am new to git. You will have to merge eventually with somebody when you are collaborating. Can you really avoid merge commits?
Many developers prefer to only rebase, such that master looks like a single chain of commits without any branching or other administrative structure.
I really really disagree. If the branch has one logical commit then no merge commit is needed. Otherwise the merge commit shows what happened and more importantly that these N commits came into the mainline as a single change.
You want both that goal and the individual tasks which achieved it to be visible.
I guess we have fundamental differences on how a tree should be structured. It's more of a DAG in your case, but I prefer to keep a tree a tree.
The only point I'm making essentially is that "the commit" is too granular to capture all the information you need about your work and its history. You need some kind of grouping mechanism as well. It doesn't have to be merge commits, necessarily. But as I understood it, your original argument was that "there is no need for anything higher level than a commit." But there clearly is imo.
> It doesn't have to be merge commits, necessarily.
I was thinking of a tagging strategy.
And I'm not cherry-picking... I usually see much, much worse git logs than this from merge-commit users. In fact, if I scroll down, this is what it looks like:
Edit: For a point of comparison, here's one of my projects using atomic commits and rebases:
git log --first-parent
With that switch and writing correct merge-commit messages you get the best of both approaches.
That doesn't mean using merge-commits is wrong, that means people write bad commit messages, which you already complained about.
I fear you may be terribly misunderstanding the point of atomic commits and readable commit messages. Everything within a merge commit will still come up during a bisect, for example. If the commits are non-atomic and/or they are badly written, that is still an issue.
--first-parent hides the problem, and adds a new one. I'm not sure what your thinking is. Once again, what's more readable to you of all the screenshots I linked?
#!/bin/bash
bad=$(git rev-parse "$1")
good=$(git rev-parse "${@:2}")
git bisect start "$bad" $good
filter=$(echo "$good" | sed 's/^/^/' | cat <(echo "$bad") - | xargs)
comm -13 \
<(git rev-list --first-parent $filter | sort) \
<(git rev-list $filter | sort) \
| xargs git bisect skip
I haven't tested it all too thoroughly, but from what `git bisect view` tells me, this seems to work like a `git bisect --first-parent`. I'm wondering why there is no such option...For anyone unfamiliar with git extension scripts: You should be able to put it in an executable (`chmod +x`) file (say `git-bisect-branch`) in your $PATH to make it usable (`git bisect-branch $bad $good...`).
My projects also have a linear progression. They look like...
* -- Bugfix
* -- Feature B
| \
| * -- Implement some other logical part of feature B
| * -- Implement first logical part feature B
| /
* -- Feature AI suspect that if merge-commits hadnt been the default on github since forever, it wouldnt have so many proponents.
Do you have buy in from other team members for this?
Also what do you do if master needs to be merged back into develop? Do you really rebase develop and make everyone fiddle with all their feature branches?
You can see this in action here:
Feature branch is prefixed with issue number. eg. PROJ-1234-update-ui-to-do-something. That ensures that every commit is logged against an issue.
If you list --first-parent and show the list of merge commits, you see a list of features which were implemented into the dev branch.
If you need to drill down into lower level changes of a feature, you can look at the individual commits that were made in that branch.
That way merge commits are atomic commits of features, and commits in a branch are logical commits/steps for an individual feature.
And in answer to the original post - I try to make all commits have a message of what was the type of change, what the change was, and where it was. eg. "Added a clear button to reset all form elements on the update address page". The general rule is, you should be able to read the commit message and know exactly what was changed and where. Compared to "Added clear button".
1) Create a post-commit hook script that only allows commits into feature branches.
This prevents accidentally committing into the dev/master branches (it still allows merges).
2) Create a script file that all developers use to start / end features which handles all the branch creation, pushing and pulling. That way the process is standardised and you cant make a mistake.
eg.
* script startfeature abc123-this-is-new-feature
* script endfeature (this automatically picks up local open features)
The only time there is ever an issue is when the end-feature causes a conflict. This is solved by rebasing your local branch, fixing up any issues in your commmits and then ending it again.
Support from tooling also helps a lot, e.g. "checkout branch of issue XYZ".
Working my current coding job I'm by no means the fastest coder, or the best, but man I get praise for documentation, comments, commit details. It kinda amazes me how many skills that are just straight required in one field, earn heaps of praise in others.
Tip when using patch modes: spend time learning edit mode, and IMO avoid edit mode for checkout or reset patch modes.
What does cause a lot of mental overhead (and consider myself a decent engineer) is creating commits that have a single purpose in the first place.
Working on a new feature I often have to refactor something, and while I am at it, I clean up some related parts. That is at the minimum 3 commits applied in the correct order, sometimes over different branches. At that point there is a lot of `git add -p` and `git stash apply` going on, which takes considerably more mental energy while you see some colleagues getting away with `git commit -a`.
Writing good commit messages itself is the reward for creating good commits.
I agree, this is what demonstrates maturity in an engineer. Perhaps we need to focus on commit driven development.
I personally do not allow teammates to ship macro commits covering multiple features. I call this out in code review process.
This makes sure you can fully test your refractors and that their change sets stand alone.
Reasons include: understanding how a change works (all related code in one place without extra distraction), easy to revert, easy to figure out why that code is there during a blame.
I do partial commits significantly more often than committing everything, and often do things like a couple commits, checkout another branch (and GitKracken does an auto stash + apply) then commit a separate fix there before switching back to the original branch.
Also there are several other things it makes easier: being able to multi-select commits and see a combined diff, quicky diff between two random branches, and just generally browsing back through history. And importantly, it's easy to do all this without having to remember, copy/paste or type any branch names or commit hashes.
With the CLI, all you can do is cycle through "Stage this hunk [y,n,q,a,d,e,?]?" prompts, and if you mess up, you have to exit completely and do `git reset --patch` and cycle through those prompts again (at least, I don't know another way to do that). Actually it's a bit worse because it has even more options:
Unstage this hunk [y,n,q,a,d,j,J,g,/,s,e,?]? ?
y - unstage this hunk
n - do not unstage this hunk
q - quit; do not unstage this hunk or any of the remaining ones
a - unstage this hunk and all later hunks in the file
d - do not unstage this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
If you use this all the time and get used to the commands, and are also good at picturing the separate pieces you are trying to commit in your head, it's probably fully functional.If you're like me, and come back to your code after an unrelated 1hr meeting (or lunch) and are trying to sort out the 3 or 4 separate changes you did earlier in the day to make nice logical commits... good luck.
And you're right: it's completely functional for doing partial commits, but I agree definitely not as pretty.
You can get a hybrid of the two if you use commands like recountdiff (from patchutils) and git-apply --cached. I do this by reading the output of git diff into vim, editing diff hunks and running recountdiff on those hunks, and running git-apply --cached. If I mess up, I can always read the output of git diff --cached and run git-apply -R --cached to unstage that hunk.
I find it better than using the CLI menu driven tool that you refer to.
That's why I typically write code where I implement a feature and then go through the diff to determine what to stage and what goes into each commit. Trying to do this while implementing something isn't really something that's worthwhile.
Also take a look at `git gui`, which is part of Git core.
Even better, use `git commit -p` and skip the staging area entirely.
If you end up staging the wrong hunk, then you will have to reset and recommit. With git add -p, you would only need to reset the hunk.
> you don't have to reset anything
You have to reset the branch pointer to the previous commit, but I think using the --amend switch may do that for you.
That's because, like GitHub itself, the documentation for them is not in the commit messages but in the pull-requests. Look at their PR page (https://github.com/pypa/pipenv/pulls) and individual PRs, you'll see that it's much better organized.
The difference is that now the source of truth is not git itself, but wherever the pull-requests are.
And you think storing that source of truth separately from the code is... a good thing?
Add = Create a capability e.g. feature, test, dependency.
Cut = Remove a capability e.g. feature, test, dependency.
Fix = Fix an issue e.g. bug, typo, accident, misstatement.
Bump = Increase the version of something e.g. dependency.
Make = Change the build process, or tooling, or infra.
Start = Begin doing something; e.g. create a feature flag.
Stop = End doing something; e.g. remove a feature flag.
Refactor = A code change that MUST be just a refactoring.
Reformat = Refactor of formatting, e.g. omit whitespace.
Optimize = Refactor of performance, e.g. speed up code.
Document = Refactor of documentation, e.g. help files.https://github.com/conventional-changelog/conventional-chang...
I often use a customized Commit Lint in combo with Husky to enforce conventional changelog messages:
https://github.com/marionebl/commitlint
https://github.com/typicode/husky
You can also throw in something like the Commitizen cli for newcomers:
I made like 5 diffs in the last week where I just removed old shit that wasn't needed. I felt absurdly happy after each one.
Just once I would like to read someone that takes a descriptivist approach to commit messages instead of a prescriptivist approach. I would prefer even a scientific approach where someone sets out to measure if these sorts of measures have a concrete measurable effect beyond people's anecdotal preferences.
Prescribing what a commit message can look like implicitly prescribes what a commit can look like and that turns a flexible tool into a less flexible one. For many people, lack of flexibility can be a feature... but it is an empirical question on whether or not if it aids development and I am not really aware of anyone trying to measure these things. In the spirit of "No silver bullet," by Fred Brooks, I am skeptical that between the code comments, the code documentation, and the ticketing system that the git commits are adding much.
We already know you changed or added something, it’s a git commit.
You can still use those verbs, but the interesting thing in commit messages is what they do, rather than what changes you made.
A commit message is really like a small note to future contributors; it’s not always easy to write them, but it’s always worth thinking about them from the perspective of someone who is looking at them two or three years hence.
"Note to future contributors" is spot on of course. The best way to write better commit messages is to consume the existing corpus as often as possible, e.g. by never trying to understand code without the blame column active in your editor of choice.
My preferred format is a condensed why-what, consisting of "$verb $ticket $wherein":
$verb would be the developer activity, like fix/optimize/remove/.., and it is mostly there to make it clear that the rest of the message should not describe developer activity.
$ticket would reference your beloved issue tracking system (an additional short keyword describing the issue doesn't hurt as a checksum and to prevent excessive referencing, but it has to be optional because a bad keyword is worse than none).
$wherein would be the customary quick rundown of how the code is supposed to work, expect future readers to only read the beginning.
I like this order because it gives a rudimentary sentence structure to the formulaic parts and positions them at the beginning where they can never be pushed below the fold by the potentially rambly description of the code. Anything more complicated than that will degrade harder when rules are not followed to the letter. Perfect is the enemy of good.
A good rule/guideline for commit messages should not only help us writing perfect messages when we would otherwise write merely good ones, but also scale down to encourage mediocre messages when we completely stopped caring. "rerere ISSUE-123 there is no hope"
Not every commit changes how the code works. Some is just documentation-related, or formatting, or some other configuration change. The list goes on. Your approach would only make sense in a subset of cases.
IMO the message should be what the commit does, not what the code does.
The recommendations are the same, it's longer and provides more rationale at some points.
This is the article I always link people to on my team when explaining how to write commit messages. My company doesn't have a style guide for this exact thing, so this article is what I've been using. And the results are here: https://github.com/google/nomulus/commits/master
It helps me realize not only how to write comments but also when to commit.
Including links to the issues the commit relates to in the body is important.
That said, most of what I've seen in large commit message bodies (like the ones I used to write) really belongs in the patch itself, as changes to the project's formal documentation or source code comments.
If you thought it was worth explaining why you made the change as you did, it likely means the choice was not obvious.
If it wasn't obvious, the explanation belongs in the project proper, where anyone who cares can see it, not tucked away in a commit message that may be hard to discover four or five years down the road.
If it's a decision that impacts UI, the justification belongs in the project specs or docs, where people besides devs can find it (I like to keep my specs and docs as plaintext in the repo and render them to HTML for non-devs to reference).
If it's a strictly internal decision, like what algorithm you chose for a function's internals, you should explain why right there instead of hiding valuable knowledge in the commit message.
A lot of times, code comments may not be updated along with code changes, so they may not be accurate. A commit message is associated with a change at the time it was made.
> not tucked away in a commit message that may be hard to discover four or five years down the road.
The git blame command makes it pretty easy to see what commit introduced a line of code and it also makes it easy to see the context of the change (the rest of the diff).
> If it's a decision that impacts UI, the justification belongs in the project specs or docs, where people besides devs can find it
There's no reason that it can't be recorded in both places.
> If it's a strictly internal decision, like what algorithm you chose for a function's internals, you should explain why right there instead of hiding valuable knowledge in the commit message.
But let's say you want to make a change to the method and you have a comment explaining the change there. Now you make a change to the method and some other part of the code breaks. If you looked at the commit message instead, you can get an explanation and the context of the change (meaning the other parts of the code that relied on the original change you're looking at).
Code review ought to catch comments that haven't been updated.
Further, if a change would have caused the comment to become stale and irrelevant to the project's current state, the commit message would have the same problem. Where you keep it doesn't impact that.
If you want to look at historical states, the comment itself is saved perfectly in the old commit, just like the commit message would be.
> The git blame command makes it pretty easy to see what commit introduced a line of code and it also makes it easy to see the context of the change (the rest of the diff).
I am intimately familiar with `git blame`, and have used it for code archaeology in puzzling codebases over a decade old.
It sure beats having nothing, especially when you configure it to ignore whitespace changes and use Magit's lovely blame interface to move through history quickly, but it can still be a pain to figure out where code really originated from.
If the originating commit gives me a link back to the issue that started it and the code's well documented, I don't need more verbosity.
> There's no reason that it can't be recorded in both places.
There's no reason it can't be recorded in fifty places.
That doesn't make doing so a good idea.
> If you looked at the commit message instead, you can get an explanation and the context of the change (meaning the other parts of the code that relied on the original change you're looking at).
You are describing looking at a commit, not the message. By definition the code changes are not part of the commit message.
At the end of the day, what I described in my comment is something I arrived at after years of writing verbose messages and slowly realizing it wasn't the best way.
You are, of course, free to disagree. Do what works for you.
There are a lot of people who just look at the diff and not the rest of the code when reviewing. If the comment doesn't appear in the context lines, they may not catch it.
> if a change would have caused the comment to become stale and irrelevant to the project's current state, the commit message would have the same problem.
Not really. Unlike a comment that can be seen with the current code base, a commit with an outdated message tends to show up in very few lines (if any) in the git blame output for a particular file. For example, in a code base I deal with, the first commit for a particular file where the message explained the rational and some implementation details now only shows up in git blame output for certain blank lines in the file since most of the file has changed in the years since that commit was made.
> but it can still be a pain to figure out where code really originated from.
You may want to look into the -S and -G parameters of the git log command. They can be used to see when some text was added, removed or moved.
> If the originating commit gives me a link back to the issue that started
Until you encounter the situation where those links are useless because the system they linked to was migrated to a new platform. Had the actual text been there, then it still would have been useful.
> the code's well documented
In my experience, code comments rarely explain why a change was made. But if the associated commit message does contain that explanation, then it makes it much easier to see the context of the change.
> There's no reason it can't be recorded in fifty places. > > That doesn't make doing so a good idea.
That also means you don't have to look in multiple places to find the information you need. The further the documentation is removed from the code, the more likely parts of it will be inaccurate due to changes in the code base, so if you only record documentation in a contract or wiki, then it's very likely that contract/wiki may not be completely accurate.
> You are describing looking at a commit, not the message. By definition the code changes are not part of the commit message.
You can see both by running git show sha1_from_git_blame.
> At the end of the day, what I described in my comment is something I arrived at after years of writing verbose messages and slowly realizing it wasn't the best way.
I've spent years encouraging people to write verbose commit messages for changes they made. I've found them very useful (especially in cases where the person who wrote them no longer works for the company and they're no longer around to ask for further clarification). Whenever I come across a commit message that doesn't explain why a change was made and have to ask the person who made it what they were thinking, I invariably think that it would have been much better if their explanation was in the commit message in the first place.
I'm just saying that huge, multi-paragraph essays are often a sign you're putting information in the wrong place.
I should also add I'm a big believer in small, focused commits - I fairly often will have a branch that has a few hundred lines changed and twenty commits.
You make a good point about the issue tracker dying - I've worried about that but have yet to encounter it in practice. Reducing the impact of such an event is probably a good reason to denormalize a little there.
See Greg Ward at PyCon 2014: "Documenting history, or How to write great commit messages". His talk starts at 6:07. Direct link: https://www.youtube.com/watch?v=Jb6ij4eRu6c#t=367
There’s no length limit.
In fact, write as much as you can. Go crazy. Write some more. Explain. Talk about how your day went. Tell us how you found the problem. Put benchmarks that show why your change makes things faster. Show the stack trace or test output that you’re fixing. Quote other people. Put an email chain in the commit message.
In a well-curated commit history, commit messages become source-level documentation available via an annotate/blame operation. Most people hate writing documentation, but commit messages are about the only time when our tools force us to write something. Take this opportunity to really write something. It’s the only time when writing is really required in any way. There’s no need for a length limit because most of the time the commit messages are hidden away, and most interfaces will hide the full commit message anyway (or can easily be configured to do so).
If you want practice jamming lots of information into a small amount of space, that’s what the first line of the commit message is, but after that, don’t feel constrained by length limits.
These are examples of my favourite kind of commits:
https://www.mercurial-scm.org/repo/hg/rev/4fb2bb61597c?style...
https://www.mercurial-scm.org/repo/hg/rev/ed5b25874d99
https://www.mercurial-scm.org/repo/hg/rev/1423ff45c322
When you're on a codebase where people bother writing commit messages, reaching for blame/annotate output becomes second nature and reveals so much about your code. It's just as good if not better than comments, because every line in your source now has a comment.
BOTH are needed IMHO, comments must be able to communicate knowledge a reader of the code-as-a-whole needs to know, and commit messages must be able to communicate knowledge a reviewer of the change needs to know.
The point of an imperative present tense voice is to consider the message from the point of the commit, not from the point of the committer.
Commit messages aren't meant to show you did work, they aren't meant to show what work you did either. They are meant to show what changed.
Simple present[0] tense.
0: https://learnenglish.britishcouncil.org/en/english-grammar/p...
...OK, now what?
Handle multiple open files
Support multiple open files
Or similar
Some people add tags, emoticons and other stuff. But the real key is consistency. Pick a format and stick with it
The commit message is the headline of your story. Headlines are in present tense even though they describe past events.
Consistency is important, but if you're expending more energy arguing about it than you would deciphering past tense message then you have serious questions to ask yourself. :P
How to write better git commit messages, as a repo README. For example, we use wording Add/Fix/Optimize/Refactor and semantic versioning, etc.
Git commit template: https://github.com/joelparkerhenderson/git_commit_template/b...
You can use a template to improve git commit messages, that prompts for writing "Why" you are making a change, and any co-authors, and any links, etc.
Constructive advice welcome. I'm the author.
https://zulip.readthedocs.io/en/latest/contributing/version-...
I really wish git would have a built-in category system so that I can automatically generate changelog headings (features, tests, etc...) without sacrificing the legibility of commit messages. Git clients could display this information alongside the message (think of how Github displays the short commit hash).
I have never seen it work in a team of 2+. People mix up what each prefix means. Hell, I've seen someone "use" it but only ever use "feat:" even for typo fixes. I ended up rewriting his entire git history to strip all "feat:" instances from the commit message since they were just noise.
Basically the only time I've seen it work is when all the following is true:
- You're on a solo project
- You commit a lot
- You're very consistent with your prefixing
- You want to use those prefixes to generate changelogs.
… then it's useful. Otherwise, it's noise.
That said if you and your friends are happy users of it, I'm glad. I suspect that if you have a small team that knows each other well enough, that is a bit of an extension of a one-person project and it can still remain. I personally have seen the system crumble enough times with even one single user, not to trust it in the hands of two at once.
Well yeah that's exactly this. Tough I've got to admit that it doesn't work that well as we'd like regarding external pull requests since contributors do not all read our commit guidelines.
However, the examples fail by emphasizing what was changed, rather than why it was changed. Sometimes those are the same, and that's ok. But when they're not, why is overwhelmingly more important. What can be seen from looking at the diff.
These days, why is most usefully a PR number, and your workflow automation turns it into a URL you can click. I.e., why did you make a change not motivated by a PR?
Especially for git, because old branches can be cleaned up/deleted which results in a loss of tracking.
If it's long term valuable, i.e. "I considered obvious, attractive alternative algorithm X but it failed horribly because of Y", I'd prefer that to go in a comment in the code instead. Far more likely to still be noticed in three years time, after the code's been run through two different auto-formatters and otherwise mangled around.
https://www.npmjs.com/package/commitizen
Edit: doh, didn't scroll to the bottom!
Somewhat related: @git_commit_m on twitter has some great (and amusing!) examples of what not to use for commit messages, which are pulled from github's public data set.
The Go programming language has very good commit messages
Each of the few times I would mention this requirement on a project people would look at me like I'm a retarded child and keep not using the period.
1) default view is all commits in a MR squashed together
2) messages beyond the title hidden under a click on some micro expand icon
3) going through a MR commit by commit means clicking on an individual commit, waiting for the damn thing to load it's view for 10 seconds, then when you're done you have to go backwards and do it all again
You get the best of both worlds, you end up with a very readable history of commit messages, where each one describes a single feature or unit. But while you're working you don't have to break your flow to write documentation every time you commit, or go back later to rearrange/rebase commits.
E.g.
http://www.kylheku.com/cgit/txr/commit/?id=bfc527af1af619742...
This standard might be useful for library maintainers in the cases stated here: https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-us...
Like having everyone using the same guidelines (code style) when writing code. This might also be useful if everyone use it.
(1) Documentation is important, and comes in a few major forms: docs, code comments, commits, and tests. Docs and code comments are good for initial, high level understanding. Most "bad" documentation appears in the form of code comments and external docs, because they are most likely to drift out of date with the code. Tests do not have this problem (assuming they all pass) because they are in sync with the code, and provide a nice way to understand interfaces and implementations (the "what"). Similarly, commit messages, by their very nature, cannot drift out of date with the code, and provide an opportunity to document the "why". Therefore, commit messages are at least as important as tests, comments, and docs and should be treated with the same respect.
(2) Often the "why" of a particular implementation touches multiple files around the codebase; in many cases you want to document the "why" in comments, but that only helps when it applies to a single section of code. A commit message is an opportunity to document the "why" of an implementation that touches multiple parts of a codebase.
(3) Writing good commit messages forces you to keep the code contents of a commit tightly related to its message, lest the message be inaccurate.
(4) Because good commits are groups of closely related files, you can understand the subtle interactions of a codebase by looking at which files change in the same commit.
(5) A good commit log tells a story and can often provide reasoning behind what may seem like the madness of a legacy codebase. If you don't understand why a file does what it does, just search the history for all commits to that file and you will have a much better idea. There is a cool tool called Gource [0] which visualizes commits to a git repo in a way that can tell such a "story."
Some of the rules I follow:
(A) A short message with an imperative mood documents the "what". A longer body, in list form, documents the "why" and/or the "how." Always include the body unless its a tiny commit with an obvious why/how.
(B) A pull request should follow the same idea as commits, in that it documents the how/why. It should also document the "how" of using any new features it introduces. If possible, it should include screenshots/videos/links of the changes so QA engineers / managers can quickly read it for high level expectations of the next release. Other commenters in this thread have mentioned that pull requests are where the documenting should happen. But good pull requests are just as important as good commit messages; they are not mutually exclusive. A pull request is just a higher level commit.
(C) Before submitting a pull request, use `git rebase -i` against the development/master branch to squash, reorder and fixup commits. For example, sometimes one commit is "solve problem A using method X," but you change your mind in a subsequent commit "actually, solve problem A using method Y". In that case, the two commits should be squashed together if they are in the same pull request. In general, do not be afraid to aggressively reorder and regroup commits in a pull request, if it improves clarity of the pull request as a whole. For this, I like to use a tool called rebase-editor [1] that makes interactive rebasing easy and satisfying.
It makes all commit messages sound like a story where one innovation leads to another.
Look at my latest comment, it's part of the package.
Also what if you move from github to bitbucket? Or self hosted git?
Git provides a great way to keep your changelogs directly next to the code, why not use it?
-> Overview of the latest changes without having to open additional links. Very handy for git bisects for instance.
-> Automatic generation of change logs.
-> It enforces changes that are purposeful and well scoped.
-> Knowledge stays with the Git repo. No data migration issues if you decide not to use GitHub anymore for instance...
-> And finally... it really just looks nice and professional. I would not take a project seriously if the Git log was just an aggregation of WIPs and Oopsies.
Of all the documentation that whatever you are working is lacking; you want to have people writing commit messages.
Seriously; no-one reads this stream of incoherent babble. If you want more documentation start somewhere else, somewhere where your documentation effort actually would be useful.
All IT-projects need more documentation. And all tools should enforce that.
Git should require a readme.md file all repositories and that file should not allowed to be empty.
Java should require javadocs for all methods, fields and classes. Should not compile if missing or empty.
And so on ...
43ec6aa Fix issue 1001
4fe84ab Fix issue 1002
753aa05 Implement feature request 1003
df3a662 Implement spec 1004It takes time and makes you unable to skim-read the commit history.
Also projects are often migrated, offshored etc., and it's not rare for repositories to get uncoupled from the ticket system.
Now "1004" tells me nothing, because I've got the source code and VCS history, but no access to the original Jira where the issue was reported.
43ec6aa Fix error when the URL is not reachable (#1001)
4fe84ab Add error message if something went wrong (#1002)
753aa05 Add server fingerprint check (#1003)
df3a662 Fix shadow box closing problem (#1004)Issue trackers like JIRA can be configured to search for commit-Ids in the messages, which will give you all commits associated with a ticket.
Adding ticket IDs to commits has fallen a bit out of fashion since feature-branches and pull request workflows have become popular. But adding the ticket ID to the commit messages allows for trunk-based development style, while not losing the ability to make a code review over the commits referencing a ticket.
Most of the time I write the ticket ID in the text below, which keeps the `git log --oneline` pretty, the tools can still pick it up.
43ec6aa [1001] Fix error when the URL is not reachable
4fe84ab [1002] Add error message if something went wrong
753aa05 [1003] Add server fingerprint check
df3a662 [1004] Fix shadow box closing problem
That makes the corresponding issue easier to find.43ec6aa Fixed crash when network fails mid transfer (#1001)
(If you apply this commit, it will) fix the button.
`{Jira-1234} ADD flux capacitor control module`
... and put more verbose details in the commit message body if/when needed?
The more verbose details and ticket id should be in the body since I'm more likely to care about them once I've pulled up the commit to review in detail.