threads / discuss / 3019

RE: git pull on Linux/ACPI release tree

Subject: RE: git pull on Linux/ACPI release tree

## tl;dr

5 messages between Jan 9, 2006 and Jan 12, 2006.

replies: 4people: 4as markdown or json

Brown, Len· Jan 9, 2006, 08:05 UTC · lore

Linus, I think Tony has articulated the work-flow problem that originally started this thread, as well as the fix.

Show 22 quoted lines
>I'll try to update the using-topic-branches document to capture this.
>Some of the problem is that it doesn't quite capture what I'm doing
>with my test/release branches.
>
>My release branch really is just used as a transfer point to Linus.
>I usually[1] don't leave patches sitting in "release" for long enough
>that I'll be tempted to merge in from Linus ... once I decide that
>some patches are ready to go to Linus I'll update "release" from Linus
>(which will be a fast-forward, so no history) merge in the topic
>branches, do one final sanity build, push to kernel.org and send
>the "please pull" e-mail.
>
>The huge majority of my "automatic update from upstream" merges
>go into my test branch ... which never becomes part of the real
>history as I never ask Linus to pull from it.
>
>-Tony
>
>[1] Sometimes I goof on this because I forget that I've applied
>a trivial patch directly to the release branch without going through
>a topic branch.  I think I'll fix my update script to check 
>for this case.

I figured that checking some trivial patches directly into "release" would be a convenient way to make sure I didn't forget to push them -- as they didn't depend on anything else in my tree. Okay.

To make sure that my test branch (where I generate my consolidated plain patch, and what Andrew pulls) includes everything, I then pull "release" into "test". Still good.

But then I decide I need to update my test tree from upstream. I did this by pulling "linus" into "release", and then pulling "release" into "test". This creates the book-keeping merge in "release" that irritates gitk users.

This "flow", BTW, is a habit I picked up from the "two-phase release strategy" that we used in bk days. There I'd pull from upstream down into my to-linus tree and then pull from the to-linus tree into the to-andrew tree. I expect BK also created a merge cset, but apparently nobody was looking at the history like they do with gitk today.

So if I simply don't pull from "linus" into a modified "release" branch then the cluttered history issue goes away. I should fetch "linus" into "release" right before I merge the topic branches into "release" and push upstream. The fetch is a clean fast-forward, and the merges all have real content.

This will work as long as "release" doesn't get too old to be pulled upstream without conflicts. Based on past experience with low latency pulls upstream, I think this will be rare.

Andrew will still get cluttered history in the test tree, but as he's focused on the content and not the (throw-away) history, this is surely a non-issue.

So problem #1 is solved, yes?

Going forward... I'm hopeful that gitk users will not be irritated also by the liberal use of topic branches. I'm starting to like using them quite a bit. Yes, it is true that I could cherry-pick the topics out of their original context to re-manufacture linear history. But that is extra work. Also, as you poined out, there is real value in the real history because the context is accurate. Further, I find that sometimes I need to augment a topic branch with a follow-up patch. I can checkout the topic branch an plop the follow-up right on the tip where it logically should live, and (Tony's) scripts will remind me when the branch is not fully pulled into test or release -- so it will never get misplaced.

In the case where a topic branch is a single commit, gitk users will see both the original commit, as well as the merge commit back into "release".

-Len
Linus Torvalds· Jan 9, 2006, 16:47 UTC · re: Brown, Len · lore
On Mon, 9 Jan 2006, Brown, Len wrote:
Show 15 quoted lines
> >
> >The huge majority of my "automatic update from upstream" merges
> >go into my test branch ... which never becomes part of the real
> >history as I never ask Linus to pull from it.
> >
> >-Tony
> >
> >[1] Sometimes I goof on this because I forget that I've applied
> >a trivial patch directly to the release branch without going through
> >a topic branch.  I think I'll fix my update script to check 
> >for this case.
> 
> I figured that checking some trivial patches directly into "release"
> would be a convenient way to make sure I didn't forget to push them --
> as they didn't depend on anything else in my tree.  Okay.

One thing we could do is to make it easier to apply a patch to a _non_current_ branch.

In other words, let's say that we want to encourage the separation of a "development branch" and a "testing and use" branch (which I'd definitely personally like to encourage people to do).

And one way to do that might be to teach "git-apply" to apply patches to a non-active branch, and then you keep the "testing and use" branch as your _checked_out_ branch (and it's going to be really dirty), but when you actually apply patches you could do that to the "development" branch with something like

	git-apply -b development < patch-file

(Now, of course, that's only if you apply somebody elses patch - if you actually do development _yourself_, you'd either have to check out the development branch and do it there, or you'd move the patch you have in your "ugly" checked-out testing branch into the development branch with

	git diff | git-apply -b development
or something similar..)

Then you could always do "git pull . development" to pull in the development stuff into your working branch - keeping the development branch clean all the time.

Do you think that kind of workflow would be more palatable to you? It shouldn't be /that/ hard to make git-apply branch-aware... (It was part of my original plan, but it is more work than just using the working directory, so I never finished the thought).

> I'm hopeful that gitk users will not be irritated also
> by the liberal use of topic branches.
"gitk" is actually pretty good at showing multiple branches. Try doing a
	gitk --all -d

and you'll see all the topic branches in date order. The "-d" isn't strictly necessary, and to some degree makes the output messier by interleaving the commits from different branches, so you may not want to do it, but it is sometimes nice to see the "relative dates" of individual commits rather than the denser format that gitk defaults to.

> In the case where a topic branch is a single commit, gitk users
> will see both the original commit, as well as the merge commit
> back into "release".

Yes, topic branches will always imply more commits, but I think they are of the "nice" kind.

I definitely encourage people to use git as a distributed concurrent development system ratehr than the "collection of patches" thing. Quilt is much better at the collection of patches.

So I'd encourage topic branches - even within something like ACPI, you might have separate topics ("interpreter" branch vs "x86" branch vs "generic-acpi" branch).

And yes, that will make history sometimes messier too, and it will cause more merges, but the difference there is that the merges will be meaningful (ie merging the "acpi interpreter" branch into the generic ACPI branch suddenly has _meaning_, even if there only ends up being a couple of commits per merge).

Ok?
		Linus
Junio C Hamano· Jan 9, 2006, 20:06 UTC · re: Linus Torvalds · lore

Re: git pull on Linux/ACPI release tree

Linus Torvalds <torvalds@osdl.org> writes:
Show 13 quoted lines
> One thing we could do is to make it easier to apply a patch to a 
> _non_current_ branch.
>...
> And one way to do that might be to teach "git-apply" to apply patches to a 
> non-active branch,...
>
> 	git diff | git-apply -b development
>
> or something similar..)
>
> Then you could always do "git pull . development" to pull in the 
> development stuff into your working branch - keeping the development 
> branch clean all the time.

I had to do something like that last night, when I hacked on gitweb. gitweb as shipped does not work for anybody but kay (e.g. it has /home/kay hardcoded in it). So I did:

	$ git clone git://git.kernel.org/pub/scm/git/gitweb gitweb
        $ cd gitweb
        $ git checkout -b custom
        $ edit gitweb.cgi ;# adjust /home/kay -> somewhere else etc.
        $ git commit -a -m "customization for junio's home"
Then I started preparing a proposed fix for Kay:
	$ git checkout -b symref master
        $ edit gitweb.cgi
        $ git commit -a -s -m "make it work on symref repository"

Now the thing is that I cannot test symref branch as is. I deliberately omitted the change necessary to make the upstream work on my local machine from that branch, because I want to keep my home-machine customization separate from what I will eventually feed Kay. So I do a throwaway test branch:

	$ git checkout -b test master
        $ git pull . custom symref ;# an octopus ;-)
        # I could have done two separate pulls, custom then symref.

The interesting part starts here. Inevitably, I find bugs and bugs and bugs in the test branch, and I fix them in the working tree, without committing. Eventually things starts working. I did not commit here in the test branch, because the symref branch is where I intend to keep this set of changes. So instead, I did this:

	$ git diff HEAD >P.diff
        $ git checkout -f symref
        $ git reset --soft HEAD^
        $ git apply P.diff
        $ git commit -a -C ORIG_HEAD

Usually I strongly discourage people to use "checkout -f" because it will leave files that are in the current branch but not in the new branch behind in the working tree. Here I used "checkout -f symref" because I knew this is a one-file project.

Instead of fixing the symref commit in place like this, I could have committed P.diff as a separate "fixup" commit on top of the symref branch, in which case the above sequence would have been:

	$ git diff HEAD >P.diff
        $ git checkout -f symref
        $ git apply P.diff
        $ git commit -a -m 'fixup bugs in the previous.'

but I did not --- it would have been more disgusting than honest.

And after that, the usual format-patch:
	$ git format-patch origin..symref

In either case, this *was* cumbersome. And I did it twice for two independent topics. Admittedly, these topic branches were both single-commit topics, and in real life your subsystem maintainers must be facing bigger mess than this toy experience of mine, but the principle is the same.

I think there are a couple of ways to improve what I had to do. I'll think aloud here. The fictitious transcripts all start after I got things working in the test branch working tree, with a clean index file (i.e. changes are in the working tree only).

1. Make a commit in the "test" branch, and then cherry-pick the
   commit back to the topic branch:
	$ git commit -a -m "Fix symref fix"
        $ git checkout symref
        $ git cherry-pick -r test
2. Fix "git checkout <branch>" so that it does a reasonable thing
   even when a dirty path is different in current HEAD and
   destination branch.  Then I could:
	$ git checkout symref ;# this would not work in the current git
	    # it would die like this:
            # $ git checkout symref
            # fatal: Entry 'gitweb.cgi' not uptodate. Cannot merge.
	$ git diff ;# just to make sure inevitable automated merge
		    # did the right thing
        $ git commit -a -m "Fix symref fix"
	    # I could collapse them into one instead, like this:
	    # $ git reset --soft HEAD^
	    # $ git commit -a -C ORIG_HEAD

To retest (possibly with latest from Kay), we can rebuild the test branch from scratch since it is by definition a throwaway branch and never is exposed to public:

        $ git fetch origin
	$ git checkout test
        $ git reset --head origin
        $ git pull . custom symref
Obviously I prefer to have #2 work well, but #1 would work today.

I am not sure if making "git-apply" to take different branch is a sane approach. It might make sense to teach git-applymbox and git-am about branches, though. So is teaching git-merge about merging into different branch.

Alex Riesen· Jan 10, 2006, 15:31 UTC · lore

Re: git pull on Linux/ACPI release tree

On 1/9/06, Junio C Hamano <junkio-j9pdmedNgrk@public.gmane.org> wrote:
Show 8 quoted lines
> 2. Fix "git checkout <branch>" so that it does a reasonable thing
>    even when a dirty path is different in current HEAD and
>    destination branch.  Then I could:
>
>         $ git checkout symref ;# this would not work in the current git
>             # it would die like this:
>             # $ git checkout symref
>             # fatal: Entry 'gitweb.cgi' not uptodate. Cannot merge.

That is actually very interesting. I already wished sometimes to be able to switch branches with a dirty working directory (and usually ended up with git diff+checkout+apply). Even if it results in a merge and conflict markers in files it looks like a very practical idea!

Show 6 quoted lines
>         $ git diff ;# just to make sure inevitable automated merge
>                     # did the right thing
>         $ git commit -a -m "Fix symref fix"
>             # I could collapse them into one instead, like this:
>             # $ git reset --soft HEAD^
>             # $ git commit -a -C ORIG_HEAD

- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html

Junio C Hamano· Jan 12, 2006, 07:33 UTC · re: Alex Riesen · lore

[PATCH] checkout: automerge local changes while switching branches.

When switching branches from A to B, if the working tree has a local modification at paths that are different between A and B, we refused the operation saying "cannot merge." This attempts to do an automerge for such paths.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 Alex Riesen <raa.lkml-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
 > On 1/9/06, Junio C Hamano <junkio-j9pdmedNgrk@public.gmane.org> wrote:
 >> 2. Fix "git checkout <branch>" so that it does a reasonable thing
 >>    even when a dirty path is different in current HEAD and
 >>    destination branch.  Then I could:
 >>
 >>         $ git checkout symref ;# this would not work in the current git
 >>             # it would die like this:
 >>             # $ git checkout symref
 >>             # fatal: Entry 'gitweb.cgi' not uptodate. Cannot merge.
 >
 > That is actually very interesting. I already wished sometimes to be
 > able to switch branches with a dirty working directory (and usually
 > ended up with git diff+checkout+apply).
 > Even if it results in a merge and conflict markers in files it looks
 > like a very practical idea!
 This is still experimental and probably has rough edges, but I
 actually tested it once and it worked fine ;-).
 git-checkout.sh |   24 +++++++++++++++++++++++-
 1 files changed, 23 insertions(+), 1 deletions(-)
7929db987a9aac1d0370b64a8a00ffa13e6bab82
diff --git a/git-checkout.sh b/git-checkout.sh
index 3bbd111..1b2db91 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -121,7 +121,29 @@ then
 	git-checkout-index -q -f -u -a
 else
     git-update-index --refresh >/dev/null
-    git-read-tree -m -u $old $new
+    git-read-tree -m -u $old $new || (
+	echo >&2 -n "Try automerge [y/N]? "
+	read yesno
+	case "$yesno" in [yY]*) ;; *) exit 1 ;; esac
+
+	# NEEDSWORK: We may want to reset the index from the $new for
+	# these paths after the automerge happens, but it is not done
+	# yet.  Probably we need to leave unmerged ones alone, and
+	# yank the object name & mode from $new for cleanly merged
+	# paths and stuff them in the index.
+
+	names=`git diff-files --name-only`
+	echo "$names" | git update-index --remove --stdin
+
+	work=`git write-tree` &&
+	git read-tree -m -u $old $work $new || exit
+	if result=`git write-tree 2>/dev/null`
+	then
+	    echo >&2 "Trivially automerged." ;# can this even happen?
+	    exit 0
+	fi
+	git merge-index -o git-merge-one-file -a
+    )
 fi
 
 # 
-- 
1.1.1-g8ecb

← back to recent threads