Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git workflow: throwaway merges and git-rerere - what's the point?

Like most people new to Git, I've had my share of confusion trying to decipher the use cases applicable to git merge and git rebase. I think I've finally decided that, as far as the resulting working copy state, they give you the same thing. Also, they both result in the same conflicts. If this is incorrect, please provide an example to enlighten me.

From my point of view, the main benefit to using rebase instead of merge (if your changes haven't been pushed or pulled) is to keep the history linear. What I really don't understand is the reasoning behind developing git-rerere.

From the manpages, git-rerere is supposed to help you in the case where you're trying to resolve a conflict that you've previously resolved. The example that I'm about to refer to is found at http://www.kernel.org/pub/software/scm/git/docs/git-rerere.html.

If the policy of your project is to not constantly merge changes from the mainline into your topic branch (like the linux kernel), the above example says to create "throw-away" merge commits. Essentially, merge the master into your topic, run tests to make sure everything still works, then do a "git reset --hard HEAD^", essentially throwing the merge commit away. Later on, when you create another "throw-away" merge commit, git-rerere assists you in resolving the conflicts that you've already solved in the frst throw-away merge.

Can someone please explain why instead of going through all the trouble of creating a temporary merge commit, the developer wouldn't instead just rebase his topic onto master? Isn't that the point of git-rebase - get the changes, but avoid the merge? Doesn't this accomplish the same thing, and assuming no one has pulled your topic branch changes, wouldn't this be a much simpler approach? Is the throw-away-merge+git-rerere workflow really just for the case when your changes have been pushed/pulled?

One final question - Linus is quoted as saying "But if I see a lot of 'Merge branch linus' in your logs, I'm not going to pull from you, because your tree has obviously had random crap in it that shouldn't be there..." Would Linus also have a problem with constant rebases?

like image 241
Josh Avatar asked Jun 18 '10 18:06

Josh


People also ask

What is the purpose of merging in git?

Merging is Git's way of putting a forked history back together again. The git merge command lets you take the independent lines of development created by git branch and integrate them into a single branch.

What is Rerere in git?

The git rerere functionality is a bit of a hidden feature. The name stands for “reuse recorded resolution” and, as the name implies, it allows you to ask Git to remember how you've resolved a hunk conflict so that the next time it sees the same conflict, Git can resolve it for you automatically.

Why do merge commits happen?

This usually happens when we're collaborating on a branch with other people, and we've made changes on our local version of a branch, and someone else (or the other you, if you use git to sync between multiple dev platforms) has made changes to the remote version of a branch in the meantime.

What is rebase preserving merge commits?

As with a normal git rebase, git with --preserve-merges first identifies a list of commits made in one part of the commit graph, and then replays those commits on top of another part. The differences with --preserve-merges concern which commits are selected for replay and how that replaying works for merge commits.


1 Answers

You're correct that rebasing and merging can produce the same final tree. The history they produce is very different, though, and version control is of course all about history. You've voiced a preference for linear history; that's indeed desirable on a local scale, while merges help to record the larger scale interaction of features, bugfixes, and so on.

The simple answer to your central question (why not just rebase) is that sometimes there's a right place for a branch to start, and if that's the case, you should merge, not rebase.

For example, you could have a bugfix which applies to a maintenance release as well as the current release; you'd want to branch it from the latest commit which is an ancestor of both releases. You can't ever rebase that branch forward along either the master or the maintenance branch, or you'd no longer be able to merge it into the other.

Similarly, all topic branches start somewhere. At some point, you want to preserve that history. You mention one of the clear-cut cases (others have pulled your work), but it could be something far less obvious. Maybe there's some interaction with other features, maybe this feature has subfeatures, and you're trying to keep that entire hierarchy preserved.

So, sure, if the branch is local and there are no reasons to keep its base fixed, it is as you say much simpler to just rebase it and be done. But sometimes that's not the right thing to do.

Your final question is actually about something very different, nothing to do with merge conflicts. Linus said that in the context of merges which didn't need to be done. This is very much an issue of branch and merge philosophy. Junio Hamano wrote an excellent blog post about that very issue. A brief quote which sums up the topic at hand:

when you merge a topic branch 'add-frotz' to your 'master' branch, you are obviously incorporating the new 'frotz' feature, but more importantly, you are stating that it is desirable to have that 'frotz' feature in the 'master' branch

Linus doesn't want to see you merging this odd branch called 'linus' all the time, because clearly you're not merging some specific topic which is desirable to have in your branch. You're repeatedly merging the upstream branch into the topic branch, which is entirely the wrong direction. You don't need all the stuff from master (or linus) to develop your topic. You should finish your topic, then merge it the other way, upstream into master! It's not desirable to have all of the content of master in your topic branch. (And a single developer's master is really a topic branch, as far as an integrator's concerned.)

So, Linus doesn't have a problem with frequent merges; he has a problem with purposeless and counterproductive merges. (And generally, if you make sure your merges are done for a good reason, they won't be frequent - and they'll almost never be downstream merges.) If your rebases are done for a good reason, and they make the history better, then they are a good thing, however frequent.

like image 174
Cascabel Avatar answered Oct 23 '22 11:10

Cascabel