Junio C Hamano | 59eb68a | 2008-07-21 12:14:42 -0700 | [diff] [blame] | 1 | From: Junio C Hamano <gitster@pobox.com> |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 2 | To: git@vger.kernel.org |
| 3 | Cc: Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org> |
| 4 | Subject: Re: sending changesets from the middle of a git tree |
| 5 | Date: Sun, 14 Aug 2005 18:37:39 -0700 |
Junio C Hamano | f358c10 | 2005-08-26 12:35:51 -0700 | [diff] [blame] | 6 | Abstract: In this article, JC talks about how he rebases the |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 7 | public "seen" branch using the core Git tools when he updates |
Junio C Hamano | f358c10 | 2005-08-26 12:35:51 -0700 | [diff] [blame] | 8 | the "master" branch, and how "rebase" works. Also discussed |
| 9 | is how this applies to individual developers who sends patches |
| 10 | upstream. |
Thomas Ackermann | 1797e5c | 2012-10-16 19:25:29 +0200 | [diff] [blame] | 11 | Content-type: text/asciidoc |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 12 | |
Thomas Ackermann | 1797e5c | 2012-10-16 19:25:29 +0200 | [diff] [blame] | 13 | How to rebase from an internal branch |
| 14 | ===================================== |
| 15 | |
| 16 | -------------------------------------- |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 17 | Petr Baudis <pasky@suse.cz> writes: |
| 18 | |
| 19 | > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter |
| 20 | > where Junio C Hamano <junkio@cox.net> told me that... |
| 21 | >> Linus Torvalds <torvalds@osdl.org> writes: |
Junio C Hamano | a6080a0 | 2007-06-07 00:04:01 -0700 | [diff] [blame] | 22 | >> |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 23 | >> > Junio, maybe you want to talk about how you move patches from your |
| 24 | >> > "seen" branch to the real branches. |
Junio C Hamano | a6080a0 | 2007-06-07 00:04:01 -0700 | [diff] [blame] | 25 | >> |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 26 | > Actually, wouldn't this be also precisely for what StGIT is intended to? |
Thomas Ackermann | 1797e5c | 2012-10-16 19:25:29 +0200 | [diff] [blame] | 27 | -------------------------------------- |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 28 | |
| 29 | Exactly my feeling. I was sort of waiting for Catalin to speak |
| 30 | up. With its basing philosophical ancestry on quilt, this is |
| 31 | the kind of task StGIT is designed to do. |
| 32 | |
| 33 | I just have done a simpler one, this time using only the core |
Thomas Ackermann | 48a8c26 | 2013-01-21 20:16:20 +0100 | [diff] [blame] | 34 | Git tools. |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 35 | |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 36 | I had a handful of commits that were ahead of master in 'seen', and I |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 37 | wanted to add some documentation bypassing my usual habit of |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 38 | placing new things in 'seen' first. At the beginning, the commit |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 39 | ancestry graph looked like this: |
| 40 | |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 41 | *"seen" head |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 42 | master --> #1 --> #2 --> #3 |
| 43 | |
| 44 | So I started from master, made a bunch of edits, and committed: |
| 45 | |
| 46 | $ git checkout master |
Junio C Hamano | e47e35a | 2005-08-26 17:27:07 -0700 | [diff] [blame] | 47 | $ cd Documentation; ed git.txt ... |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 48 | $ cd ..; git add Documentation/*.txt |
Junio C Hamano | 22a06b3 | 2005-11-19 19:21:11 -0800 | [diff] [blame] | 49 | $ git commit -s |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 50 | |
| 51 | After the commit, the ancestry graph would look like this: |
| 52 | |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 53 | *"seen" head |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 54 | master^ --> #1 --> #2 --> #3 |
| 55 | \ |
| 56 | \---> master |
| 57 | |
| 58 | The old master is now master^ (the first parent of the master). |
| 59 | The new master commit holds my documentation updates. |
| 60 | |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 61 | Now I have to deal with "seen" branch. |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 62 | |
| 63 | This is the kind of situation I used to have all the time when |
| 64 | Linus was the maintainer and I was a contributor, when you look |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 65 | at "master" branch being the "maintainer" branch, and "seen" |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 66 | branch being the "contributor" branch. Your work started at the |
| 67 | tip of the "maintainer" branch some time ago, you made a lot of |
| 68 | progress in the meantime, and now the maintainer branch has some |
| 69 | other commits you do not have yet. And "git rebase" was written |
| 70 | with the explicit purpose of helping to maintain branches like |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 71 | "seen". You _could_ merge master to 'seen' and keep going, but if you |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 72 | eventually want to cherrypick and merge some but not necessarily |
| 73 | all changes back to the master branch, it often makes later |
| 74 | operations for _you_ easier if you rebase (i.e. carry forward |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 75 | your changes) "seen" rather than merge. So I ran "git rebase": |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 76 | |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 77 | $ git checkout seen |
| 78 | $ git rebase master seen |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 79 | |
| 80 | What this does is to pick all the commits since the current |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 81 | branch (note that I now am on "seen" branch) forked from the |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 82 | master branch, and forward port these changes. |
| 83 | |
| 84 | master^ --> #1 --> #2 --> #3 |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 85 | \ *"seen" head |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 86 | \---> master --> #1' --> #2' --> #3' |
| 87 | |
| 88 | The diff between master^ and #1 is applied to master and |
| 89 | committed to create #1' commit with the commit information (log, |
| 90 | author and date) taken from commit #1. On top of that #2' and #3' |
| 91 | commits are made similarly out of #2 and #3 commits. |
| 92 | |
| 93 | Old #3 is not recorded in any of the .git/refs/heads/ file |
| 94 | anymore, so after doing this you will have dangling commit if |
Johannes Schindelin | 77dc604 | 2020-06-25 12:18:58 +0000 | [diff] [blame] | 95 | you ran fsck-cache, which is normal. After testing "seen", you |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 96 | can run "git prune" to get rid of those original three commits. |
| 97 | |
| 98 | While I am talking about "git rebase", I should talk about how |
Thomas Ackermann | 48a8c26 | 2013-01-21 20:16:20 +0100 | [diff] [blame] | 99 | to do cherrypicking using only the core Git tools. |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 100 | |
| 101 | Let's go back to the earlier picture, with different labels. |
| 102 | |
| 103 | You, as an individual developer, cloned upstream repository and |
Junio C Hamano | 22a06b3 | 2005-11-19 19:21:11 -0800 | [diff] [blame] | 104 | made a couple of commits on top of it. |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 105 | |
| 106 | *your "master" head |
| 107 | upstream --> #1 --> #2 --> #3 |
| 108 | |
| 109 | You would want changes #2 and #3 incorporated in the upstream, |
| 110 | while you feel that #1 may need further improvements. So you |
| 111 | prepare #2 and #3 for e-mail submission. |
| 112 | |
| 113 | $ git format-patch master^^ master |
| 114 | |
Junio C Hamano | 917a8f8 | 2007-01-17 15:03:39 -0800 | [diff] [blame] | 115 | This creates two files, 0001-XXXX.patch and 0002-XXXX.patch. Send |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 116 | them out "To: " your project maintainer and "Cc: " your mailing |
Junio C Hamano | 215a7ad | 2005-09-07 17:26:23 -0700 | [diff] [blame] | 117 | list. You could use contributed script git-send-email if |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 118 | your host has necessary perl modules for this, but your usual |
| 119 | MUA would do as long as it does not corrupt whitespaces in the |
| 120 | patch. |
| 121 | |
| 122 | Then you would wait, and you find out that the upstream picked |
| 123 | up your changes, along with other changes. |
| 124 | |
| 125 | where *your "master" head |
| 126 | upstream --> #1 --> #2 --> #3 |
Junio C Hamano | a6080a0 | 2007-06-07 00:04:01 -0700 | [diff] [blame] | 127 | used \ |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 128 | to be \--> #A --> #2' --> #3' --> #B --> #C |
| 129 | *upstream head |
| 130 | |
| 131 | The two commits #2' and #3' in the above picture record the same |
| 132 | changes your e-mail submission for #2 and #3 contained, but |
Pavel Roskin | addf88e | 2006-07-09 03:44:30 -0400 | [diff] [blame] | 133 | probably with the new sign-off line added by the upstream |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 134 | maintainer and definitely with different committer and ancestry |
| 135 | information, they are different objects from #2 and #3 commits. |
| 136 | |
| 137 | You fetch from upstream, but not merge. |
| 138 | |
| 139 | $ git fetch upstream |
| 140 | |
| 141 | This leaves the updated upstream head in .git/FETCH_HEAD but |
Justin Lebar | a58088a | 2014-03-31 15:11:44 -0700 | [diff] [blame] | 142 | does not touch your .git/HEAD or .git/refs/heads/master. |
Ryan Anderson | 365a00a | 2005-08-15 04:25:53 -0400 | [diff] [blame] | 143 | You run "git rebase" now. |
| 144 | |
| 145 | $ git rebase FETCH_HEAD master |
| 146 | |
| 147 | Earlier, I said that rebase applies all the commits from your |
| 148 | branch on top of the upstream head. Well, I lied. "git rebase" |
| 149 | is a bit smarter than that and notices that #2 and #3 need not |
| 150 | be applied, so it only applies #1. The commit ancestry graph |
| 151 | becomes something like this: |
| 152 | |
| 153 | where *your old "master" head |
| 154 | upstream --> #1 --> #2 --> #3 |
| 155 | used \ your new "master" head* |
| 156 | to be \--> #A --> #2' --> #3' --> #B --> #C --> #1' |
| 157 | *upstream |
| 158 | head |
| 159 | |
| 160 | Again, "git prune" would discard the disused commits #1-#3 and |
| 161 | you continue on starting from the new "master" head, which is |
| 162 | the #1' commit. |
| 163 | |
| 164 | -jc |