47

I have a "main" bare repository and a "personal" bare repository. I want to update changes form "main" to "personal", so I run:

$ git pull
fatal: /home/gimenero/applib/git/libexec/git-core/git-pull cannot be used without a working tree.

How do I pull the changes pushed to "main"?

Ben James
  • 121,135
  • 26
  • 193
  • 155
chila
  • 2,372
  • 1
  • 16
  • 33

2 Answers2

64

A git pull does a fetch followed by a merge, and you can't merge without a working tree. (There would be nowhere to resolve merge conflicts if they should arise.)

Instead, you could just fetch. Assuming your main repository is configured as a remote called origin on your personal repository:

$ git fetch origin master:master

Note that this will only be successful if the master branch of your personal repository is mirroring the master branch of the main repository. Otherwise, Git will reject the non-fast-forward fetch.

Ben James
  • 121,135
  • 26
  • 193
  • 155
  • I think you mean git fetch origin master:master – Dipstick Sep 01 '11 at 18:30
  • 1
    Yeah, I thought fetch did it, but when I wrote: "git fetch" it says: "From /home/rater/gitRepo/src * branch HEAD -> FETCH_HEAD". That 'HEAD->FETCH_HEAD' confused me. What does it mean? (It looks as if it fetches to a FETCH_HEAD for later merging like in a non-bare repo). – chila Sep 01 '11 at 18:41
  • 1
    when I write: "git fetch origin master:master" it doesn't say anything. – chila Sep 01 '11 at 18:43
  • I don't understand. If I fetch my local master branch pointer wouldn't point to the same commit of the remote master pointer. How can it fast forward, wasn't that suppose to only happen during a pull? – Roberto Jan 29 '14 at 19:57
  • I thought `git fetch --all` would work but it did not give the desired result (i.e. if you do `git fetch --all` in the bare "personal" repo, then cd into the non-bare "personal" repo and do a `git pull` none of the changes from the master repo are pulled) – Trevor Boyd Smith Jun 24 '15 at 12:12
  • Thanks it works, I would like to execute few commands after this, Is there any hooks available for it or by any other option. – Shankar Prakash G Dec 06 '17 at 13:12
49

Update with:

$ git fetch origin +refs/heads/*:refs/heads/* --prune

What does this do?

First an aside: When we speak of a branch named "xyz", git actually addresses it as refs/heads/xyz. But you can type "xyz" for short because otherwise it would be insane. (Incidentally, tags are refs/tags/xyz.) Plain xyz is ambiguous as it could be a branch, a tag, or the first N letters of a commit hash. refs/heads/xyz on the other hand explicitly represents a branch.

So even though you can type git fetch origin foo:bar to grab their foo branch as named bar in your repository, you can more explicitly type git fetch origin refs/heads/foo:refs/heads/bar to do the same thing. (Although if foo was actually a tag and not a branch, the latter will fail because their refs/heads/foo doesn't exist. Explicitness ftw.)

git fetch origin refs/heads/*:refs/heads/* means all their branch are belong to us. The command is run as if the * part is substituted to their branch name for each of their branches. i.e. git fetch origin refs/heads/abc:refs/heads/abc refs/heads/def:refs/heads/def ... (assuming they have branches named abc and def).

The --prune option means any branches we have in our repository that matches refs/heads/* but doesn't exist in their repository are deleted.

Finally, the + prefix is to allow non-fast-forward fetches. Without it, any update to branches that require force-updates are rejected.

Put together, the end result is that branches in your repository ends up looking exactly the same as theirs.

Here's an example output:

 - [deleted]               (none)     -> bar
 * [new branch]            foo        -> foo
   4812558a5f..a6aeec6517  abc        -> abc
 + a1b2c3d4e5...1a2b3c4d5e def        -> def  (forced update)
  • The example tells us they have branches foo, abc, def while we have (had) one extra: bar
  • Notice the deletion of bar by --prune and force update of def allowed by the + prefix.

Here's what happens instead if + and --prune were left off:

 * [new branch]            foo        -> foo
   4812558a5f..a6aeec6517  abc        -> abc
 ! [rejected]              def        -> def  (non-fast-forward)

One last thing:

Compare the command at the top with the following:

$ git fetch origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/* [--prune]

This is essentially what happens when we type git fetch origin [--prune]!

antak
  • 19,481
  • 9
  • 72
  • 80
  • 1
    The answer above may be more powerful and flexible than the other, but it's not visible. With a little explanation this answer could be much more interesting. What I understand is that this command is the reverse of a git `push --mirror`, which is dangerous (replaces even in case of conflicts, removes on destination anything that is not on sender side). – Stéphane Gourichon Nov 19 '14 at 06:38