threads / discuss / 1913

Re: Please undo "Use git-merge instead of git-resolve in

Subject: Re: Please undo "Use git-merge instead of git-resolve in

## tl;dr

3 messages between Sep 22, 2005 and Sep 22, 2005.

replies: 2people: 3as markdown or json

Jon Loeliger· Sep 22, 2005, 14:55 UTC · lore
Dave Wrote:
Show 10 quoted lines
> From: Linus Torvalds <torvalds@osdl.org>
> 
> > I often have local changes in my tree that I don't want to commit but that 
> > I'm testing out. Havign them interfere with merging other peoples work 
> > would mean that I'd have to have a totally separate tree for that, which I 
> > could do, but I'm much much happier not having to.
> 
> You know, I personally was unaware that this was supported until now.
> I have been always reverting local debugging changes in order to merge
> other people's work in, then reapply the debugging changes afterwards.

So, interesting that this comes up now, as I recently had a discussion on this topic with a few coworkers. We concluded that we were clueless and what would help us out a whole bunch would be a few more Use Cases down this line added to the Tutorial.

I'll include my original (internal) question as an example use case. Perhaps it will illustrate two things:

    - How clueless I am about Git still
    - Where some of the Git Frustration still lies

I'd offer to write it, but I'm just flat in the dark here and need to _read_ it first. :-) I'll offer this instead: If you (someone) tells me the commands that illustrate how to do what I'm after here, I'll make a stab at writing up the tutorial Use Case for it.

(Yes, I know there is a Use Case very similar to this in the Tutorial, but it is not quite the same. And I can't see how to intuit a step towards what I'm wanting here.)

Thanks, jdl

    OK, so I have a git tree that looks like this:
    241 % git show-branch --more=5
    * [jdl] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
     ! [master] Merge branch 'master' of /home/src/linux-2.6/
      ! [origin] Merge branch 'master' of /home/src/linux-2.6/
       ! [paul] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
    ----
    +  + [jdl] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
    ++++ [master] Merge branch 'master' of /home/src/linux-2.6/
    ++++ [master~1] NTFS: Fix ntfs_{read,write}page() to cope with concurrent truncates better.
    ++++ [master~2] NTFS: Fix handling of compressed directories that I broke in earlier changeset.
    ++++ [master~3] NTFS: Fix various bugs in the runlist merging code.  (Based on libntfs
    ++++ [master~4] vc: Use correct size on buffer copy in vc_resize
    +  + [jdl~1] Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge
    +  + [jdl^2] ppc32: Allow user to individual select CHRP/PMAC/PREP config
    +  + [jdl^2~1] powerpc: Merge simplified sections.h into asm-powerpc
    +  + [jdl^2~2] powerpc: Remove section free() and linker script bits
    +  + [jdl^2~3] powerpc: Remove sections use from ppc64 and drivers
    +  + [jdl^2~4] powerpc: Remove sections use from ppc
    +  + [jdl^2~5] ppc32: Removed non-inlined versions of local_irq* functions
    ++++ [jdl~2] Merge master.kernel.org:/home/rmk/linux-2.6-arm
    I have current, modified, non-committed files in my working tree
    in the "jdl" branch.  I don't want to commit them now (yet).
    I now know that Linus has updated his tree with new -rc2 parts.
    I want it.  In fact, I want it on the "origin" or "master" branch.
    (Or both.  And I don't know which.)
    How do I get Linus' updates and merge them into the "origin" branch
    without changing to that branch first?
    How do I get Paul's updates and merge them into the "paul" branch
    without changing to that branch first?
    I think I can fetch the Linus updates by doing something like this:
	git fetch origin
    or
	git fetch rsync://....path/to/linus-2.6-git
    That will just grab the Objects and throw them into my .git/objects.
    But how to do the merge?  I think that the merges all require
    the "target branch" to be the "active"/checkedout branch, right?
    I don't know how to now say "Merge-up those new Objects on the
    origin branch".
    I think what's confusing me still is that the previous
    World View According to CVS was essentially that you have
    this import branch into which you dragged all the external
    updates.  Then you merged that over to your working branch.
    And, you could easily have views of _both_ of those
    branches simultaneously.
    With Git, you can't really do that in quite the same way.
    Sure, you can treat a branch as an "import branch".  But
    if you have uncommitted files over in a different branch,
    you can't change your cehckout-view to do so.
    However, I _could_ just stick in my "jdl" working branch and
    directly pull-in and merge the linus changes.  I mean, my next
    step after pulling those changes into the so-called import
    branch was going to be to merge them to my branch anyway.
    OK, so let's say I did pull linus' update into the jdl branch.
    And they merge up nicely.  How do I now propogate _just_ the
    linus changes to the origin branch?  Again, I don't think I
    can without first checking out the "origin" branch.
    Am I missing something here?  Fighting against the tool?
A coworker replied:
    > I read your message, and I read the git documentation, and I
    > scratched my head a bit, and the end result is that I still don't
    > know.  The docs really suck.  Everything you say seems to make
    > sense, but I just can't confirm that it's actually how things
    > work.  And I don't know how to do a merge like you propose.
I responded:
    So, you will all be pleased to know that I tried
    some stuff and was not successful.  In the "jdl"
    branch, I did a "git pull linus".  It happily went
    out and grabbed all the new objects from his tree.
    Spiffy.  It then announced that my branch of the
    working tree was "dirty" and quit.
    At this point, I _think_ this is where a "cg-pull"
    instead of a "git pull" would have gone on, done
    some figuring, and decided that it needed to
    rebase my current changes after merging in the
    fetched objects.
    Not sure.
Petr Baudis· Sep 22, 2005, 16:01 UTC · re: Jon Loeliger · lore

Dear diary, on Thu, Sep 22, 2005 at 04:55:26PM CEST, I got a letter where Jon Loeliger <jdl@freescale.com> told me that...

Show 19 quoted lines
>     I now know that Linus has updated his tree with new -rc2 parts.
>     I want it.  In fact, I want it on the "origin" or "master" branch.
>     (Or both.  And I don't know which.)
> 
>     How do I get Linus' updates and merge them into the "origin" branch
>     without changing to that branch first?
> 
>     I think I can fetch the Linus updates by doing something like this:
> 
> 	git fetch origin
>     or
> 	git fetch rsync://....path/to/linus-2.6-git
> 
>     That will just grab the Objects and throw them into my .git/objects.
> 
>     But how to do the merge?  I think that the merges all require
>     the "target branch" to be the "active"/checkedout branch, right?
>     I don't know how to now say "Merge-up those new Objects on the
>     origin branch".

[I say 'master', but I mean the whatever branch you are currently working on.]

Your origin branch just represents what Linus has in his master branch. You don't ever merge anything to it - if you fetch new stuff from Linus, it simply gets updated to point at the newest Linus' stuff. You can then merge your 'origin' branch to your 'master' branch, therefore getting the newest Linus' stuff there.

About two nights ago I tried to describe all this branching stuff in Cogito's README. It is aimed at Cogito, but generally appliable to GIT as well. s/cg-/git-/, cg-update is git-pull, and instead of using cg-branch-* you edit stuff in .git/remotes. It'd be interesting to know how much more light it manages to shed on the issue, and generally what do people think about it:

Understanding GIT branching and merging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Cogito's (inherited from GIT) concept of branching and merging may be a little confusing at first, since it can be different from what you knew so far. First, "branch" is too abstract word for us, so we will abandon it for now. We will present two other key concepts instead:

	- Repository - when you did `cg-clone` or `cg-init`, you created
	  a repository. That is a kind of container holding (usually) all your
	  history and data.
	- Head - each repository has some heads available. Those are kind of
	  handles for various sequences of commit. A head contains simply a
	  pointer to the last commit in the sequence, and if you commit 'onto'
	  a head, the pointer will be advanced to the new commit. Your
	  "current" head is the one you are currently working on. It is
	  normally called 'master'.
Now let's take an hypothetical repository:
	repository
	+--------+
	|  master<  heads
	|   unoji<
	+--------+

Let's suppose that we want to fork off master's development. We have two possibilities, either make new repository for it, or a new head.

Let's say that we want to fork it off for our work offline on a notebook, so we will make it through cloning the repository to our notebook. What will `cg-clone` do?

	+--------+
	+--------+
First it creates an empty repository
	+--------+
	$  origin<
	+--------+
Then it creates an 'origin' head, and will copy all the history from the
remote repository's 'master' head there. So this head exists to reflect
the state of the remote repository. The important point is that it is
called 'origin' in our new repository, even through it corresponds to
a 'master' head in the old repository. This is normal - you can name your
local heads whatever you want.
The dollar sign denotes that this head is associated with a "remote branch"
- a source location of the head is saved somewhere and you can fetch the
head and possibly push to it.
	+--------+
	|  master<
	$  origin<
	+--------+
Finally it copied over the 'origin' head to the 'master' head, which will
from now as your current head represent your local development in the
repository.

So you do some local development, do few commits on the 'master' head and want to catch up with the upstream repository. You use 'cg-update', but what will it do?

	+--------+
	|  master<
	$  origin< < < < <
	+--------+
First, it will populate your 'origin' head with the new commits from the
remote's 'master' head.
	+--------+
	|  master<-M-.
	$  origin>---'
	+--------+
Then, it will merge those new commits to your 'master' head.

Now let's imagine that there is also another head 'unoji' on the other side besides 'master', containing some cool commits not in 'master' (it has such an exotic name, after all...). You want to merge its commits to your head too?

	$ cg-branch-add r-unoji 'http://remote/repository#unoji'
	$ cg-fetch r-unoji
will make your repository look like
	+--------+
	|  master<
	$  origin<
	$ r-unoji<
	+--------+
with 'r-unoji' containing stuff from the remote's 'unoji' branch.

Ok, you did some development, but you decided not to merge it into upstream's 'master' yet since it is not yet stable enough. However, you want to upload it into the upstream repository since it is public and you want people to be able to try out your stuff. Easy, let's push it to a new head on the server.

	$ cg-branch-add upmirror 'git+ssh://remote/repository#nislu'
will make your repository look like:
	+--------+
	|  master<
	$  origin<
	$ r-unoji<
	$upmirror|
	+--------+

Note that 'upmirror' has no head associated, it has just the "remote branch" info. That is because it needs no head since it's solely for pushing. It is however normal to have a head (frequently it's the 'origin') both for pulling and pushing.

	$ cg-push upmirror
will then make the remote repository look like:
	+--------+
	|  master<
	|   unoji<
	|   nislu<
	+--------+

with 'nislu' on the remote side corresponding to the 'master' in your local repository.

Ok, so this is how it goes for multiple repositories, where the cloned repositories are essentially single branches. Note that if you clone the repository locally, it can be actually very cheap, basically for free with `cg-clone -l` (but please read its documentation).

But what if you still do not want multiple repositories? The key here is to change your "current head" from 'master' to some new head, and then to be able to switch back and forth. This is unfortunately something Cogito does not let you do directly right now, but you can use core GIT commands

	$ git-checkout -b aspyk
to create a new 'aspyk' head and switch to it, and
	$ git-checkout master

to switch back to 'master' later, etc. Note that between the switching, Cogito will work just fine even if your current head is not 'master'.

You can get the list of available heads by
	$ cg-status -g

where the current head is marked by '>' and remote heads are marked by 'R'. You can also get the list of source locations for remote heads by

	$ cg-branch-ls
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.
Linus Torvalds· Sep 22, 2005, 16:06 UTC · re: Jon Loeliger · lore
On Thu, 22 Sep 2005, Jon Loeliger wrote:
> 
>     - Where some of the Git Frustration still lies

Btw, I'd love to have more "this frustrates me" stories. I used to ask for them from the (few) people that used git early on, just to see what the problems were.

I can't really help you with documentation, and would just hope that people who figure out a problem they had would actually document it so that others don't have to figure it out the hard way.

But if there is some usage pattern that doesn't make sense, post about it, and I can try to at least say why it happens that way (and then it's back to the "please send a patch to the documentation" case above ;).

Alternatively, maybe it is something that doesn't need to happen at all, and it's just git being stupid, and we can just fix it.

So to look at your care.
Show 39 quoted lines
>     OK, so I have a git tree that looks like this:
> 
>     241 % git show-branch --more=5
>     * [jdl] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
>      ! [master] Merge branch 'master' of /home/src/linux-2.6/
>       ! [origin] Merge branch 'master' of /home/src/linux-2.6/
>        ! [paul] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
>     ----
>     +  + [jdl] Merge with rsync://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
>     ++++ [master] Merge branch 'master' of /home/src/linux-2.6/
>     ++++ [master~1] NTFS: Fix ntfs_{read,write}page() to cope with concurrent truncates better.
>     ++++ [master~2] NTFS: Fix handling of compressed directories that I broke in earlier changeset.
>     ++++ [master~3] NTFS: Fix various bugs in the runlist merging code.  (Based on libntfs
>     ++++ [master~4] vc: Use correct size on buffer copy in vc_resize
>     +  + [jdl~1] Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge
>     +  + [jdl^2] ppc32: Allow user to individual select CHRP/PMAC/PREP config
>     +  + [jdl^2~1] powerpc: Merge simplified sections.h into asm-powerpc
>     +  + [jdl^2~2] powerpc: Remove section free() and linker script bits
>     +  + [jdl^2~3] powerpc: Remove sections use from ppc64 and drivers
>     +  + [jdl^2~4] powerpc: Remove sections use from ppc
>     +  + [jdl^2~5] ppc32: Removed non-inlined versions of local_irq* functions
>     ++++ [jdl~2] Merge master.kernel.org:/home/rmk/linux-2.6-arm
> 
>     I have current, modified, non-committed files in my working tree
>     in the "jdl" branch.  I don't want to commit them now (yet).
> 
>     I now know that Linus has updated his tree with new -rc2 parts.
>     I want it.  In fact, I want it on the "origin" or "master" branch.
>     (Or both.  And I don't know which.)
> 
>     How do I get Linus' updates and merge them into the "origin" branch
>     without changing to that branch first?
> 
>     How do I get Paul's updates and merge them into the "paul" branch
>     without changing to that branch first?
> 
>     I think I can fetch the Linus updates by doing something like this:
> 
> 	git fetch origin

Yes, this works. This will fetch the new objects, and automatically update the right branch (ie it will also update the "origin" branch).

> 	git fetch rsync://....path/to/linus-2.6-git

This will _not_ work. Or rather, it will "work" in the sense that it fetches the objects, but without a place to put them into, it won't update any of the branches, so it's kind of pointless.

Show 6 quoted lines
>     That will just grab the Objects and throw them into my .git/objects.
> 
>     But how to do the merge?  I think that the merges all require
>     the "target branch" to be the "active"/checkedout branch, right?
>     I don't know how to now say "Merge-up those new Objects on the
>     origin branch".
The first one should have done that already.

You can also specify _precisely_ what branches you want to use as a source and as a destination.

Ie
	git fetch rsync:..../linus-2.6-git <src>:<dst>

will fetch the <src> branch (ie you'd usually use "master") from my tree and write it to the <dst> branch on your tree.

And it's not a "merge" - it's just an update. A merge implies that you take two trees that have had development on them and try to join them together. A "git fetch" does _not_ merge anything: it just _fetches_ the other side, and writes the objects (and top branch).

Show 6 quoted lines
>     I think what's confusing me still is that the previous
>     World View According to CVS was essentially that you have
>     this import branch into which you dragged all the external
>     updates.  Then you merged that over to your working branch.
>     And, you could easily have views of _both_ of those
>     branches simultaneously.
Hmm.. I'm not sure exactly what you want, but
	git fetch origin

will fetch my stuff without touching your changes AT ALL, and then you can do things like

	gitk --all

to see both your development series _and_ my stuff at the same time. And yes, it works fine even if you have "dirty state" in your tree.

>     However, I _could_ just stick in my "jdl" working branch and
>     directly pull-in and merge the linus changes.  I mean, my next
>     step after pulling those changes into the so-called import
>     branch was going to be to merge them to my branch anyway.
And indeed, if you just did
	git pull origin

then now you're doing a _pull_ instead of a fetch, which means that you do both the fetch _and_ the merge.

In fact, if you use the shorthand with a named branch, the above really _will_ do a "git fetch origin" first, ie it will actually _update_ the "origin" branch before merging it into your current branch. So you'll have _both_.

You can see that (again) with
	gitk --all

where you can actually see that "origin" got updated, and also merged into whatever branch you were working on.

>     OK, so let's say I did pull linus' update into the jdl branch.
>     And they merge up nicely.  How do I now propogate _just_ the
>     linus changes to the origin branch?  Again, I don't think I
>     can without first checking out the "origin" branch.
The "origin" branch was already updated automatically if you used
	git pull origin
However, if you used
	git pull rsync:..../linus-2.6.git

then git would only have fetched the objects, and _not_ updated the "origin" branch (because you didn't tell it about the "origin" branch).

But you can trivially fix that by doing
	git fetch origin
at this point, which will end up doing the equivalent of
	git fetch rsync:..../linus-2.6.git master:origin

(depending on what the contents of your .git/remotes/origin are, of course, the above is just an example).

>     Am I missing something here?  Fighting against the tool?

No, you just didn't realize how "git pull" and "git fetch" worked. Git should actually do what you want to do very naturally. Its' really how it's designed to work, you just didn't realize ;)

Show 6 quoted lines
>     So, you will all be pleased to know that I tried
>     some stuff and was not successful.  In the "jdl"
>     branch, I did a "git pull linus".  It happily went
>     out and grabbed all the new objects from his tree.
>     Spiffy.  It then announced that my branch of the
>     working tree was "dirty" and quit.
Ok, it really depends on what your ".git/remotes/linus" looks like.
For example, it _may_ just contain something like
	URL: rsync:..../linus2.6.git

in which case there is no explicit heads specified. In that case, you really should specify _which_ of the heads you want to pull, and what the target should be. For example, you can do that with

	git fetch linus master:linus

which says: "fetch the branch 'master' from the repository described by 'linus' (.git/remotes/linus) into _my_ branch 'linus'".

NOTE! This really is a _fetch_. It will fetch the objects, and _overwrite_ the old value of the branch "linus".

Now, you can specify that this is what you _always_ want to do, and actually set the branches in the ".git/remotes/linus" file explicitly. You can make your .git/remotes/linus file look like this instead:

	URL: rsync:..../linus2.6.git
	Pull: master:linus

and now you've told it that whenever you fetch (or pull) from "linus", you want to fetch the "master" branch from the remote end, and you always want to store it in the "linus" branch in the local repository.

NOTE NOTE NOTE! Your branch-name does _not_ have to match the shorthand name. So you can make the "Pull:" line say "master:linus-branch", and that will mean that when you do "git fetch linus", it will update the "linus-branch" instead.

Still with me?
Finally (or _instead_ of the "fetch"), we can do
	git pull linus

now. It will do the fetch, and since you now specify a destination in your "remotes/linus" file, it will always update the "linus" part (it a "git pull" is a _superset_ of what "git fetch" does). But in _addition_ to fetching the "linus" branch, it will then try to merge it.

Now, this is where "dirty" comes in. The merge will fail if you have changed any files that the merge wants to modify. So do a

	git diff --name-only HEAD
to see if there are any changes, and commit them - or undo them - if so.  
Then try to pull again.
	
		Linus

← back to recent threads