FETCH_HEAD documentation vs reality

From: Joey Hess <hidden>
Date: 2016-06-15 22:52:41

While trying to find some documentation of the format of .git/FETCH_HEAD,
I found this example in git-read-tree.txt, which I think will no longer
work. Probably when this was written, .git/FETCH_HEAD contained only a single
SHA; it's much more complicated now.

        $ JC=`git rev-parse --verify "HEAD^0"`
        $ git checkout-index -f -u -a $JC
        ...
        $ git fetch git://.... linus
        $ LT=`cat .git/FETCH_HEAD`
        ...
        $ git read-tree -m -u `git merge-base $JC $LT` $JC $LT

It's also common for the first line of .git/FETCH_HEAD to be an
arbitrary branch that was fetched (as part of an unqualified "git
pull"), marked not-for-merge. So using "FETCH_HEAD" as a refname will
refer to such a branch unintentionally. There are several places in the
docs that seem to expect FETCH_HEAD to always refer to the one that was
fetched and will be merged (ie, master):

revisions.txt:

	'FETCH_HEAD' records the branch which you fetched from a remote repository
	with your last `git fetch` invocation.

git-pull.txt:

	In its default mode, `git pull` is shorthand for
	`git fetch` followed by `git merge FETCH_HEAD`.

gittutorial.txt:

	alice$ git log -p HEAD..FETCH_HEAD
	$ gitk HEAD..FETCH_HEAD

howto/rebase-from-internal-branch.txt:

	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

All this documentation could be changed, or resolve_ref_unsafe in refs.c
could be changed to have a special case parser for .git/FETCH_HEAD,
that finds the first branch that is marked for merge, where it now has
this minor special case for it:

        /* Please note that FETCH_HEAD has a second line containing other data. */
        if (get_sha1_hex(buffer, sha1) || (buffer[40] != '\0' && !isspace(buffer[40]))) {

Or yet another way to fix it would be to make git fetch always write the
intended FETCH_HEAD first into .git/FETCH_HEAD. (When not in --append mode.)
This seems like perhaps the best fix, although it does mean that if a
fetch is done of only not-for-merge refs, without --append, FETCH_HEAD
will still refer to one of them. 

I've attached a minimal proof-of-concept patch implementing this last
option.

-- 
see shy jo

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help