One Thing that Git Does Better: Rebranching

2013-05-04 0:06

Much can be said about similarities between two popular, distributed version control systems: Git and Mercurial. For the most part, choosing between them can be a matter of taste. And because Git seems to have considerably more proponents in the Cool Kids camp, it doesn’t necessarily follow it’s a better option.

But I have found at least one specific and common scenario where Git clearly outshines Hg. Suppose you have coded yourself into a dead end: the feature you planned doesn’t pan out the way you wanted it; or you have some compatibility issues you cannot easily resolve; or you just need to escape the refactoring bathtub.

Rebranching in Git (start)

In any case, you just want to step back a few commits and pretend nothing happened, for now. The mishap might be useful later, though, so it’d be nice if we left it marked for the future.

In Git, this is easily done. You would start by creating a new branch that points to your dead end:

  1. $ git checkout my_feature
  2. $ git branch __my_feature__dead_end__

Afterwards, both my_feature and __my_feature__dead_end__ refer to the same, head commit. We would then move the former a little back, sticking it to one of the earlier hashes. Let’s find a suitable target:

  1. $ git log
  2. commit 130fe41a3a0587a48c1ef8797030ae2e682c6fb4
  3. Author: John Doe <john.doe@example.com>
  4. Date:   Fri May 3 21:39:32 2013 +0200
  5.  
  6.     I don't like this adventure. Not one bit.
  7.  
  8. commit f834a10d199f5c23fa14ed0ebfcf89226d9c21a1
  9. Author: John Doe <john.doe@example.com>
  10. Date:   Fri May 3 21:25:46 2013 +0200
  11.  
  12.     Let's try this, maybe...
  13.  
  14. commit 9d877d32f3a08f416615f9a051ad3985e6e4d2ad
  15. Author: John Doe <john.doe@example.com>
  16. Date:   Fri May 3 21:18:57 2013 +0200
  17.  
  18.     Shiny!
  19. $ git checkout 9d877
  20. Note: checking out '9d877'.
  21. # trimmed for brevity

If it looks right, we can reset the my_feature branch so it points to this specific commit:

  1. $ git reset --hard 9d877

Our final situation would then looks like this:

Rebranching in Git (end)

which is exactly what we wanted. Note how any further commits starting from the referent of my_feature would fork at that point, diverging from development line which has lead us into dead end.

Why the same thing is not so easily done in Mercurial?… In general, this is mostly because of its one fundamental design decision: every commit belongs to one branch, forever and for always. Branch designation is actually part of the changeset’s metadata, just like the commit message or diff. Moving things around – like we did above – is therefore equivalent to changing history and requires tools that are capable of doing so, such as hg strip.

Tags: , , ,
Author: Xion, posted under Programming »


5 comments for post “One Thing that Git Does Better: Rebranching”.
  1. Kos:
    May 4th, 2013 o 10:17

    There seems to be a nice debate on which model is actually better; some feel that Git branches aren’t very descriptive compared to Hg after you merge stuff. There’s this:
    http://jhw.dreamwidth.org/1868.html
    Yet, others still insist that yes, they still are:
    http://felipec.wordpress.com/2012/05/26/no-mercurial-branches-are-still-not-better-than-git-ones-response-to-jhws-more-on-mercurial-vs-git-with-graphs/

  2. Xion:
    May 4th, 2013 o 23:30

    It is a bit of a philosophical issue: on one hand it’s about what do you exactly mean by “branch”, and on the other is how much do you really care about preserving history of everything.

    I don’t really know what you mean “descriptive after merge”. Branch pointer still stays where it was before, and commit history is preserved prior to it, so…

  3. higrys:
    May 5th, 2013 o 13:42

    Good read and valid point indeed. when it comes to philosophy…
    I used to be a big proponent of mercurial’s way of branches. My argument was “then I can easily find out what was the history of the branch, how it came into being and generally tons of useful info”. But after learning about git squashing and the way how branches/tags and especially rebases work in git + after rigorously using code review workflows and “branch per feature” I changed my mind.
    If you really follow branch-per-feature + rebase + squash to one commit before final rebase, then git branches show it’s real power. After merge, you DON’T care any more what was the history of feature. You care about what changes are in the feature + you have the history of code reviews done for this feature (comments there are often important and good to refer to). This way you can see “big picture” in commits and dive into nitty-gritty details in reviews, but only if you really want. You can easily remove feature by reversing single commit.

    What is really missing in both git and mercurial is lack of semantical knowledge about the language + ability to follow refactoring. That’s why PlasticSCM (http://www.plasticscm.com/) is a very interesting subject to follow. One thing that breaks the whole flow of “branch-per-feature” approach is exactly this. I will have to finally start my blog (I think about it for ages) and I believe this subject will be one of the first to cover :).

  4. Xion:
    May 5th, 2013 o 22:57

    @up: Thanks for the points on rebasing & squashing. It really sounds like a good workflow.

    And about PlasticSCM, I see it’s from the same folks that do http://www.semanticmerge.com/. I’ll be interesting when they start supporting more languages… and especially how they’ll tackle dynamic ones :)

  5. goodAdviceUncle:
    May 10th, 2013 o 15:39

    Why does ‘Cool Kids camp’ leads to github.com ?

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.