Re: Dangers of working on a tracking branch

Previous thread: [PATCH] pretend-sha1: grave bugfix. by Junio C Hamano on Thursday, February 15, 2007 - 6:16 pm. (4 messages)

Next thread: [PATCH] Add `git diff2`, a GNU diff workalike by Johannes Schindelin on Thursday, February 15, 2007 - 9:01 pm. (4 messages)
From: Jakub Narebski
Date: Thursday, February 15, 2007 - 7:00 pm

You cannot fetch or push to the remote branch if you made some commits
on the tracking branch ("broke the model") and remote branch has other
commits. You can force the issue, but then either remote (for push)
or local (for fetch) commits would be lost.

Sidenote: for some branches you have to skip fast-forward check, because

But one of those branches can be temporary "branch" FETCH_HEAD (if you

Because usually you work with one branch with tracking (remote) + local
branch workflow; I think with multiple branches you usually use temporary
feature branches...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


-

From: Bill Lear
Date: Friday, February 16, 2007 - 8:13 am

Ok, I'm trying to come up with an experiment that verifies this, so
I can give a concrete example to our developers.

I don't seem to be able to get it to fail, but I sure remember having
severe problems with this in practice.  Here is my attempt, again with
git 1.4.4.1:

# Create my repo and add a file A
% mkdir my_repo
% cd my_repo
% git init-db
defaulting to local storage area
% echo A > A
% git add A && git commit -a -m "Add A"
Committing initial tree f53c91092dbda83f3565e78c285f3e2ab0cfd968

# Create a peer repo and add a file B
% cd ..
% mkdir peer_repo
% cd peer_repo/
% git init-db
defaulting to local storage area
% echo B > B
% git add B && git commit -a -m "Add B"
Committing initial tree bfcfa4ca04d80d4b092e022ad163e82ca0f4a34f

# Create a topic branch in peer repo and add file C
% git checkout -b topic
% echo C > C
% git add C && git commit -a -m "Add C"

# Go back to my repo and fetch peer's topic branch
% cd ../my_repo/
% git fetch ../peer_repo topic:topic
warning: no common commits
remote: Generating pack...
remote: Done counting 6 objects.
remote: Deltifying 6 objects.
remote: /6) done/6) done
Unpacking 6 objects
remote: Total 6, written 6 (delta 0), reused 0 (delta 0)
 100% (6/6) done
* refs/heads/topic: storing branch 'topic' of ../peer_repo
  commit: af3ab53

# In my repo, checkout topic and change B
% git checkout topic
% echo "Change B" >> B
% git commit -a -m "Change B"

# Go back to peer repo and change C
% cd ../peer_repo/
% echo "Change C" >> C
% git commit -a -m "Change C"

# Go back to my repo and pull peer's topic branch
% cd ../my_repo
% git pull ../peer_repo topic:topic
remote: Generating pack...
remote: Done counting 5 objects.
remote: Result has 3 objects.
remote: Deltifying 3 objects.
remote:  100% (3/3) done
remote: Total 3, written 3 (delta 0), reused 0 (delta 0)
Unpacking 3 objects
 100% (3/3) done
* refs/heads/topic: not updating to non-fast forward branch 'topic' of ../peer_repo
  old...new: ...
From: Jeff King
Date: Friday, February 16, 2007 - 8:21 am

Because your pull command really means "merge in the topic branch from
peer_repo, and while you're at it, store it in my local tracking branch
topic". Remember that pull is really a fetch+merge. But the fetch is
actually doing _two_ things: putting the fetched branch into FETCH_HEAD,
and putting it in into refs/heads/topic. The latter fails (because of a
non-fastforward), but pull actually uses the FETCH_HEAD results to
do the merge.

Yes, this seems overly complex for what you're doing, but the reason for
FETCH_HEAD is to support pulls when you _don't_ have a tracking branch
at all (i.e., 'git pull ../peer_repo topic').

-Peff
-

From: Bill Lear
Date: Friday, February 16, 2007 - 8:27 am

Ok, fair enough, but then I guess I'm back to my original question:
how can I give a concrete demonstration to our developers that this is
a bad thing?

This is not 100% required, so if you are tired of answering my
incessant questions, feel free to decline.  I will be able to get our
group to move forward, simply because we need to try to stay current,
and there are lots of improvements in git besides this issue.


Bill
-

From: Jeff King
Date: Friday, February 16, 2007 - 8:52 am

I think it will always work with the example you gave, because you are
simultaneously fetching into the tracking branch (which fails) and
merging from FETCH_HEAD (which succeeds) into that same tracking branch.

At best, though, the tracking branch you have is pointless (since you
immediately overwrite it anyway).  The point of a tracking branch
generally is to allow you to do operations against your peer's idea of
the branch (e.g., diffing against upstream's version of "topic"). But
you can't do that, because "topic" always contains your topic, not
upstream's. In effect, your pull becomes one without a tracking branch
at all.

This will also get you on a push, where there is no merging at all, just
a fast-forward (or failure). IIRC, you ran into problems before because
you were trying to push into your public repo from your private, but the
two had divergent branches. So I think to illustrate the problem you had
before, you actually need an intermediate repo which has you fetch from
and push to.

-Peff
-

From: sbejar
Date: Friday, February 16, 2007 - 9:10 am

It no longer works with recent git, as of v1.4.4.1-37-gd25c26e. Now
git-fetch exit with a non-zero status when fast-forward check fails,
so the merge does not happen.

Santi
-

From: Nicolas Pitre
Date: Friday, February 16, 2007 - 9:34 am

Try this:

	# create first repository
	mkdir foo
	cd foo
	git init-db
	echo FOO > biz
	git add biz
	git commit -a -m "commit 1 in foo"

	# clone this repository elsewhere
	cd ..
	git clone foo bar
	cd bar

	# modify the tracking branch (origin in this case)
	git checkout origin
	echo BAR > biz
	git commit -a -m "modify tracking branch in bar"

	# go back to original repo and modify it
	cd ../foo
	echo BAZ > biz
	git commit -a -m "modify master branch in foo"

	# now back to the cloned repo
	cd ../bar
	git fetch	# it fails
	git push	# itfails
	git pull	# it almost performs the merge but...

Because you now have a conflict to resolve, you might wish to inspect 
what the remote state actually is.  But because you modified your origin 
branch you don't have any pristine version of what the remote has, 
except maybe the MERGE_HEAD.  But if you work in a complex project, 
MERGE_HEAD will not stay there for long if you move around.

Imagine that you want to move to another branch, say master, because 
right now you don't feel like resolving this ultra complex merge:

	git checkout master	# it fails (unresolved merge)
	git checkout -f		# succeeds, discarding the merge

But at this point you still don't have any way to look at the remote's 
content.  If instead the origin branch was untouched and the work had 
occurred in the master branch, then you could git-log the origin branch, 
you could git-diff your master branch with the origin branch, you could 
even checkout the origin content to test it, etc.  But since you added 
commits on top of the origin branch then you cannot do any of that 
because it is impossible to update the origin branch with the remote 
stuff.  Well you can force it of course:

	git fetch -f

But by doing so you lose all the work you committed on top of origin.

BTW I checked out v1.4.4.1 to verify the above operations..... and this 
GIT version really feels odd compared to v1.5.0


Nicolas
-

From: Bill Lear
Date: Friday, February 16, 2007 - 9:40 am

Ok, that's basically what I was looking for --- incontrovertible
evidence from "them" (a git expert --- not me).  Thanks very much
Nicolas.


Bill
-

Previous thread: [PATCH] pretend-sha1: grave bugfix. by Junio C Hamano on Thursday, February 15, 2007 - 6:16 pm. (4 messages)

Next thread: [PATCH] Add `git diff2`, a GNU diff workalike by Johannes Schindelin on Thursday, February 15, 2007 - 9:01 pm. (4 messages)