7

If we use the git clone --branch command, we're only copying the specified branch. What is the additional --single-branch param used fo? The documentation isn't clear to me.

TIA

mrahma04
  • 109
  • 1
  • 6
  • check here https://stackoverflow.com/a/14930421/6898523 – MAhipal Singh Feb 19 '18 at 14:45
  • Note: this work with submodules too now (Git 2.26, Q1 2020). See the last section of [How do I clone a single branch in Git?](https://stackoverflow.com/a/9920956/6309) – VonC Mar 06 '20 at 08:39

3 Answers3

14

--branch foo automatically checks out foo after the clone is done but the clone downloads all the branches/tags and their reachable data.

--branch foo --single-branch tells git-clone to download only the data reachable from foo and check out foo.

ElpieKay
  • 27,194
  • 6
  • 32
  • 53
7

If we use the git clone --branch command, we're only copying the specified branch.

No, you're cloning the entire repository and checking out that branch.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
6

As ElpieKay answered, git clone --branch name url is (my paraphrase) very roughly equivalent to:

(git clone url && cd clone-target-directory && git checkout name)

—i.e., it does a full clone. (The parentheses above are because your main command interpreter does not change directories, so to simulate this, we need to do the cd in a sub-shell.)

The git clone command itself is short-hand for a series of more-primitive Git operations. All get done in a new directory,1 which I'll show as step 1 here, but note that your command interpreter itself stays outside this new directory so you end up having to do your own separate cd into the new directory. Some options are incompatible or set other options, e.g., using --depth sets --single-branch by default.2 These are built in to a single command, rather than actually having git clone invoke each separate Git command, but assuming the whole clone succeeds, the effect is the same as if you manually run each of these commands.3

  1. mkdir target && cd target. The target directory is the one you specify, or the one computed from the URL you give to git clone. See footnote 1 again.

  2. git init, to create the new, empty repository.

    If you use the --bare or --mirror flags, git clone will configure the repository as a bare clone or mirror clone here, as if by running git init --bare instead.

  3. git remote add origin url, so that the name origin identifies the url argument you give to git clone.

    You can get git clone to do additional configuration here as well; see the -c / --config option.

    If you use the -o or --origin flag, you can change the name from origin to any other name you like. The rest of this assumes that you did not.

  4. If you use the --single-branch flag, git config remote.origin.fetch +refs/heads/branch:refs/remotes/origin/branch. This overrides the default that git remote add creates. The default setting tells Git: bring over every branch. This particular setting tells Git: bring over only the one named branch. See footnote 2 here as well.

    In either case, after bringing over each branch tip commit (and all commits reachable from these tips), your Git renames the branches it got from the other Git, so that instead of actual branch names, these become remote-tracking names: refs/remotes/origin/whatever.

    If you use the --mirror option during git clone, Git will override all of these and set the fetch refspec to +refs/*:refs/*. (It's not clear how --mirror should interact with --single-branch.)

  5. git fetch origin: this step actually contacts the other Git—the one at url—and obtains from it the list of references (branch and tag names, and so forth) to get the list of tip commits to bring over. The commits brought over depend on the remote.origin.fetch setting set up in step 4, if any, or the default set up in step 3.

  6. Last, as long as this is not a bare clone (neither --bare nor --mirror), git checkout branch. The argument to the git checkout step is chosen from the best match in this list:4

    • the argument you gave to -b / --branch
    • the branch name recommended by the other Git
    • master

    This git checkout command actually creates your local branch, using the same commit that the copied remote-tracking name identifies. For instance, if you said to check out -b xyz, your git fetch will have brought over their refs/heads/xyz and renamed it to your refs/remotes/origin/xyz. This git checkout then creates your own refs/heads/xyz, pointing to the same commit as your refs/remotes/origin/xyz, which of course points to the commit that their Git has (or had) as their refs/heads/xyz.

    (If you name a tag with your -b option, your Git creates no branches in your own repository.)

Hence, while both -b and --single-branch allow you to pick your own branch name, they have different effects earlier in the sequence of steps that git clone runs.


1The exception to this rule occurs when you run git clone url directory to tell git clone to put the clone into the given but existing directory, e.g., .. For Git to allow this, the given directory must be empty.

2If you use git clone --single-branch (even if it's just implied), Git will clone the particular branch you specify with -b / --branch. If you don't choose one with this option, Git will choose one for you, using the method shown in step 6.

3If the git clone operation fails, Git will clean up after itself, removing the entire new directory, or everything created in the empty directory.

4In order to choose the right branch, your Git has to ask the other Git what its HEAD is. In Git versions before 1.8.5, there is no way to find out. If either Git involved in the cloning process predates 1.8.5, your Git will have the other Git list all its branch names and their hash IDs, and then list the hash ID that goes with their HEAD, and guess which branch that might be. If both Gits are at least 1.8.5, your Git will just get their Git to send you their recommended branch name—there's no need to guess when both Gits support the "read symbolic HEAD" capability.

torek
  • 448,244
  • 59
  • 642
  • 775