Uwe Andersen
Uwe Andersen

Reputation: 337

How to clone a git repository with all branches?

I have a server containing a git repository with several branches. I checked on the server git with "git branch -r" and it displays:
origin/HEAD
origin/develop
origin/neatUI
origin/iOS
... and some more

If I clone this repository with: "git clone [path_to_server]/ATS ATS" I receive a repository just containing "develop". "git branch -a" shows:
* develop
remotes/origin/HEAD -> origin/develop
remotes/origin/develop

All other branches are missing.

If I clone the repository with the --mirror option all branches are present but I cannot work with them. "git branch -a" shows:
remotes/origin/HEAD
remotes/origin/develop
remotes/origin/neatUI
remotes/origin/iOS
... and the rest

If I try to checkout a branch git tells me "fatal: This operation must be run in a work tree"

I also tried "SourceTree" to clone the repoistory but also SourceTree creates only the "develop" branch.

Anyone with an idea?

Upvotes: 11

Views: 17632

Answers (5)

Hedayat Abedijoo
Hedayat Abedijoo

Reputation: 95

1- Install Github CLI

2- Login with your account: gh auth login. follow to the process.

3- Make a folder in any place. example in the root ~/BACKUP_FOLDER_NAME

gh repo list Organizaion_Repo_Name --limit 1000 | while read -r repo _; do   
gh repo clone "$repo" "$repo";
cd "$repo" && for BRANCH in $(git branch -a | grep remotes | grep -v HEAD | grep -v master); do git branch --track "${BRANCH#remotes/origin/}" "${BRANCH}"; done; 
cd "~/BACKUP_FOLDER_NAME";done

Upvotes: -1

ugmurthy
ugmurthy

Reputation: 59

I had a similar problem with repo on github.com with 2 branches. The solution below is based on a demo repository on github.com created solely for the purpose of this answer.

The demo.git repo has two branches named first and second contain only one file README.md the content of which is different each of the branches.

Clone the repository, list the branches, switch to the branch of interest. Note: additional comments below are prefixed with ##

## clone demo repo to local machine
$ git clone git:github.com:ugmurthy/demo.git
Cloning into 'demo'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), done.

$ cd demo

## show local branches
$ git branch
* main

## show remote branches (github.com)
$ git branch -r
  origin/HEAD -> origin/main
  origin/first
  origin/main
  origin/second

## show both local and remote branches
$ git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/first
  remotes/origin/main
  remotes/origin/second


$ cat README.md 
# Demo

## switching branch 
$ git switch first
Branch 'first' set up to track remote branch 'first' from 'origin'.
Switched to a new branch 'first'

## Note that we now have first as a local branch
$ git branch 
* first
  main

$ cat README.md
# Demo
## FIRST BRANCH

$ git switch second
Branch 'second' set up to track remote branch 'second' from 'origin'.
Switched to a new branch 'second'
$ cat README.md 
# Demo
## SECOND BRANCH

$ git branch 
  first
  main
* second

References:

  1. git reference
  2. How to clone a specific branch from github

Upvotes: 0

dmtweigt
dmtweigt

Reputation: 83

I had the same problem. I had previously cloned my repo with --branch <branch-name> or --depth 1 options.
This will set the config entry for remote.origin.fetch to be +refs/heads/<branch-name>:refs/remotes/origin/<branch-name> or +refs/heads/<default-branch>:refs/remotes/origin/<default-branch> respectively.

<default-branch> will usually be main or master or in case of OP develop.

You can check with this command:

git config --get remote.origin.fetch

Replace origin if your remote is named differently, see git remote -v.

You can update the setting with

git config --replace-all remote.origin.fetch +refs/heads/*:refs/remotes/origin/*

You can also edit the config in your configured editor with git config -e.

[remote "origin"]
    url = https://github.com/<some-user>/<some-repo>.git
    fetch = +refs/heads/*:refs/remotes/origin/*

Now git fetch should fetch all the remote branches (and associated tags).

For details see @torek s answer

Upvotes: 1

torek
torek

Reputation: 487755

There are a few separate, but intertwined, key concepts here.

The first is that while Git has branch names, that's not all that Git has (and for that matter, the term branch is ambiguous: see also What exactly do we mean by "branch"?). Git also has tags and what Git calls remote-tracking branch names, and these all fall into a general category called references.

  • A branch name like master is simply a reference whose full name starts with refs/heads/.

  • A remote-tracking branch name like origin/iOS is a reference whose full name starts with refs/remotes/, followed by the name of the remote itself (origin) and another slash. The last part, iOS, is something your Git normally copies from another Git.

    (The remote part of this is an almost-arbitrary string. You can invent your own remote names. However, the fact that the name of the remote gets a slash added afterward is tied to the reason you should be careful about using slashes in your remote names.)

  • To complete this particular list, a tag name like v1.0 is simply a reference whose full name starts with refs/tags/. There are yet more forms of references (refs/notes/ is for Git's git notes, and GitHub uses refs/pull/ for instance) but branch, tag, and remote-tracking branches are all built in, and standard, and most importantly, highly visible—so you should know about them.

When you run git branch, Git finds all your refs/heads/ reference names and shows them with refs/heads/ stripped off. When you run git branch -r, Git finds all your refs/remotes/ references and shows them with refs/remotes/ stripped off. When you run git branch -a, Git finds both, and shows the first with refs/heads/ stripped but shows the second with just refs/ stripped. (Why? Who knows! It's Git being gitty. :-) )

This explains why you see what you see, but not what happens with git clone --mirror, nor why you can git checkout iOS and suddenly have a new refs/heads/iOS; and for that we need two more items, about refspecs (as used with git fetch and git push), and about what Git calls DWIM, or Do What I Mean, in git checkout.

To keep this short: a refspec is just a pair of references, separated by a colon, and sometimes with one part replaced with *. For instance, refs/heads/*:refs/remotes/origin/* is a refspec. You can prefix a refspec with a leading plus sign as well; this sets the --force flag. Both git fetch and git push work with refspecs (and both have a --force flag of their own, which effectively adds a + to any refspecs you give on the command line). The reference before the colon is the source and the reference after the colon is the destination, and this matters because there are two Gits involved in git fetch and git push: yours, and some other Git.

When you git fetch, the source references are the other Git's references and the destination ones are yours. When you git push, the source references are yours and the destination ones are theirs.

Using git clone --mirror tells your Git to set up a bare repository (which I'll leave undefined here) and to set up +refs/*:refs/* as the refspec for git fetch. This copies all the references from the other Git at origin, but it means you cannot have your own branches: your Git is now an exact copy of theirs, and every time you run git fetch you replace everything you have with ... an exact copy of theirs, again.

The main point of most git clone operations is to get an inexact copy of "their Git". The fundamental idea here is that you want all of their branch names to become your remote-tracking branch names. Their master becomes your origin/master; their iOS becomes your origin/iOS.

This leaves no room for their origin/*, because your inexact-copy has its own origin/*. If you want to get their remote-tracking branches, you can—but you need to name them something else!

Once you do have your (non-mirror) clone, and their whatever becomes your origin/whatever, you can git checkout whatever and the DWIM action I mentioned (and linked) above comes into play, creating a new local whatever using your own origin/whatever—which you copied from their whatever!

Upvotes: 9

Mayur Nagekar
Mayur Nagekar

Reputation: 811

Be rest assured if you cloned with git clone <url> all the branches are there in your working tree. You just need to strip origin/ when you want to checkin into other branch. For example, if you want to checkout iOS, do git checkout iOS

git branch -r shows all remote branches on the repository

git branch -a shows remote as well as local branches(if you created any in your local repo)

Upvotes: 1

Related Questions