문제

I made two changes to my remote repository in GitHub, by adding a new file and deleting a old file (by using the Web interface of GitHub). when I do :

git fetch origin master
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From github.com:TommyHilly/programFiles
 * branch            master     -> FETCH_HEAD
git merge origin/master
Already up-to-date.

whenever new files are added or deleted, git pull only works (git fetch/merge fails).

$git pull
From github.com:TommyHilly/programFiles
   b598c97..531d466  master     -> origin/master
Updating b598c97..531d466
Fast-forward
 README.txt |   2 ++
 a.out      | Bin 8496 -> 0 bytes
 2 files changed, 2 insertions(+)
 create mode 100644 README.txt
 delete mode 100755 a.out

But when I have some files edited (nothing new added or deleted), git fetch and merge works fine.

Am I doing something wrong or is this how git works?

EDIT:

git remote -v
origin  git@github.com:TommyHilly/programFiles.git (fetch)
origin  git@github.com:TommyHilly/programFiles.git (push)

EDIT 2: Just doing git fetch and git merge origin/master seems to work. But I dont understand what is going on?

But git fetch origin master followed by git merge origin/master did not work?

도움이 되었습니까?

해결책

It's true that git pull is really just git fetch plus git merge. But there are a bunch of caveats.

git fetch

When you run:

$ git fetch origin master

this "means":

$ git fetch origin master:FETCH_HEAD

which tells git fetch to run over to origin and ask them—github, in this case, and I will use "them" and "they" here to refer to origin, so that "it" means "your fetch"—what they have for branch master. Whatever they have, it brings over, but it puts that under the local special name FETCH_HEAD.

If you run instead:

$ git fetch origin

this "means" for fetch to run over to origin and ask them about all their branches, and bring them all over as "remote branches". If they have branches "master" and "experiment", it brings those over as "remote branches" origin/master and origin/experiment.

git merge

First, git merge always merges into your current branch (the one marked with a * in git branch output).1 In other words, it knows where to merge to. You need to tell it where to merge from, though.

If you run:

$ git merge

with no arguments, it has to figure out what commit-ID you want to "merge from". It does this by looking for a configuration variable, merge.defaultToUpstream. If you get:

fatal: No commit specified and merge.defaultToUpstream not set.

this means merge.defaultToUpstream is not set, or is set to false instead of true.

If you run git merge name-or-ID, that tells git merge what to "merge from", so it does not need this special configuration variable. Hence:

$ git merge FETCH_HEAD

means "find the commit specified by FETCH_HEAD". Or, if you run:

$ git merge origin/master

this means "find the commit specified by origin/master".

Important: If you supply more than one extra argument to git merge, it does an "octopus merge" (which I'm not going to describe in this answer). This means that git merge origin master is quite different from git merge origin/master. The slash makes a huge difference, because it changes the merge command from a two-argument merge, to a one-argument merge. (I think it's unfortunate—and/or bad design—that git pull has you use exactly those arguments, but they mean something quite different to git merge.)

Putting them together

So, when do you want to supply FETCH_HEAD to git merge, and when do you want to supply origin/master instead? Well, go back and re-read the section about git fetch above.

The FETCH_HEAD method is the old2 way, in which you tell git fetch both the place to fetch from, and the branch to fetch from, and have git fetch write the result under the special name FETCH_HEAD. It does not matter what branch you fetched: git fetch origin inigo_montoya, git fetch origin you_killed_my_father, git fetch origin inconceivable: they all come over and get renamed FETCH_HEAD, so that's what you merge with.

The origin/master method is the new3 way: you run git fetch origin and it just brings everything over and you can take your time and browse through "remote branches" at your leisure. Once you're happy with origin/master and ready to merge it in, you merge it in by its (clear, simple, and obvious) name, instead of by FETCH_HEAD.

git pull

Alas, git pull.4 The pull script still uses the "old way". When you run git pull origin master, or even just git pull with no arguments,5 it winds up running git fetch origin master, which makes git fetch behave the "old way". Then it uses git merge FETCH_HEAD, which it has to, because it's just run git fetch such that fetch did not update origin/master.6


1Even if you're in the "detached HEAD" mode, git merge still merges to your "current branch", sort of. It's just that the closest thing to "current branch" is now "the detached HEAD".

2Or maybe "traditional". I wish it were "obsolete", and that might happen eventually, but for now it's pretty deeply rooted.

3And far superior. :-)

4I don't like git pull. It's meant as a convenience, and due to its insistence on doing things the "old way", it winds up being less convenient, not to mention one rare but serious bug it's had for a long time (fixed in git 1.8.4).

5With no arguments, git pull gets the name of the remote and branch from the configuration for the current branch. If you're on branch master, for instance, git reads branch.master.remote and branch.master.merge to get origin and master. These are the same values that make local branch master a "tracking branch", tracking remote-branch origin/master. Which is great, except git pull forces git fetch not to update origin/master. So git pull updates your local master, but leaves things such that git tells you you're now ahead of origin/master! Yuck. (This is fixed in git 1.8.4; git fetch updates remote branches now, even while it writes to FETCH_HEAD.)

6This is fixed in git 1.9, which might finally make git pull a convenience method that's actually convenient. :-)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top