Re: [PATCH 0/3] Somebody updated my branch tip underneath me.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sergio Callegari <scallegari@xxxxxxxxxxxxxx> writes:

> Junio C Hamano <junkio <at> cox.net> writes:
>
>> 
>> Answering that is part of "let's see who are motivated enough"
>> area .  Are you?
>
> Touché! :-)

Having said that...

       If we allowed a commit to be created in such a case, your next
       commit will have B as the parent, with the tree state you wanted
       to have in X.  The graph becomes like this:

                 x---x---B
                /          \
        ---o---A            X (New HEAD)

       The commit essentially reverts what happened in 'x' and 'B',
       which is quite bad.

       What you want to happen in this case is to make a graph like
       this:

                 x---x---B branch tip
                /
        ---o---A-------X (your work is still based on A)

       and then perhaps merge B's work, after making sure B is a
       fast-forward of A and doing other sanity checks:

                 x---x---B
                /         \
        ---o---A-------X---M the final branch tip

I did not code the patch to detach the HEAD at the same time,
because I was not convinced that "What you want to happen" part
is the *only* sane resolution of the situation.

Depending on who created the chain that leads to B, I suspect
the desired outcome to resolve this situation would be
different.  If it was yourself working in another repository
(either working in a separate repository on the same machine,
and then pushed to update the branch tip from there, or working
in a separate working tree that shares the .git/refs with this
repository created with Julian Phillips's workdir script to
directly update the branch tip), then you might want to rebase
the branch tip on top of your commit 'X', resulting in a picture
like this instead:

                         x'--x'--B' branch tip
                        /
        ---o---A-------X (your work is still based on A)

Both of these workflows would require you to detach your HEAD to
A.

But it is conceivable that you might want to do an equivalent of
"switching branches while merging the local changes" (aka "git
checkout -m other-branch") without making a commit, to result
in:

                 x---x---B.......X' (your work is now based on B)
                /        tip
        ---o---A

This is especially true when the chain leading to B is somebody
else's work, which potentially is already published elsewhere.
You do not want to rebase that (although it is perfectly fine to
merge with it, so the solution I suggested in the original
message is Ok).

The difference in the end result is your commit will come after
B, not before it, and in this case you do not need to detach the
HEAD.  For this, you would need to perform the same operation as
"# Match the index to the working tree, and do a three-way" part
of git-checkout.sh:

	git update-index --refresh >/dev/null

	new=`git rev-parse --verify HEAD` ;# updated head at B
	old=`git update-index --get-base` ;# base of the working tree at A

	# prepare $work tree that represents what you would have
        # committed if you did "git commit -a"
    	git diff-files --name-only | git update-index --remove --stdin &&
	work=`git write-tree` &&
	git read-tree --reset -u $new || exit

        # Three-way merge to transplant A..X change on top of B
	eval GITHEAD_$new='${new_name:-${branch:-$new}}' &&
	eval GITHEAD_$work=local &&
	export GITHEAD_$new GITHEAD_$work &&
	git merge-recursive $old -- $new $work

	# Do not register the cleanly merged paths in the index yet.
	# this is not a real merge before committing, but just carrying
	# the working tree changes along.
	unmerged=`git ls-files -u`
	git read-tree --reset $new	;# index has B's tree now
	case "$unmerged" in
	'')	;;
	*)
		# ... except we carry the conflicted paths along
		(
			z40=0000000000000000000000000000000000000000
			echo "$unmerged" |
			sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
			echo "$unmerged"
		) | git update-index --index-info
		;;
	esac


Where you should detach your head to (if you choose to do so) is
already recorded in the index and "git update-index --get-base"
would give that to you if you need it, but once we detach the
HEAD, we would not know on which branch we were, and we need to
keep that information while detaching the HEAD.  If there is a
sane resolution that does not require detaching the HEAD (such
as the above example), there is no point to do so, so I left
that policy decision to later steps.

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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]