Documentation / howto / separating-topic-branches.txton commit New --dirstat=lines mode, doing dirstat analysis based on diffstat (1c57a62)
   1From: Junio C Hamano <gitster@pobox.com>
   2Subject: Separating topic branches
   3Abstract: In this article, JC describes how to separate topic branches.
   4
   5This text was originally a footnote to a discussion about the
   6behaviour of the git diff commands.
   7
   8Often I find myself doing that [running diff against something other
   9than HEAD] while rewriting messy development history.  For example, I
  10start doing some work without knowing exactly where it leads, and end
  11up with a history like this:
  12
  13            "master"
  14        o---o
  15             \                    "topic"
  16              o---o---o---o---o---o
  17
  18At this point, "topic" contains something I know I want, but it
  19contains two concepts that turned out to be completely independent.
  20And often, one topic component is larger than the other.  It may
  21contain more than two topics.
  22
  23In order to rewrite this mess to be more manageable, I would first do
  24"diff master..topic", to extract the changes into a single patch, start
  25picking pieces from it to get logically self-contained units, and
  26start building on top of "master":
  27
  28        $ git diff master..topic >P.diff
  29        $ git checkout -b topicA master
  30        ... pick and apply pieces from P.diff to build
  31        ... commits on topicA branch.
  32
  33              o---o---o
  34             /        "topicA"
  35        o---o"master"
  36             \                    "topic"
  37              o---o---o---o---o---o
  38
  39Before doing each commit on "topicA" HEAD, I run "diff HEAD"
  40before update-index the affected paths, or "diff --cached HEAD"
  41after.  Also I would run "diff --cached master" to make sure
  42that the changes are only the ones related to "topicA".  Usually
  43I do this for smaller topics first.
  44
  45After that, I'd do the remainder of the original "topic", but
  46for that, I do not start from the patchfile I extracted by
  47comparing "master" and "topic" I used initially.  Still on
  48"topicA", I extract "diff topic", and use it to rebuild the
  49other topic:
  50
  51        $ git diff -R topic >P.diff ;# --cached also would work fine
  52        $ git checkout -b topicB master
  53        ... pick and apply pieces from P.diff to build
  54        ... commits on topicB branch.
  55
  56                                "topicB"
  57               o---o---o---o---o
  58              /
  59             /o---o---o
  60            |/        "topicA"
  61        o---o"master"
  62             \                    "topic"
  63              o---o---o---o---o---o
  64
  65After I am done, I'd try a pretend-merge between "topicA" and
  66"topicB" in order to make sure I have not missed anything:
  67
  68        $ git pull . topicA ;# merge it into current "topicB"
  69        $ git diff topic
  70                                "topicB"
  71               o---o---o---o---o---* (pretend merge)
  72              /                   /
  73             /o---o---o----------'
  74            |/        "topicA"
  75        o---o"master"
  76             \                    "topic"
  77              o---o---o---o---o---o
  78
  79The last diff better not to show anything other than cleanups
  80for crufts.  Then I can finally clean things up:
  81
  82        $ git branch -D topic
  83        $ git reset --hard HEAD^ ;# nuke pretend merge
  84
  85                                "topicB"
  86               o---o---o---o---o
  87              /
  88             /o---o---o
  89            |/        "topicA"
  90        o---o"master"