Git cloning a repository that is already a clone

There's no side effects but you should understand exactly what happens when you clone a repository.

Some theory

The "problem" is that when you clone a repository "the normal way"—that is, without any funky knobs adjusted when calling git clone—you do not end up with a repository which is the same as the source one. It indeed contains exactly the same history but it has different branch layout.

To explain it in a non-scientific way, let's take an example:

  1. A source repo contains branches "master", "dev" and "release".

    It also contains two tags, "v1" and "v2".

    The "HEAD" reference in that repository points to a branch "master".

  2. When you clone this repo, your local clone will have:

    • The three remote-tracking branches: "origin/master", "origin/dev" and "origin/release".

    • The two tags, "v1" and "v2".

    • A local branch named "master" which points to the same commit the remote-tracking branch "origin/master" does.

  3. If you now clone this clone the result will have:

    • A single remote-tracking branch "origin/master".

    • A single local branch "master".

    • The two tags, "v1" and "v2".

This might appear weird, but in fact this is explicitly stated in the manual page:

Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository (visible using git branch -r), and creates and checks out an initial branch that is forked from the cloned repository’s currently active branch.

After the clone, a plain git fetch without arguments will update all the remote-tracking branches, and a git pull without arguments will in addition merge the remote master branch into the current master branch, if any (this is untrue when "--single-branch" is given; see below).

This default configuration is achieved by creating references to the remote branch heads under refs/remotes/origin and by initializing remote.origin.url and remote.origin.fetch configuration variables.

So "clone" in git clone means that all the history is cloned (unless told otherwise) but the layout of branches is different.

The reasoning is this: exactly because Git is a distributed VCS, all branches in your non-bare repository are "yours" in the sense that you do work on them and only you decide how they get synchronized with the branches in other repostories, when and why.

So when you clone a repo "the normal way" Git:

  • Only fetches the branches local to that repo: no remote-tracking branches are consdered.

    This is because the remote-tracking branches serve as bookmarks to the states of other repositories, and no work is done on them.

    To understand why Git behaves this way, consider that when you clone a Joe's repository most of the time you want Joe's work, not the stuff he fetched from whatever random repositories he communicated with.

  • Turns all the fetched branches into remote-tracking branches in the resulting repo.

  • Creates a single local branch and checks it out.

    This is merely a convenience which only adds to a possible confusion.

What to do

Well, git clone accepts a "--mirror" command-line option which produces a true copy of the origin repo but the resulting repo will be bare. Should you re-clone the resulting repo again using the "--mirror" command-line option, you will again get the true copy.

If you did a "normal" clone (which, I reckon, you did) you still are able to get everything from that repository but git clone won't cut it: you'll need to do git init followed by git remote add origin <url> followed by a specially crafted git fetch.

Exactly how to craft that git fetch, depends on what you really want to grab from the source repo, and where to put it. For a start, consider that the source repo now has "origin/master" and "master", and they might very well contain diverged histories.

Also note that cloning a non-bare repo using git clone --mirror will work but the result will not be very sensible as in this case git clone will dutifully copy all the branches—both local and remote-tracking—from the source repo verbatim, and remote-tracking branches in not something you typically expect to be present in a bare repo.


You will certainly miss the branches of the initial repository if they were not checked out in the first place.

Tags:

Git

Git Clone