What is the difference between these `git fetch` syntaxes?
I've bare-cloned a repository ( git clone --bare
) and apparently git fetch
doesn't update it, but git fetch origin master:master
does. I don't understand all the nuances between these syntaxes:
git fetch
git fetch origin
git fetch origin master
git fetch origin master:master
origin
is my only remote and master
is my only branch, and the help says:
When no remote is specified, by default the origin remote will be used
So why these four lines aren't the same?
Edit: the three first commands seems to fetch in a temporary branch called FEATCH_HEAD
. But since I'm using a bare clone, I can't use git merge
to get the fetched results.
Edit2: From @torek's answer, I made a small test and diff'ed a --bare and a --mirror clone directories. Here is the result:
diff -ru mesa.bare.git/config mesa.mirror.git/config
--- mesa.bare.git/config 2014-10-14 20:01:42.812226509 -0400
+++ mesa.mirror.git/config 2014-10-14 20:00:53.994985222 -0400
@@ -4,3 +4,5 @@
bare = true
[remote "origin"]
url = git://anongit.freedesktop.org/mesa/mesa
+ fetch = +refs/*:refs/*
+ mirror = true
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.idx
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.pack
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.idx
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.pack
Thanks!
Andrew C's comment contains the key here, but I'll expound a bit:
git fetch
, with no additional arguments, chooses a remote name by looking at the current branch, or uses origin
(see the documentation for details). Having chosen a remote, it then proceeds as for the next form.
git fetch remote
, again with no additional arguments, uses the given remote, and extracts the fetch =
lines for that remote to obtain a set of "refspecs". It then proceeds similarly to the last case.
git fetch remote refspec
uses the given remote and the given refspec (you may give multiple refspecs here) to choose what references to update.
Once git fetch
has a remote or URL—given the name of a remote, it extracts the url =
line to obtain the URL—it contacts the other git commands on the remote server and asks them for a list of all of the remote repository's references (branches, tags, and other references, all in the refs/*
name-spaces, with a special addition for HEAD
which is also obtainable but not generally used here—it's there for the initial clone step).
For each reference thus obtained, git fetch
sees whether you have asked it to bring that reference over, and if so, what name you asked git to use in your repository.
Again, the names available are obtained from the remote. The names wanted are obtained from your refspecs, and the names they will be given in your repository are also obtained from your refspecs.
A refspec of the form a:b
means "take reference a
, but call it b
locally."
A refspec missing the b
part means "take reference a
, but put it into the special FETCH_HEAD
file." ( FETCH_HEAD
then becomes like a normal reference, like MERGE_HEAD
and ORIG_HEAD
and so on, except that it has some extra text written to it meant for the pull
script, so it only sometimes works the way you might expect.)
A refspec may contain a wildcard character: refs/heads/*
means "take all branches" (branches being, by definition, references that begin with refs/heads/
). Normally the fetch =
line in your git configuration says refs/heads/*:refs/remotes/origin/*
.1 As before, this means to rename the matched branch, with the *
on the right expanding to whatever the *
on the left of the colon matched. So this brings all branches over, but renames them as origin/master
and the like. That's normally want you want for a non- --bare
repository.
Sometimes that's also what you want for a --bare
repository, and sometimes it's not. In particular, sometimes you want a "mirror" repository, which is a bare clone that simply slave-copies some other repository. To change an ordinary bare repository into such a mirror, you simply need to modify the fetch =
line: instead of refs/heads/*:refs/remotes/origin/*
the line should read fetch = refs/heads/*:refs/heads/*
. In fact, you may want to bring over everything (tags and even notes) with fetch = refs/*:refs/*
. Whether you actually want this is something only you can decide, of course.
Note that this is common enough that git clone
has a flag to set it up automatically: clone with --mirror
and you get a bare clone with the modified fetch =
line.
1Actually the line reads +refs/heads/*:refs/remotes/origin/*
, ie, there is also a leading +
character. This plus-sign sets the "force flag", as if you had used git fetch --force
, for that particular reference-update. This is not particularly relevant to the spelling issues here, but I'll note that usually you want a forced update for remote branches like the one listed here, and also for pure mirror repositories.
If you're mirroring tags, you probably want those to do forced-update. Ideally, of course, tags never change (nor are deleted) so in an ideal world this would not matter, but in the real world they do sometimes change, or get deleted.
To handle reference deletion, you must tell git fetch
to --prune
(or, similarly, supply --prune
to git remote update
). There is no syntax in refspecs for automatic pruning (although it would be reasonable, I have not seen any proposal for it).