git fetch, FETCH_HEAD and origin/master

痴心易碎 提交于 2019-12-17 06:43:17

问题


I'm very new to git and I'm having trouble with a simple fetch operation.

I'm trying to fetch a coworker's progress from his repository. At first I did git fetch HEAD which prompted git to download about 350MB of data so I was sure it had done something. However, origin/master ended up still pointing to the same old commit (actually it's under the name dev but I'll call it master - he doesn't have a master).

After that I tried git fetch origin master but it didn't seem to do anything, it only updated FETCH_HEAD. I tagged the FETCH_HEAD commit so I wouldn't lose it, but I'd still like to have an updated remote branch.

What was it that went wrong? I do not have access to the remote repository. Can I still fix it at home?


回答1:


I'm a bit confused by the commands you use. HEAD is usually a label git uses to track the commit that is currently in the working directory. The git fetch command expects a remote or a remote commit configuration to know what you want fetched. Using git fetch HEAD would indicate HEAD is a remote in your repository. That the command worked without error is curious.

For example: git fetch HEAD in the repository I'm currently working results in the following error

fatal: 'HEAD' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

The command git remote will list all remotes, while git remote --verbose will include the address of the remote. Could you use this to see if you have a remote defined as HEAD and what remote addresses your friends repository?

However, my questions aside and to help clear up your confusion. The git fetch ... command only updates remote refs -- not your local ones.

To make this clear, look inside the .git folder in your repository (it is hidden by default so you may need to unhide it). You will find a folder structure similar to the following

working directory
|=>.git
|  |=>objects           <= contains data for each commit
|  |=>refs
|     |=>heads
|        |-master       <= file containing current commit of local master branch
|     |=>remotes
|        |=>origin
|           |-master    <= file containing current commit of remote origin's master branch
|-FETCH_HEAD            <= file updated by `git fetch`, contains info of what was fetched

Say you checkout the master branch, git checkout master -- git will change your working directory to match the commit data in the 'objects' folder that matches the commit value in the '.git/refs/heads/master' file.

If you then git fetch origin master, the '.git/refs/remotes/origin/master' file is updated to the commit of the master branch on the remote origin -- and all commit data needed for that commit is downloaded and placed in the 'objects' folder.

The important point here is git fetch does not update your working directory reflects the local branch checked out and git fetch never updates a local branch.

Using either git merge ... or git rebase ... is needed to update the local master branch with the changes in origin/master. git pull ... does both git fetch ... and either git merge ... or git rebase ..., depending on options and configuration (git merge ... is the default).

After all that explanation, you want to be able to see what -- if anything -- was fetched from your friends repository. The git branch -avv command will list all local and remote branches, with commit numbers and in the case of local branches, what remote branch it is tracking.

To see how the branches relate to each other I find it helpful to use a tool to graph the repository tree. There are several to choose from but I find the git log command sufficient; such as git log --all --graph --oneline --decorate. Fair warning, this can be quite long and convoluted for a large repository. A shorter output can be obtained with by adding the --simplify-by-decoration argument.

To summarize: if you can fix it at home depends on the information in your repository. The above mentioned commands; git remote --verbose, git branch -avv and git log ... should be give you an understanding of the current state of your repository. From there you can determine if you need to do something more to get the data in your local branch(es) using git merge or git rebase.

As always, if you run into trouble, post back with what you learn.




回答2:


Since git 1.8.4 (August 2013), git fetch will update the remote tracking branch! Not just FETCH_HEAD.

See commit f269048 from Jeff King (peff):

When we run a regular "git fetch" without arguments, we update the tracking refs according to the configured refspec.
However, when we run "git fetch origin master" (or "git pull origin master"), we do not look at the configured refspecs at all, and just update FETCH_HEAD.

We miss an opportunity to update "refs/remotes/origin/master" (or whatever the user has configured). Some users find this confusing, because they would want to do further comparisons against the old state of the remote master, like:

$ git pull origin master
$ git log HEAD...origin/master

But that supposes you have set your repo to fetch branches:

git config remote.origin.fetch

If empty:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'



回答3:


git fetch does not actually touch your working dir. It only fetches the latest changes from remotes. To actually update your current state use git merge or git rebase. Also, you may use git pull which works like shortcut to git fetch + git merge.

The main difference between merge and rebase is that in some cases merge will create a new commit, with accumulated state (non fast-forward merge). IMHO this is bad, as reminds me of the times I used SVN. Rebase just replays your changes on the top of specified commit, so your history is always linear. Just be sure to use the same flow as your colleagues.

I suggest you read some stuff about git in general and git flow: a must-read book and a good article.




回答4:


What you want to do is:

  • Add a remote for your coworker
  • Fetch the changes from his repository
  • Create a local branch which refers to his remote branch

Presumably, you've already done step #1. But for completeness, it's:

git remote add coworker git://path/to/coworkers/repo.git

where the URL can be any URL format which git supports.

Now that you have the remote added, you want to fetch his changes:

git fetch coworker

This gives you remote branches for each of his branches. Let's say his branch is called "hamster." Now, in order to do work, you create your own local copy of the remote branch

git checkout -b hamster coworker/hamster

This creates and switches you to a branch called hamster.

From that point on, you can do work on hamster and push it to him with

git push coworker hamster

the first time, and then just git push after that.

Anytime you want to pull down and merge his changes, you can do:

git pull



来源:https://stackoverflow.com/questions/15032159/git-fetch-fetch-head-and-origin-master

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!