I have never understood why people hate merge commits so much. Their advantages are not insignificant: you know when a feature got merged in master, its much easier to revert a feature if you have a merge commit for it, much easier to generate a change log with merge commits, and you have none of the problems that pushing "cleaned up" histories will have: https://www.mail-archive.com/dri-devel@lists.sourceforge.net...
The main disadvantage, as the article rightly points out, is that it makes it much harder to read the history. But that's easily solved with a simple switch: --no-merges. It works with git-log, gitk, tig, and probably others too. Use --no-merges, and get a nice looking linear history without those pesky merge commits.
The problem, at least for me, is not the merge commit. They are indeed easily ignored. The problem is, that I don't want to see a dozen commits fixing typos or trivial bugs.
One trick that can really help with this is `git commit --amend`, which allows you to amend the last commit. If you encounter a bug or a typo in the your last commit, add your fix to the index and then do `git commit --amend`. This will replace your last commit with a new one that contains your latest fix. Of course, this should only be done if you did not push your last commit to remote.
For fixes to earlier commits, I don't bother much, and just live with the trivial commit. Though if I end up making several trivial commits in one setting, I do a cleanup and merge this fixes in one commit before pushing.
slightly OT, but I wonder if anyone has an answer for this.
We use feature branches and rebase before merging to master (mostly for the reason stated above - keep things clean and treating the branch as a single logical unit, not caring about higher-resolution history within the branch).
However, some times, especially since we typically merge on Github from a PR, it's easy to forget to rebase, or notice that there are more commits. So our history is mostly clean, but occasionally contain some "messy" commits.
I know we can reset master, but it feels a bit too risky compared to living with a bit of noise when mistakes happen.
Anyone knows of some way to prevent / alert / notify or otherwise help us avoid this rather common mistake before it happens?
I recommend regularly updating your branch of master via fast-forward. That way if you are working with a slightly different git history, git will complain loudly (refuse to update).
This also has the benefit of complaining if someone else has force pushed (changed history / removed commits) to upstream/master.
I guess it's unclear what you meant by "mess". Some companies think training their devs is worthwhile, especially after losing days/work/$ through git messes. :)
The commits aren't bad as such, just noisy, typically. Github gives you a nice diff of the whole branch against master, so we normally don't pay attention to individual commits. We look at the change as a whole before merging it.
There is an indicator for the number of commits and you can view each one individually, but somehow it's so easy to forget.
Yes, that's one possible solution, but feels like we're punishing ourselves for every merge for the sake of avoiding a reasonably-rare issue. We're reviewing PRs on github, so it's much more convenient to merge them on the spot.
The biggest disadvantage I see isn't in the branching model per se - it's that git itself does not record branch history. By "does not record branch history" I mean that branches are really just pointers to a specific commit in the commit history. However, git doesn't record where that branch pointed to IN THE PAST. So, when looking back in time and you look at a merge commit (say between a feature branch onto development), you can't immediately tell which of the two paths BEFORE that merge commit was originally the feature branch, and which was originally the feature branch. A great example of this is looking at the network view in github, which can turn into a confusing mess because how github decides to color the branch paths is NOT necessarily how those branch paths existed in the past.
If anyone has a solution to this problem please share!
The only solution I can think of is to write a prepare-commit-msg hook that adds a line like "On branch: <branch-name>" to the commit message. So when reading your commit history, every commit that was made on this branch would contain this message. You can also look up just commits made on a particular branch by doing `git log --grep="On branch: <branch-name>"` this way.
At the very least, it may be useful as a starting point.
While I use it extensively on large projects, I find that the merge commit can do just as well. Of course, that doesn't help you outside context of the merge commit---bisecting, for example---unless you are okay with discovering the merge commit that introduced it into the mainline. That can still be scripted.
The convention is to make sure that the stable branch is the left parent, and the feature branch is the right, and that the merge commit log messages are decent (Gitb web UIs do this fairly decently by default). Now you can get a log of left-parent merge commits to see the log of features that shipped (or releases that shipped if you have multiple tiers of stability).
This is exactly what I like about git and don't like about Mercurial: keeping book about which was what does not matter IMO, and complicates (automatic) reasoning (e.g. bisect) about the development process. What does matter is that concurrent development took place, and that's exactly what git's commit DAG represents.
> its much easier to revert a feature if you have a merge commit for it
I like this theory, and generally like merge commits because of it -- but in practice, I've found it still _really really hard_ to revert a feature even if I have a merge commit. Simply reverting the SHA of the merge commit does not, I think, do it, git complains/warns about that. I have to admit I still havent' figured out how to do it reliably even with a merge commit!
The main disadvantage, as the article rightly points out, is that it makes it much harder to read the history. But that's easily solved with a simple switch: --no-merges. It works with git-log, gitk, tig, and probably others too. Use --no-merges, and get a nice looking linear history without those pesky merge commits.