3

I have two pc's where I have stored my repos. They are not connect via any kind of network! Lets name the repos on that two different pc's repo1 and repo2.

And I have a local "clone" which can I move from one to the other pc. Lets name this cloned repository as simply the "clone".

If I now fetch my clone from the origin ( which is here repo1), everything is fine. But if I need to use the repo2, I can't get it to run!

Simply the command

git fetch --all repo2

gives me: fetch --all does not take a repository argument

At this point I have no idea how to continue.

I found a lot of worarounds like: How to clone all remote branches in Git?

But none of the answers dealing with multiple repos!

Is that simply not manageable?

Klaus
  • 20,019
  • 4
  • 46
  • 90

2 Answers2

3

First, I'd suggest to check the URL of your repos at stake by doing git remote -v. For the sequel, I assume that you have two remotes named origin and repo2.

Regarding the SO question you mention - How to clone all remote branches in Git? - it should be noted that it is unneeded to checkout all branches to retrieve them, because git fetch repo2 is enough to get locally the whole history of remote repo2.

According to the doc of git fetch, you can also do git fetch --all (with no additional argument) instead of git fetch origin ; git fetch repo2.

I recall that in order to list the remote branches corresponding to the remote called repo2, you can just do git branch -r which will show something like:

origin/HEAD -> origin/master
origin/master
origin/name-of-an-origin-branch
...
repo2/HEAD -> repo2/master
repo2/master
repo2/name-of-a-repo2-branch
...

that is, all remote branches are prefixed with the identifier of the remote.

In order to browse the content of these remote branches (without requiring some internet connection), you can either do gitk --all to display a read-only summary of the history of all branches, or git checkout name-of-a-repo2-branch to create a local branch associated to the tracking branch name-of-a-repo2-branch (see the doc of git checkout).

Or you can do the usual git manipulations such as merge (e.g. git merge origin/master), rebase (e.g., git rebase repo2/master) involving tracking branches from your remote repos.

Proposition of workflow to sync your two repos

Regarding your main use case (synchronize two repos that are not directly connected by a network, using a "local moveable clone"), I think the simplest configuration would be to have a "bare" moveable intermediate repo (i.e., a repo with no working directory, see the corresponding doc) at a given local URL, say "file:///path/to/bare-repo.git".

To setup one such repo, you could just do:

git init --bare /path/to/bare-repo.git

Then in repo1 you could do the following setup:

git remote add sync file:///path/to/bare-repo.git
git config alias.pull-ff-sync '!f(){ git fetch sync && git for-each-ref --format "%(refname:strip=3)" refs/remotes/sync/ | grep -v -e '\''^HEAD$'\'' | xargs -n1 bash -c '\''git checkout -q "$1" && git pull --ff-only -v sync "$1"'\'' bash; }; f'
git config alias.pull-ff-sync  # to check the alias has been properly setup
# and in particular that the «'\''» have been replaced with single «'»

git config push.default matching

for b in master develop ... ; do git push sync ${b}; done
# push all the branches you want to sync

And of course, a similar setup in repo2:

git remote add sync file:///path/that/can/be/different/to/bare-repo.git
git config alias.pull-ff-sync '!f(){ git fetch sync && git for-each-ref --format "%(refname:strip=3)" refs/remotes/sync/ | grep -v -e '\''^HEAD$'\'' | xargs -n1 bash -c '\''git checkout -q "$1" && git pull --ff-only -v sync "$1"'\'' bash; }; f'
git config push.default matching

Now, in repo1 (resp. in repo2), you can sync in the following way:

  • to fetch all the branches you have selected and merge them if the operation is fast-forward (so this command is more powerful than just git fetch sync because all local branches will be updated if a manual merge commit is not required):

      git pull-ff-sync
    
  • to push all the branches you have selected (which relies on the matching setting of the push.default configuration):

      git push -v sync
    

Remark to avoid one configuration step

Note that if you don't want to change the push.default config of your two repos (e.g., if you also want to use git push to only push one branch from repo1 to another remote...), you can instead:

  • replace

      git config push.default matching
    

    with

      git config push.default upstream  # recommended
    

    or just with

      git config push.default simple  # the default config in Git >= 2.0
    
  • run the slightly longer command below to send all matching branches from repo1 (resp. repo2) to the sync remote in one go:

      git push -v sync :
    
ErikMD
  • 7,337
  • 1
  • 13
  • 39
  • I receive all branches but I can't push them! A push --all will NOT contain all other branches. That is exactly the misunderstanding which was in my head before I really did it :-) – Klaus Apr 29 '18 at 11:02
  • @Klaus, that is normal, because `git push` alone for example, won't push anything with the normal configuration unless you have set-up the upstream remote of the current branch. But `git push repo2 master` for example, should work if you have a `master` branch both locally and in the `repo2` remote. If need be I could give more pointers on that topic in my answer. – ErikMD Apr 29 '18 at 11:13
  • Yes, I can push every *single* branch, if I am aware of it. but I want simply keep both repos in sync without handling every branch by hand. – Klaus Apr 29 '18 at 11:17
  • Actually I guess you should either make a new question regarding `git push`, or just edit your question to describe what is exactly your use case w.r.t. your two remotes? Because the current text of your question only deals with `git fetch`, which I covered in my answer. – ErikMD Apr 29 '18 at 11:17
  • It is not a question on push fetch pull ... it is simply as the headline says: "keeping multiple remote servers in sync". Use case is described: Two repos on two pcs. How to keep them in sync with a moveable clone. Anything missing? – Klaus Apr 29 '18 at 11:23
  • OK. I'd say your configuration is not that usual (because in principle, the intermediate repo ("local moveable clone") that helps synchronize two repos should be a "bare" repo that is accessed from both repo1 and repo2, while it seems that your "moveable clone" is a "non-bare" repo that has two remotes IIUC). Anyway I think what you need is just a specific configuration for push to setup in your repos repo1 and repo2. I'm going to suggest this in my answer. – ErikMD Apr 29 '18 at 11:32
0

ErikMD's two origin answer is the right way.

However, if you don't care about force pushing the repo, i.e, you have run (git pull --all or git fetch -all) and are sure that the other pc will not commit anything during the time you are doing this, then:

git push --mirror

From the docs:

--mirror

Instead of naming each ref to push, specifies that all refs under refs/ (which includes but is not limited to refs/heads/, refs/remotes/, and refs/tags/) be mirrored to the remote repository. Newly created local refs will be pushed to the remote end, locally updated refs will be force updated on the remoate end, and deleted refs will be removed from the remote end. This is the default if the configuration option remote..mirror is set.

Another way to fix all option is to try this answer.

Varun Garg
  • 1,896
  • 18
  • 33
  • I see 2 issues with this solution: (1) as noted [here](http://blog.plataformatec.com.br/2013/05/how-to-properly-mirror-a-git-repository), we shouldn't use `git push --mirror` in repos that weren’t cloned by `--mirror` as well. See also [this](https://help.github.com/articles/duplicating-a-repository) and [that](https://stackoverflow.com/questions/3959924/whats-the-difference-between-git-clone-mirror-and-git-clone-bare). (2) `--mirror` is especially suited for a 1-way backup, not a 2-way sync with 2 repos that could evolve concurrently… not to mention the risk of losing history with force-push. – ErikMD Apr 30 '18 at 13:14