94 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			94 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
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 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"
 |