I have a local repository that pulls from a remote one. Running git pull
as well as git fetch; git merge FETCH_HEAD
used to perform exactly the same action, as is expected from the description of git pull
:
DESCRIPTION
Incorporates changes from a remote repository into the current branch. In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD.
Presently, and unexpectedly, running git fetch
stopped updating the FETCH_HEAD
reference correctly. FETCH_HEAD
is now stuck to an old commit. Running git fetch
downloads all changes to remote tracked branches, but FETCH_HEAD remains unchanged regardless of the branch in which it is run.
# currently in branchone
> git fetch
# branchone is up to date since...
> git rev-parse branchone
593539e8a98ba5980d4b645db3b0f506bb9b6a2c
# ...its in the same commit as the remote branch
> git rev-parse origin/branchone
593539e8a98ba5980d4b645db3b0f506bb9b6a2c
# however FETCH_HEAD shows something different
> git rev-parse FETCH_HEAD
37301df96597ac037f8e7e846fea6fc7df77bea5
git pull
still performs the correct task. However running git fetch; git merge FETCH_HEAD
will do something different since FETCH_HEAD
points to an incorrect commit.
Is there any setting or issue that could be messing with git fetch
behavior?
git pull Not Updating Files Due to Uncommitted Files in Your Local Repository. As a source code management system, Git does its best to prevent you from losing your files and data. For this reason, Git may refuse to merge your local files with files from your remote repository when performing the git pull command.
I faced this issue before, the main reason is that you didn't config the remote. origin. fetch in your git local config. after that, run 'git fetch origin', i think you will get the expected output.
So while fetch does indeed fetch all object data from the remote storage, FETCH_HEAD is used to indicate to where the remote branch tracked by the local branch has advanced. So if you are on the local master branch and run git fetch , and branch. master.
git fetch is the command that tells your local git to retrieve the latest meta-data info from the original (yet doesn't do any file transferring. It's more like just checking to see if there are any changes available). git pull on the other hand does that AND brings (copy) those changes from the remote repository.
Running git fetch
without any options will fetch all references in the remotes and write them to the .git/FETCH_HEAD
file. The contents of the file usualy looks something like this:
37301df96597ac037f8e7e846fea6fc7df77bea5 branch 'master' of github.com:user/repo
593539e8a98ba5980d4b645db3b0f506bb9b6a2c not-for-merge branch 'branchOne' of github.com:user/repo
When you have a file like this under the .git
directory, you can use it as a reference as long as the first thing in that file is either a 40 character hex number, or a shorter hex number that actualy matches to an existing commit.
# This file can be used as a reference
> cat .git/MAGIC_HEAD
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef lorem ipsum
the rest does not really matter
refrigerator
# And thus it will be interpreted by many git commands like this
> git rev-parse MAGIC_HEAD
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
Knowing this we can see that after running git fetch
the reference FETCH_HEAD
will resolve to is whatever happens to be in that first line
# Assuming the already mentioned contents of .git/FETCH_HEAD
> git rev-parse FETCH_HEAD
37301df96597ac037f8e7e846fea6fc7df77bea5
Seems like the order of the contents of .git/FETCH_HEAD
is not guaranteed to contain first the reference for the current branch.
By trying it in different repositories it seems that in some the first line is always the current branch, and thus git fetch; git merge FETCH_HEAD
works as expected. On other repositories however the contents of .git/FETCH_HEAD
will be ordered differently and often the first line will be a reference to the remote commit of a different branch, thus making the FETCH_HEAD
reference incorrect.
Why it behaves differently is a mystery to me.
As a solution, if git fetch remote_name branch_name
is used only this specific branch is fetched and only that single line will appear in the contents of .git/FETCH_HEAD
, making the FETCH_HEAD
reference always correct.
# Will only fetch branchone
> git fetch origin branchone
# FETCH_HEAD will contain only a single line
> cat .git/FETCH_HEAD
593539e8a98ba5980d4b645db3b0f506bb9b6a2c branch 'branchOne' of github.com:user/repo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With