Now I want to merge a remote branch, naming it origin/branch1
, with my local branch branch1
, as my partner pushed a new commit to branch1 on remote after our last merge, and I haven't committed since his last commit and want to get update from this commit. I used the following commands:
$ git fetch origin branch1
Compressing...
*branch branch1 ->FETCH_HEAD
$ git merge origin/branch1
Already up-to-date
That was not what I intended. What was in my mind before doing this was using fetch to get what my partner added and made the remote branch origin/branch1
being updated. However, the "Already up-to-date" means I failed to get the updates in my local branch1. Then I checked the sha1 value of origin/branch1
by
$ git ls-remote origin
and found that it kept the stale value of old commit after we merged last time. It tells that the git fetch origin branch1
cannot update origin/branch1
. I did another experiment, where my partner created another branch named "branch2" in his side and pushed a commit in branch2 to the remote origin. Then I still used
$ git fetch origin branch2
Compressing...
$ git merge origin/branch2
No branch named "origin/branch2"
The "Compressing" told me that the first command downloaded something in branch2 in origin successfully, however, the second command told me that there was no branch named origin/branch2! Thus I concluded that neither could git fetch origin branchname
update origin/branchname
locally, nor could it create a remote branch if it doesn't exist.
After I replace git fetch origin branch#
with git fetch origin
, all the git merge
s worked as I expected.
However, I often see the combination of
$ git fetch remote branch-name
$ git merge remote/branch-name
So my question is what is the difference between git fetch remote
and git fetch remote branch-name
? And in what conditions could I succeed in letting it work as my wish by this combination?
If you need to know what exactly git fetch
is doing or any other git
command, just prefix it with GIT_TRACE=1
, so it'll give you trace output with any other commands which are invoked, e.g.
$ GIT_TRACE=1 git fetch origin master
03:08:15.704945 git.c:348 trace: built-in: git 'fetch' 'origin' 'master'
03:08:15.706183 run-command.c:347 trace: run_command: 'ssh' 'git@github.com' 'git-upload-pack '\''FOO/BAR.git'\'''
03:08:16.006394 run-command.c:347 trace: run_command: 'rev-list' '--objects' '--stdin' '--not' '--all' '--quiet'
03:08:16.013096 run-command.c:347 trace: run_command: 'rev-list' '--objects' '--stdin' '--not' '--all'
03:08:16.013625 exec_cmd.c:129 trace: exec: 'git' 'rev-list' '--objects' '--stdin' '--not' '--all'
03:08:16.016617 git.c:348 trace: built-in: git 'rev-list' '--objects' '--stdin' '--not' '--all'
From github.com:FOO/BAR
* branch master -> FETCH_HEAD
03:08:16.153070 run-command.c:347 trace: run_command: 'gc' '--auto'
03:08:16.153748 exec_cmd.c:129 trace: exec: 'git' 'gc' '--auto'
03:08:16.157704 git.c:348 trace: built-in: git 'gc' '--auto'
which basically is doing ssh to the remote host, running git-upload-pack
which send objects packed back to git-fetch-pack
which receives missing objects from another repository.
In man git-upload-pack
we can read:
Invoked by git fetch-pack
, learns what objects the other side is missing, and sends them after packing.
And in man git-fetch-pack
we can read:
Invokes git-upload-pack
on a possibly remote repository and asks it to send objects missing from this repository, to update the named heads. The list of commits available locally is found out by scanning the local refs/ hierarchy and sent to git-upload-pack
running on the other end.
To answer the question, the difference between git fetch remote
and git fetch remote branch-name
, is that when you don't specify <refspec>
parameter (such as branch), it fetches all branches and/or tags (refs, see: git ls-refs
) from one or more other repositories along with the objects necessary to complete their histories. By default only tags which are reachable by the objects that are fetched are downloaded (e.g. you end up only with tags that point at branches that you are interested in).
And when you run with explicit branches and/or tags, git first determines what needs to be fetched, then getting only the relevant refs (branches or tags). E.g. git fetch origin master
will fetch only the master branch.
running git-upload-pack which send objects packed back to git-fetch-pack
which receives missing objects from another repository.
You can see more about git fetch-pack
with Git 2.19 (Q3 2018), since "git fetch-pack --all
" used to unnecessarily fail upon seeing an annotated tag that points at an object other than a commit.
See commit c12c9df (13 Jun 2018) by Kirill Smelkov (navytux
).
Helped-by: Junio C Hamano (gitster
).
See commit e9502c0 (11 Jun 2018) by Jeff King (peff
).
Helped-by: Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit 0079732, 28 Jun 2018)
Fetch-pack --all
became broken with respect to unusual tags in
5f0fc64 (fetch-pack
: eliminate spurious error messages, 2012-09-09, Git v1.8.0),
and was fixed only recently in e9502c0 (fetch-pack: don't try to fetch
peel values with --all
, 2018-06-11).
fetch-pack
: don't try to fetch peel values with --all
When "fetch-pack --all
" sees a tag-to-blob on the remote, it tries to fetch both the tag itself ("refs/tags/foo") and the peeled value that the remote advertises ("refs/tags/foo^{}
").
Asking for the object pointed to by the latter can cause upload-pack to complain with "not our ref", since it does not mark the peeled objects with the OUR_REF (unless they
were at the tip of some other ref).
Arguably upload-pack
should be marking those peeled objects. But it never has in the past, since clients would generally just ask for the tag and expect to get the peeled
value along with it.
And that's how "git fetch
" works, as well as older versions of "fetch-pack --all
".
Let's explicitly test all relevant cases with 4 tag objects pointing to
- 1) a blob,
- 2) a tree,
- 3) a commit, and
- 4) another tag objects.
The referenced tag objects themselves are referenced from under regular refs/tags/*
namespace.
Before e9502c0 (Git 2.19) fetch-pack --all
was failing e.g. this way:
.../git/t/trash directory.t5500-fetch-pack/fetchall$ git ls-remote ..
44085874... HEAD
...
bc4e9e1f... refs/tags/tag-to-blob
038f48ad... refs/tags/tag-to-blob^{} # peeled
520db1f5... refs/tags/tag-to-tree
7395c100... refs/tags/tag-to-tree^{} # peeled
.../git/t/trash directory.t5500-fetch-pack/fetchall$ git fetch-pack --all ..
fatal: A git upload-pack: not our ref 038f48ad...
fatal: The remote end hung up unexpectedly