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