|  | From:	Junio C Hamano <gitster@pobox.com> | 
|  | To:	git@vger.kernel.org | 
|  | Cc:	Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org> | 
|  | Subject: Re: sending changesets from the middle of a git tree | 
|  | Date:	Sun, 14 Aug 2005 18:37:39 -0700 | 
|  | Abstract: In this article, JC talks about how he rebases the | 
|  | public "pu" branch using the core Git tools when he updates | 
|  | the "master" branch, and how "rebase" works.  Also discussed | 
|  | is how this applies to individual developers who sends patches | 
|  | upstream. | 
|  | Content-type: text/asciidoc | 
|  |  | 
|  | How to rebase from an internal branch | 
|  | ===================================== | 
|  |  | 
|  | -------------------------------------- | 
|  | Petr Baudis <pasky@suse.cz> writes: | 
|  |  | 
|  | > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter | 
|  | > where Junio C Hamano <junkio@cox.net> told me that... | 
|  | >> Linus Torvalds <torvalds@osdl.org> writes: | 
|  | >> | 
|  | >> > Junio, maybe you want to talk about how you move patches from your "pu" | 
|  | >> > branch to the real branches. | 
|  | >> | 
|  | > Actually, wouldn't this be also precisely for what StGIT is intended to? | 
|  | -------------------------------------- | 
|  |  | 
|  | Exactly my feeling.  I was sort of waiting for Catalin to speak | 
|  | up.  With its basing philosophical ancestry on quilt, this is | 
|  | the kind of task StGIT is designed to do. | 
|  |  | 
|  | I just have done a simpler one, this time using only the core | 
|  | Git tools. | 
|  |  | 
|  | I had a handful of commits that were ahead of master in pu, and I | 
|  | wanted to add some documentation bypassing my usual habit of | 
|  | placing new things in pu first.  At the beginning, the commit | 
|  | ancestry graph looked like this: | 
|  |  | 
|  | *"pu" head | 
|  | master --> #1 --> #2 --> #3 | 
|  |  | 
|  | So I started from master, made a bunch of edits, and committed: | 
|  |  | 
|  | $ git checkout master | 
|  | $ cd Documentation; ed git.txt ... | 
|  | $ cd ..; git add Documentation/*.txt | 
|  | $ git commit -s | 
|  |  | 
|  | After the commit, the ancestry graph would look like this: | 
|  |  | 
|  | *"pu" head | 
|  | master^ --> #1 --> #2 --> #3 | 
|  | \ | 
|  | \---> master | 
|  |  | 
|  | The old master is now master^ (the first parent of the master). | 
|  | The new master commit holds my documentation updates. | 
|  |  | 
|  | Now I have to deal with "pu" branch. | 
|  |  | 
|  | This is the kind of situation I used to have all the time when | 
|  | Linus was the maintainer and I was a contributor, when you look | 
|  | at "master" branch being the "maintainer" branch, and "pu" | 
|  | branch being the "contributor" branch.  Your work started at the | 
|  | tip of the "maintainer" branch some time ago, you made a lot of | 
|  | progress in the meantime, and now the maintainer branch has some | 
|  | other commits you do not have yet.  And "git rebase" was written | 
|  | with the explicit purpose of helping to maintain branches like | 
|  | "pu".  You _could_ merge master to pu and keep going, but if you | 
|  | eventually want to cherrypick and merge some but not necessarily | 
|  | all changes back to the master branch, it often makes later | 
|  | operations for _you_ easier if you rebase (i.e. carry forward | 
|  | your changes) "pu" rather than merge.  So I ran "git rebase": | 
|  |  | 
|  | $ git checkout pu | 
|  | $ git rebase master pu | 
|  |  | 
|  | What this does is to pick all the commits since the current | 
|  | branch (note that I now am on "pu" branch) forked from the | 
|  | master branch, and forward port these changes. | 
|  |  | 
|  | master^ --> #1 --> #2 --> #3 | 
|  | \                                  *"pu" head | 
|  | \---> master --> #1' --> #2' --> #3' | 
|  |  | 
|  | The diff between master^ and #1 is applied to master and | 
|  | committed to create #1' commit with the commit information (log, | 
|  | author and date) taken from commit #1.  On top of that #2' and #3' | 
|  | commits are made similarly out of #2 and #3 commits. | 
|  |  | 
|  | Old #3 is not recorded in any of the .git/refs/heads/ file | 
|  | anymore, so after doing this you will have dangling commit if | 
|  | you ran fsck-cache, which is normal.  After testing "pu", you | 
|  | can run "git prune" to get rid of those original three commits. | 
|  |  | 
|  | While I am talking about "git rebase", I should talk about how | 
|  | to do cherrypicking using only the core Git tools. | 
|  |  | 
|  | Let's go back to the earlier picture, with different labels. | 
|  |  | 
|  | You, as an individual developer, cloned upstream repository and | 
|  | made a couple of commits on top of it. | 
|  |  | 
|  | *your "master" head | 
|  | upstream --> #1 --> #2 --> #3 | 
|  |  | 
|  | You would want changes #2 and #3 incorporated in the upstream, | 
|  | while you feel that #1 may need further improvements.  So you | 
|  | prepare #2 and #3 for e-mail submission. | 
|  |  | 
|  | $ git format-patch master^^ master | 
|  |  | 
|  | This creates two files, 0001-XXXX.patch and 0002-XXXX.patch.  Send | 
|  | them out "To: " your project maintainer and "Cc: " your mailing | 
|  | list.  You could use contributed script git-send-email if | 
|  | your host has necessary perl modules for this, but your usual | 
|  | MUA would do as long as it does not corrupt whitespaces in the | 
|  | patch. | 
|  |  | 
|  | Then you would wait, and you find out that the upstream picked | 
|  | up your changes, along with other changes. | 
|  |  | 
|  | where                      *your "master" head | 
|  | upstream --> #1 --> #2 --> #3 | 
|  | used   \ | 
|  | to be     \--> #A --> #2' --> #3' --> #B --> #C | 
|  | *upstream head | 
|  |  | 
|  | The two commits #2' and #3' in the above picture record the same | 
|  | changes your e-mail submission for #2 and #3 contained, but | 
|  | probably with the new sign-off line added by the upstream | 
|  | maintainer and definitely with different committer and ancestry | 
|  | information, they are different objects from #2 and #3 commits. | 
|  |  | 
|  | You fetch from upstream, but not merge. | 
|  |  | 
|  | $ git fetch upstream | 
|  |  | 
|  | This leaves the updated upstream head in .git/FETCH_HEAD but | 
|  | does not touch your .git/HEAD or .git/refs/heads/master. | 
|  | You run "git rebase" now. | 
|  |  | 
|  | $ git rebase FETCH_HEAD master | 
|  |  | 
|  | Earlier, I said that rebase applies all the commits from your | 
|  | branch on top of the upstream head.  Well, I lied.  "git rebase" | 
|  | is a bit smarter than that and notices that #2 and #3 need not | 
|  | be applied, so it only applies #1.  The commit ancestry graph | 
|  | becomes something like this: | 
|  |  | 
|  | where                     *your old "master" head | 
|  | upstream --> #1 --> #2 --> #3 | 
|  | used   \                      your new "master" head* | 
|  | to be     \--> #A --> #2' --> #3' --> #B --> #C --> #1' | 
|  | *upstream | 
|  | head | 
|  |  | 
|  | Again, "git prune" would discard the disused commits #1-#3 and | 
|  | you continue on starting from the new "master" head, which is | 
|  | the #1' commit. | 
|  |  | 
|  | -jc |