1. Introduction

One of the major benefits of Git is the ability it provides to create, move, and clone whole organized structures of data along with the history of all changes made to those structures. In fact, we call such bundles repositories. Conversely, modifications within a repository can become very complex, especially with time, so we usually branch out and then merge features in progress.

In this tutorial, we explore ways to get or clone a single branch from a Git repository. First, we briefly refresh our knowledge about Git branches. After that, we use a common git subcommand to extract a single Git branch from a remote repository. Finally, we achieve the same by handling the link to such a remote repository.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15. Unless otherwise specified, it should work in most POSIX-compliant environments.

2. Git Branches

In theory, a Git branch represents a split of a given path at a certain point for separating further modifications into a different path, stemming from the initial one. Usually, the modifications fall under some kind of categorization, such as a feature.

In practice, a branch in Git is just a ref (reference) or pointer to a commit.

Once we create a repository and perform a (root) commit, we already have a branch, the so-called main branch:

$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change.[...]
$ vi file
[...]
$ git add file
$ git commit --all --message 'initial'
[master (root-commit) 2850700] initial
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file

As we can see from the output of init, the actual name of the main branch depends on the Git configuration.

Let’s visualize the repository structure at this point:

(initial)
| HEAD  |
|master |
+-------+
|2850700|
+-------+

Here, we have the initial commit with an identifier that begins with 2850700. This commit starts the master main branch and is the current HEAD, i.e., the latest commit, of that branch.

After several changes, we end up with a more branch-like structure:

                                    | HEAD  |
(initial)                           |master |
+-------+   +-------+   +-------+   +-------+
|2850700|<--|1fb0c0b|<--|84c3441|<--|58404cc|
+-------+   +-------+   +-------+   +-------+

Importantly, the branch pointer always stays with the latest commit of that branch instead of remaining over the root.

At this point, let’s create and check out a branch that stems from the root commit:

$ git checkout -b branch1 2850700

Once we work on that branch for a while, we can already see a tree-like organization:

(initial)                           |master |
+-------+   +-------+   +-------+   +-------+
|2850700|<--|1fb0c0b|<--|84c3441|<--|58404cc|
+-------+   +-------+   +-------+   +-------+
    ^
    |       +-------+   +-------+
    +-------|7b7561d|&lt;--|191f89b|
            +-------+   +-------+
                        |branch1|
                        | HEAD  |

Now that we have a solid understanding of branches, let’s proceed with different ways to extract one from a repository.

3. Using clone for a Single Branch

Perhaps the most basic way to get a copy of a repository is the clone subcommand:

$ git clone https://github.com/Baeldung/tutorials-backup
Cloning into 'tutorials-backup'...
remote: Enumerating objects: 378408, done.
remote: Total 378408 (delta 0), reused 0 (delta 0), pack-reused 378408
Receiving objects: 100% (378408/378408), 352.46 MiB | 16.66 MiB/s, done.
Resolving deltas: 100% (147022/147022), done.
Updating files: 100% (27888/27888), done.
$ cd tutorials-backup

At this point, we have the full tutorials-backup repository locally:

$ du --human-readable --summarize
651M    .
$ git branch --all
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/dkapil-patch-1
  remotes/origin/lor6-patch-1
  remotes/origin/master

With 378408 objects and a total size of 651M in this case, it’s obvious that getting an entire repository when we need a single branch can be costly and unnecessary. Even if we have to download most of the data, resolving dependencies and deltas can take longer, and we’d have metadata that we might not need.

Let’s see a way to isolate a –single-branch with clone:

$ git clone --single-branch --branch lor6-patch-1 https://github.com/Baeldung/tutorials-backup lor6-patch-1
Cloning into 'lor6-patch-1'...
remote: Enumerating objects: 377517, done.
remote: Counting objects: 100% (3241/3241), done.
remote: Compressing objects: 100% (258/258), done.
remote: Total 377517 (delta 3127), reused 2983 (delta 2983), pack-reused 374276
Receiving objects: 100% (377517/377517), 352.16 MiB | 16.67 MiB/s, done.
Resolving deltas: 100% (146596/146596), done.
Updating files: 100% (27828/27828), done.
$ cd lor6-patch-1
$ git branch --all
* lor6-patch-1
  remotes/origin/lor6-patch-1

This way, we only get the branch of interest, downloading just 377517 objects. When it comes to minor branches, this number can be drastically reduced.

Further, if we aren’t interested in the full history around a branch, there is a way to reduce the data, size, and processing time even more:

$ git clone --single-branch --branch $BRANCH --depth 1 $REPOSITORY $BRANCH

In this case, we add the –depth parameter to get a shallow copy of the requested branch. Notably, –depth implies –single-branch.

Let’s see the space reduction in our case:

$ git clone --single-branch --depth 1 --branch lor6-patch-1 https://github.com/Baeldung/tutorials-backup lor6-patch-1
Cloning into 'lor6-patch-1'...
remote: Enumerating objects: 50196, done.
remote: Counting objects: 100% (50196/50196), done.
remote: Compressing objects: 100% (34846/34846), done.
remote: Total 50196 (delta 7204), reused 43024 (delta 4741), pack-reused 0
Receiving objects: 100% (50196/50196), 47.43 MiB | 16.68 MiB/s, done.
Resolving deltas: 100% (7204/7204), done.
Updating files: 100% (27828/27828), done.

Thus, we received less than 15% of the data we had to get with the other method.

4. Using remote With a Single Branch

The remote subcommand of git enables us to link a local and a remote repository for synchronization. Until we add a so-called remote in the form of a URL, the current repository has a single copy, and it’s local.

Let’s [init]ialize a new empty local repository and link it:

$ git init && git remote add --fetch origin https://github.com/Baeldung/tutorials-backup

This way, we perform several steps:

  • initialize a new empty local repository
  • add a new remote from the repository at https://github.com/Baeldung/tutorials-backup
  • name the new remote as origin, by convention
  • –fetch all the data and metadata, such as branches

However, there is a way to only synchronize a single remote branch:

$ git init && git remote add -t lor6-patch-1 -f origin https://github.com/Baeldung/tutorials-backup 

Further, we can specify -t several times with different branches to only track these parts of the repository:

$ git init && git remote add -t $BRANCH [-t $BRANCH2 ... -t $BRANCHn] -f origin https://github.com/Baeldung/tutorials-backup

Another benefit of this approach is that any remote operations such as push or pull continue to only work on the branch or branches specified with -t.

5. Summary

In this article, we looked at methods to get a single branch from a remote Git repository.

In conclusion, although there are several ways to extract one branch from a Git repository, our choice depends on the time, size, and metadata optimization we want to achieve.