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"