44

I'm following this documentation: https://help.github.com/articles/duplicating-a-repository/

git clone --mirror https://github.com/exampleuser/repository-to-mirror.git

cd repository-to-mirror.git

git push --mirror https://github.com/exampleuser/mirrored

The output shows that the repository is pushed as a mirror, but for some reason I'm getting these errors as well:

 ! [remote rejected] refs/pull/1/head -> refs/pull/1/head (deny updating a hidden ref)
 ! [remote rejected] refs/pull/1/merge -> refs/pull/1/merge (deny updating a hidden ref)

What are these errors? Can I assume the repository was mirrored ?

deez
  • 1,188
  • 2
  • 16
  • 25

6 Answers6

43

As mentioned in this issue, that happens when you mirror a GitHub repo which has pull requests made to it.

The refs beginning 'refs/pull' are synthetic read-only refs created by GitHub - you can't update (and therefore 'clean') them, because they reflect branches that may well actually come from other repositories - ones that submitted pull-requests to you.

So, while you've pushed all your real refs, the pull requests don't get updated

You would need to mirror a GitHub repo without their pull requests.

Simply replace the catch-all refspec above with two more specific specs to just include all heads and tags, but not the pulls, and all the remote pull refs will no longer make it into your bare mirror:

fetch = +refs/heads/*:refs/heads/*
fetch = +refs/tags/*:refs/tags/*
fetch = +refs/change/*:refs/change/*

If push still fails, as commented by Ofek Shilon, add the push entries:

push = +refs/heads/*:refs/heads/*
push = +refs/tags/*:refs/tags/*
push = +refs/change/*:refs/change/*

As mention in Git Refspec:

The + tells Git to update the reference even if it isn’t a fast-forward.

VonC
  • 1,129,465
  • 480
  • 4,036
  • 4,755
  • 1
    Thanks, I went through the procedure but for some reason i'm still getting the same error. I clone the repo with --mirror, I edit the git configuration with `git config -e` and run - `git remote update` and `git push mirror` and still get the same error. – deez Dec 14 '15 at 13:19
  • @deezx What does return `git config --get-regex remote.origin.fetch`? – VonC Dec 14 '15 at 13:29
  • This is the output- $ git config --get-regex remote.origin.fetch remote.origin.fetch +refs/heads/*:refs/heads/* remote.origin.fetch +refs/tags/*:refs/tags/* Actually, when I cloned the repository without --mirror, edited the git config as you wrote, it worked. it fetched only branches and tags, so it worked! My only question now is that I see that it didn't mirror the `refs/changes`. Is there a way to tell git to fetch ALL except for pull requests (`refs/pull`)? – deez Dec 14 '15 at 13:41
  • @deezx no, you need to add `+refs/changes/*:refs/changes/*` for it to fetch `heads`, `tags` and `changes`, but not `pull`. Does the `git push --mirror` works after that? Make sure to try again in a new local clone (not `clone --mirror`, just simple clone, in which you add the fetch refspecs, do a `git fetch`, then `push --mirror` to another repo) – VonC Dec 14 '15 at 13:45
  • @VonC I'm having the same trouble as deez had. On a fresh repo, added the config into your suggested fetch refspec, and push still fails with the same error. Do you know if this recipe still works in 2021? – Ofek Shilon Dec 12 '21 at 18:11
  • @OfekShilon it should still work. Try and describe your use case in a separate question, with OS and Git version. – VonC Dec 12 '21 at 20:11
  • @VonC adding ‘push’ keys to the config, with identical refspecs, solved my problem (fetch keys weren’t enough). – Ofek Shilon Dec 12 '21 at 21:13
  • @OfekShilon OK. I have edited the answer to include your comment. Thank you for this feedback. – VonC Dec 12 '21 at 21:51
  • A small aside: The '+' at the refspecs start is said to "tell Git to update the reference even if it isn’t a fast-forward" (from the Pro-git book). Not sure if it is relevant to the `push` lines. – Ofek Shilon Dec 13 '21 at 10:47
  • 1
    @OfekShilon It does. I have updated the answer accordingly. – VonC Dec 13 '21 at 14:09
16

instead of

git clone --mirror

use

git clone --bare

instructions

Smart Networks
  • 191
  • 2
  • 6
12

Full steps:

git clone --bare https://github.com/exampleuser/old-repository.git
cd old-repository
git push --mirror https://github.com/exampleuser/new-repository.git
Vovan
  • 149
  • 1
  • 3
4

Found working and simple solutions there https://www.metaltoad.com/blog/git-push-all-branches-new-remote

git push newremote refs/remotes/oldremote/*:refs/heads/*

or

git push newremote refs/remotes/oldremote/features/*:refs/heads/features/*
Panoptik
  • 854
  • 1
  • 14
  • 22
2

(I wanted this to be a comment, but not enough reputation)

Based on @VonC's answer, this sounds like a non-problem.

So, while you've pushed all your real refs, the pull requests don't get updated

I see two scenarios in which you want to duplicate your repository.

  1. You want a backup/copy of a repo that you have full control over.
  2. You're modifying the history of a repo and you need a backup locally in case you need to undo your changes.

In either case, it seems like git clone --mirror is your safest option because even if you see errors in your push, all of the non-pull request related content was successfully pushed, which takes care of scenario 1. For scenario 2, you'd want those pull request references as part of your backup.

zhanga
  • 89
  • 2
  • 9
  • I am more in senario 2, where I would like to fully migrate my repository (and so interested in keeping the history of any pull requests). How would I go about a solution that keeps them intact (ie github repo --> mirror clone --> gitlab (or other vcs)) – Cole Apr 25 '21 at 03:21
0

Adding these three lines to the git config file after the fetch = +refs/:refs/ line fixed it for me:

push = +refs/heads/*:refs/heads/*
push = +refs/tags/*:refs/tags/*
push = +refs/change/*:refs/change/*
bcoder
  • 29
  • 4