gitster (Junio C Hamano) (gitster) wrote,
gitster (Junio C Hamano)

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: git

  • For the last time...

    I was asked by a few people where my blog moved to, so here it is.

  • Sorry, LiveJournal, git bye and thanks for all the spam

    I've been blogging elsewhere without announcing where it is to the public. The primary reason I left here is because the pages seem to get too…

  • Git 1.7.5

    The cycle took a bit longer than I would have liked (83 days), but finally I tagged the latest release v1.7.5 with 547 changes from 77…

  • Post a new comment


    Comments allowed for friends only

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded