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"?
A bare repo is characterized by not having a working copy in the file system. Therefore no file on the disk of a bare repo can be part of the repo, and you can't pull it as a result.
Using a Bare Repository A bare repository is linked with a local repository, hence the files in . git of local repo should match with the files in the bare repo. First, create a bare repository (See section for the code snippet).
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.
Update with:
$ git fetch origin +refs/heads/*:refs/heads/* --prune
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.
- [deleted] (none) -> bar * [new branch] foo -> foo 4812558a5f..a6aeec6517 abc -> abc + a1b2c3d4e5...1a2b3c4d5e def -> def (forced update)
foo
, abc
, def
while we have (had) one extra: bar
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)
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]
!
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