You are viewing gitster

November 26th, 2009


Previous Entry Add to Memories Share Next Entry
12:06 pm - Fun with merges and purposes of branches
When merging branches in git, all branches are taken as equals. This stems from the consistent view towards history git maintains at the philosophical level, and the philosophy, if not the mechanism and implementation, should be applicable to any SCM that supports merges.

This entry is about that philosophy and the implications from it, as it is important to understand what you are doing when you make merges.

First, the philosophy part.
  • A branch has a purpose. The most obvious is a topic branch you use for developing a new feature. A topic branch 'add-frotz' would be about adding a new 'frotz' feature and shouldn't do anything else. In a well organized project, 'master' branch (or 'trunk' if you are coming from subversion) has the sole purpose of containing proven-to-be-good changes to produce the next release. Your per-customer branch is to contain the changes suitable for the next customer code dump and nothing else. It typically consists of bugfixes and selected features the particular customer asked (and paid for).
  • The act of making a commit with one or more parents and advancing the tip of a branch with that commit is to make this statement: I have considered what all of these parent commits represent, and in my belief the state I am committing is more suitable for the purpose of this branch than any of them.
As the consequence of the latter point, 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. This is because...
  • The commit at the tip of 'add-frotz' (one of the parents of the resulting merge) didn't contain any of the other good changes happened on the 'master' branch', so compared to that commit, the resulting merge commit is more suitable for the purpose of the 'master' branch.
  • The commit at the tip of 'master' (the other parent of the resulting merge) didn't contain the new 'frotz' feature, and your wanting to have that feature in the next release makes the resulting merge more suitable for the purpose of the 'master' branch.
If the latter were not true, you wouldn't be merging 'add-frotz' to 'master'.

This is why you do not merge an integration branch 'master' into a topic branch 'add-frotz' at random points. Merging in that direction declares that all the other unrelated changes done on 'master' in preparation for the next release somehow bring 'add-frotz' closer to the goal of the 'frotz' topic, namely, realizing the new 'frotz' feature---that is usually not true.

Similarly, you in general do not merge 'master' into a branch for supporting a particular customer, especially if the purpose of 'master' is to prepare for the next release for the general public, and if the purpose of 'customer' is to support the customer by maintaining the last release with only bugfixes and customer specific features. For the purpose of a typical customer branch, random new features meant for general public that would appear in the next release are not wanted. This is even more true if the purpose of your 'master' branch is to hold any random thing that happened recently in the development community that might be interesting to somebody, which is unfortunately the way 'master' is used in many less well-organized projects.

So instead, a branch meant for a particular customer would typically merge directly from topic branches, to get specific set of bugfixes, and selected new features.

Sometimes it is valid to merge an integration branch like 'master' into a topic branch like 'add-frotz', and it is not inconsistent with the philosophical background I explained above. If you started working on adding a new feature 'frotz' back when the 'master' release was 1.0, and later the codebase of 'master' has substantially changed and your 'add-frotz' branch does not cleanly merge anymore into 'master' that is preparing for 2.0 release, you could choose to change the purpose of your 'add-frotz' branch from "add frotz feature" to a more specific "add frotz feature in a way that it merges cleanly to the 2.0 codedbase". It is valid only because the codebase between 1.0 release made on 'master' and the current one working toward producing 2.0 release has significantly changed, and a generlc "add frotz feature" cannot make sense anymore without saying to which codebase it is adding the feature.

In order for the act of merging 'master' into 'add-frotz' to declare that the resulting merge is more suitable than both the tip of 'master' and 'add-frotz' for the purpose of 'add-frotz' branch, however, the purpose of 'add-frotz' branch has to change from "add frotz (to the version the branch forked from)" to "add frotz to the recent master cleanly".

The implication of this merge is to also make the resulting branch unsuitable for the original purpose of the branch; you cannot merge the 'add-frotz' topic to older 1.0 codebase anymore. It is by choice made by you when you decided to merge 'master' to it.

Of course, you could choose to do something like this to keep two branches with separate purposes when this happens:


$ git checkout add-frotz
$ git branch add-frotz-to-1.0
$ git merge master


You create a new branch 'add-frotz-to-1.0' with the purpose of building the 'frotz' feature on top of the older 1.0 codebase. After that is done, you repurpose 'add-frotz' branch by merging 'master' into it, at which point, the new purpose of the branch becomes adding 'frotz' cleanly to the newer 'master' for 2.0 release.
Tags:

(3 comments | Leave a comment)

Comments:


[User Picture]
From:ahefner
Date:November 27th, 2009 02:25 pm (UTC)

Branch of branch

(Link)
The implication of this merge is to also make the resulting branch unsuitable for the original purpose of the branch; you cannot merge the 'add-frotz' topic to older 1.0 codebase anymore. It is by choice made by you when you decided to merge 'master' to it.

In that case, would it make sense to make a new branch (of the branch) before merging 'master' in to declare this changed intent? Something like 'add-frotz-2.0'.

[User Picture]
From:gitster
Date:November 28th, 2009 06:39 am (UTC)

Re: Branch of branch

(Link)
Yes. You could even do that after making a merge and changing the purpose of add-frotz branch unsuitable anymore for 1.0 codebase, with "git branch add-frotz-to-1.0 add-frotz^".
I've linked tons of people to this post after cringing at seeing the way they manage their branches. The documentation in gitworkflows is good too, but the philosophical justification here is very helpful.
gitster's journal - Fun with merges and purposes of branches

> Recent Entries
> Archive
> Friends
> User Info

Links
Pages at the k.org
Gifts
貢ぎ物
The latest blog by Gitster

> Go to Top
LiveJournal.com