| From: Junio C Hamano <gitster@pobox.com> |
| Subject: Separating topic branches |
| Abstract: In this article, JC describes how to separate topic branches. |
| Content-type: text/asciidoc |
| |
| 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 cruft. 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" |