663

The git clone help page has this to say about --mirror:

Set up a mirror of the remote repository. This implies --bare.

But doesn't go into detail about how the --mirror clone is different from a --bare clone.

Zombo
  • 1
  • 62
  • 391
  • 407
Sam
  • 14,642
  • 6
  • 27
  • 39
  • 9
    helpful, but if you also want to push this mirror to a remote repo like github, I found [this link](https://help.github.com/articles/duplicating-a-repository#mirroring-a-repository) handy. – Eat at Joes Aug 27 '14 at 21:59

8 Answers8

755

The difference is that when using --mirror, all refs are copied as-is. This means everything: remote-tracking branches, notes, refs/originals/* (backups from filter-branch). The cloned repo has it all. It's also set up so that a remote update will re-fetch everything from the origin (overwriting the copied refs). The idea is really to mirror the repository, to have a total copy, so that you could for example host your central repo in multiple places, or back it up. Think of just straight-up copying the repo, except in a much more elegant git way.

The new documentation pretty much says all this:

--mirror

Set up a mirror of the source repository. This implies --bare. Compared to --bare, --mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository.

My original answer also noted the differences between a bare clone and a normal (non-bare) clone - the non-bare clone sets up remote tracking branches, only creating a local branch for HEAD, while the bare clone copies the branches directly.

Suppose origin has a few branches (master (HEAD), next, pu, and maint), some tags (v1, v2, v3), some remote branches (devA/master, devB/master), and some other refs (refs/foo/bar, refs/foo/baz, which might be notes, stashes, other devs' namespaces, who knows).

  • git clone origin-url (non-bare): You will get all of the tags copied, a local branch master (HEAD) tracking a remote branch origin/master, and remote branches origin/next, origin/pu, and origin/maint. The tracking branches are set up so that if you do something like git fetch origin, they'll be fetched as you expect. Any remote branches (in the cloned remote) and other refs are completely ignored.

  • git clone --bare origin-url: You will get all of the tags copied, local branches master (HEAD), next, pu, and maint, no remote tracking branches. That is, all branches are copied as is, and it's set up completely independent, with no expectation of fetching again. Any remote branches (in the cloned remote) and other refs are completely ignored.

  • git clone --mirror origin-url: Every last one of those refs will be copied as-is. You'll get all the tags, local branches master (HEAD), next, pu, and maint, remote branches devA/master and devB/master, other refs refs/foo/bar and refs/foo/baz. Everything is exactly as it was in the cloned remote. Remote tracking is set up so that if you run git remote update all refs will be overwritten from origin, as if you'd just deleted the mirror and recloned it. As the docs originally said, it's a mirror. It's supposed to be a functionally identical copy, interchangeable with the original.

H. Pauwelyn
  • 13,575
  • 26
  • 81
  • 144
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • 3
    Does "normal clone" refer to a clone without the --bare or --mirror flags? – Sam Oct 18 '10 at 18:45
  • 3
    Yeah, it does. With a bare clone, as it says on the man page, branches are copied directly as well (no refs/remotes/origin, no tracking). Edited in. – Cascabel Oct 18 '10 at 19:22
  • 4
    Can you add some more usage example about the difference, not just the git-internal differences? – cmcginty Oct 18 '10 at 21:17
  • @Casey is that what you were looking for? I didn't think what I originally wrote was "internal" at all - tags and branches are very much porcelain features. – Cascabel Oct 18 '10 at 21:45
  • Does "branches copied as is" mean that branches are copied to the same relative path on the clone? Or does it imply that branches are transformed in some way? – Sam Nov 02 '10 at 09:00
  • 1
    You said "...and remote branches origin/next, origin/pu, and origin/maint" in `git clone origin-url` section and then said "Any remote branches" are ignored. How's that? – Inam Ul Huq Oct 18 '20 at 04:38
  • @Cascabel Lets say I am working in a team of 5 member. So, when I did `git clone --mirror origin-url`, does it give local branches of other team members local repository? – Subrato Pattanaik Jan 02 '21 at 06:45
  • 1
    @SubratoPatnaik You'll get whatever's in the repo you're cloning. If they've all pushed all their branches to it, you'll get them; if they haven't, you won't. If you clone one of their local repos directly, you'll get everything in it. – Cascabel Jan 04 '21 at 00:59
  • @Cascabel so clear explanation. just one doubt: what do you mean when you say "other refs `refs/foo/bar` and `refs/foo/baz`". What kind of refs are you talking about. I understood the tags, local branch, remote branch part. But what is this "other refs" thing? – Asif Kamran Malick Mar 02 '21 at 20:53
  • 1
    Great answer. What about submodules? Do those count as "other refs"? – Adam J Richardson Jun 01 '21 at 17:00
  • @AsifKamranMalick if you research how to archive git branches, you'll discover an archiving mechanism that directly creates refs: https://stackoverflow.com/a/41008657/565877 – Devin Rhode Jun 26 '21 at 19:57
  • @Cascabel your answer is well written, just being curious if you can add other set of bullets points indicating when take each approach, it mostly for the `--mirror`, because in this network (SO) already exists many posts about differences and when use `non bare` vs `bare` – Manuel Jordan Nov 07 '21 at 00:05
  • "all refs will be overwritten from origin, as if you'd just deleted the mirror and recloned it." so it will download everything from scratch without leveraging git's functionality of fetching just the difference? – Gobe Jan 11 '22 at 18:52
  • To clarify: this does *not* include stashes - though are hacks to copy stashes, see: https://stackoverflow.com/questions/1550378/is-it-possible-to-push-a-git-stash-to-a-remote-repository – scry Apr 13 '23 at 09:35
93
$ git clone --mirror $URL

is a short-hand for

$ git clone --bare $URL
$ (cd $(basename $URL) && git remote add --mirror=fetch origin $URL)

(Copied directly from here)

How the current man-page puts it:

Compared to --bare, --mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository.

jhpratt
  • 6,841
  • 16
  • 40
  • 50
hfs
  • 2,433
  • 24
  • 37
  • 8
    I believe you'd have to follow that with a `git fetch` for it to actually be identical. Anyway, this is sort of a non-answer - the point of the question is "how is a mirror remote/clone different from a normal one?" – Cascabel Oct 18 '10 at 14:15
  • 8
    I actually like this way of demonstrating the difference. Hopefully it is accurate! I hope hfs adds the fetch command. – joeytwiddle Jul 06 '12 at 06:37
  • not really clear, e.g. what is $(basename $URL) translating into, etc. – Kzqai Oct 22 '12 at 15:24
  • 6
    `basename` is the normal unix utility that strips the directory part of a path, and `$()` is simply bash's command substitution. – Victor Zamanian Feb 27 '13 at 21:29
  • 9
    This still has `--mirror` in it. This would only be an acceptable answer if it explained what `git remote add --mirror` does. – Zenexer May 06 '14 at 03:45
29

I add a picture, show configdifference between mirror and bare. enter image description here The left is bare, right is mirror. You can be clear, mirror's config file have fetch key, which means you can update it, by git remote update or git fetch --all

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
yanzi1225627
  • 893
  • 11
  • 13
28

My tests with git-2.0.0 today indicate that the --mirror option does not copy hooks, the config file, the description file, the info/exclude file, and at least in my test case a few refs (which I don't understand.) I would not call it a "functionally identical copy, interchangeable with the original."

-bash-3.2$ git --version
git version 2.0.0
-bash-3.2$ git clone --mirror /git/hooks
Cloning into bare repository 'hooks.git'...
done.

-bash-3.2$ diff --brief -r /git/hooks.git hooks.git
Files /git/hooks.git/config and hooks.git/config differ
Files /git/hooks.git/description and hooks.git/description differ
...
Only in hooks.git/hooks: applypatch-msg.sample
...
Only in /git/hooks.git/hooks: post-receive
...
Files /git/hooks.git/info/exclude and hooks.git/info/exclude differ
...
Files /git/hooks.git/packed-refs and hooks.git/packed-refs differ
Only in /git/hooks.git/refs/heads: fake_branch
Only in /git/hooks.git/refs/heads: master
Only in /git/hooks.git/refs: meta
Mark E. Hamilton
  • 688
  • 7
  • 15
19

A nuanced explanation from the GitHub documentation on Duplicating a Repository:

As with a bare clone, a mirrored clone includes all remote branches and tags, but all local references will be overwritten each time you fetch, so it will always be the same as the original repository.

Feckmore
  • 4,322
  • 6
  • 43
  • 51
  • 1
    Thank you; this clarified for me that local *tags* will be overwritten as well as branches by using a mirrored clone. Very helpful. – Wildcard Dec 07 '15 at 21:00
  • 3
    You might also want to use `--prune` when running git fetch to remove local references that are no longer on the remote. – nishanthshanmugham Nov 06 '17 at 17:40
18

A clone copies the refs from the remote and stuffs them into a subdirectory named 'these are the refs that the remote has'.

A mirror copies the refs from the remote and puts them into its own top level - it replaces its own refs with those of the remote.

This means that when someone pulls from your mirror and stuffs the mirror's refs into thier subdirectory, they will get the same refs as were on the original. The result of fetching from an up-to-date mirror is the same as fetching directly from the initial repo.

PaulMurrayCbr
  • 1,167
  • 12
  • 16
10

Unlike git clone, git clone --mirror and git clone --bare both are bare repos. The difference between them are in the config file.

git clone's config file looks like:

[remote "origin"]
    url = https://github.com/example
    fetch = +refs/heads/*:refs/remotes/origin/*

git clone --bare's config file looks like:

[remote "origin"]
    url = https://github.com/example

git clone --mirror's config file looks like:

[remote "origin"]
    url = https://github.com/example
    fetch = +refs/*:refs/*
    mirror = true

So, we see that the main difference in in the refspec to be used for fetching

The format of the refspec is, first, an optional +, followed by <src>:<dst>, where <src> is the pattern for references on the remote side and <dst> is where those references will be tracked locally. The + tells Git to update the reference even if it isn’t a fast-forward.

In case of git clone that is automatically written by a git remote add origin command, Git fetches all the references under refs/heads/ on the server and writes them to refs/remotes/origin/ locally.

In case of git clone --bare, there is no refspec to be used for fetching.

In case of git clone --mirror, the refspec to be used for fetching looks like fetch = +refs/*:refs/*. It means, tags, remotes, replace (which is under refs directory) along with heads will be fetched as well. Note that, by default git clone only fetch heads.

NOTE 1: git clone --mirror and git clone --bare --mirror are equivalent.

NOTE 2: there is also difference in packed-refs. As it records the same information as refs/heads/, refs/tags/, and friends record in a more efficient way.

Ahmad Ismail
  • 11,636
  • 6
  • 52
  • 87
9
$ git clone --bare https://github.com/example

This command will make the new "example" directory itself the $GIT_DIR (instead of example/.git). Also the branch heads at the remote are copied directly to corresponding local branch heads, without mapping. When this option is used, neither remote-tracking branches nor the related configuration variables are created.

$ git clone --mirror https://github.com/example

As with a bare clone, a mirrored clone includes all remote branches and tags, but all local references (including remote-tracking branches, notes etc.) will be overwritten each time you fetch, so it will always be the same as the original repository.

Manur
  • 8,436
  • 2
  • 27
  • 29
Shantanu Singh
  • 197
  • 2
  • 7