You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
6.2 KiB
164 lines
6.2 KiB
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 "seen" 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 |
|
>> > "seen" 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 'seen', and I |
|
wanted to add some documentation bypassing my usual habit of |
|
placing new things in 'seen' first. At the beginning, the commit |
|
ancestry graph looked like this: |
|
|
|
*"seen" 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: |
|
|
|
*"seen" 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 "seen" 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 "seen" |
|
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 |
|
"seen". You _could_ merge master to 'seen' 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) "seen" rather than merge. So I ran "git rebase": |
|
|
|
$ git checkout seen |
|
$ git rebase master seen |
|
|
|
What this does is to pick all the commits since the current |
|
branch (note that I now am on "seen" branch) forked from the |
|
master branch, and forward port these changes. |
|
|
|
master^ --> #1 --> #2 --> #3 |
|
\ *"seen" 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 "seen", 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
|
|
|