Separate of topic branch

From: Junio C Hamano <gitster@pobox.com>
Subject: Separating topic branches
Abstract: In this article, JC describes how to separate topic branches.

This text was originally a footnote to a discussion about the
behaviour of the git diff commands.

Often I find myself doing that [running diff against something other
than HEAD] while rewriting messy development history.  For example, I
start doing some work without knowing exactly where it leads, and end
up with a history like this:

            “master”
        o—o
             \                    “topic”
              o—o—o—o—o—o

At this point, “topic” contains something I know I want, but it
contains two concepts that turned out to be completely independent.
And often, one topic component is larger than the other.  It may
contain more than two topics.

In order to rewrite this mess to be more manageable, I would first do
“diff master..topic”, to extract the changes into a single patch, start
picking pieces from it to get logically self-contained units, and
start building on top of “master”:

        $ git diff master..topic >P.diff
        $ git checkout -b topicA master
        … pick and apply pieces from P.diff to build
        … commits on topicA branch.

              o—o—o
             /        “topicA”
        o—o”master”
             \                    “topic”
              o—o—o—o—o—o

Before doing each commit on “topicA” HEAD, I run “diff HEAD”
before update-index the affected paths, or “diff –cached HEAD”
after.  Also I would run “diff –cached master” to make sure
that the changes are only the ones related to “topicA”.  Usually
I do this for smaller topics first.

After that, I’d do the remainder of the original “topic”, but
for that, I do not start from the patchfile I extracted by
comparing “master” and “topic” I used initially.  Still on
“topicA”, I extract “diff topic”, and use it to rebuild the
other topic:

        $ git diff -R topic >P.diff ;# –cached also would work fine
        $ git checkout -b topicB master
        … pick and apply pieces from P.diff to build
        … commits on topicB branch.

                                “topicB”
               o—o—o—o—o
              /
             /o—o—o
            |/        “topicA”
        o—o”master”
             \                    “topic”
              o—o—o—o—o—o

After I am done, I’d try a pretend-merge between “topicA” and
“topicB” in order to make sure I have not missed anything:

        $ git pull . topicA ;# merge it into current “topicB”
        $ git diff topic
                                “topicB”
               o—o—o—o—o—* (pretend merge)
              /                   /
             /o—o—o———-‘
            |/        “topicA”
        o—o”master”
             \                    “topic”
              o—o—o—o—o—o

The last diff better not to show anything other than cleanups
for crufts.  Then I can finally clean things up:

        $ git branch -D topic
        $ git reset –hard HEAD^ ;# nuke pretend merge

                                “topicB”
               o—o—o—o—o
              /
             /o—o—o
            |/        “topicA”
        o—o”master”

By Lu Jun

80后男,就职于软件行业。习于F*** GFW。人生48%时间陪同电子设备和互联网,美剧迷,高清视频狂热者,游戏菜鸟,长期谷粉,临时果粉,略知摄影。

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.