git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: sending changesets from the middle of a git tree

From
Junio C Hamano <junkio@cox.net>
Date
Aug 15, 2005, 01:37 UTC
Message-ID
<7vfytc9dzw.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<20050814092757.GP5608@pasky.ji.cz>
Petr Baudis <pasky@suse.cz> writes:
Show 8 quoted lines
> 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 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 git-apply-patch-script.txt ...
    $ cd ..; git add Documentation/*.txt
    $ git commit -s -v

NOTE. The -v flag to commit is a handy way to make sure that your additions are not introducing bogusly formatted lines.

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 amde 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.txt and 0002-XXXX.txt. Send them out "To: " your project maintainer and "Cc: " your mailing list. You could use contributed script git-send-email-script 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 upsteam 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 nor .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
Previous: Petr BaudisNext: Catalin Marinas
Message 8 of 12 in “sending changesets from the middle of a git tree”
  1. Steve FrenchAug 14, 2005
  2. Ryan AndersonAug 14, 2005
  3. Ryan AndersonAug 15, 2005
  4. Linus TorvaldsAug 14, 2005
  5. Linus TorvaldsAug 14, 2005
  6. Junio C HamanoAug 14, 2005
  7. Petr BaudisAug 14, 2005
  8. Junio C HamanoAug 15, 2005
  9. Catalin MarinasAug 15, 2005
  10. Wolfgang DenkAug 17, 2005
  11. Junio C HamanoAug 17, 2005
  12. Catalin MarinasAug 15, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.