如何克隆一个包含所有分支的git代码库?

10
我有一个包含多个分支的git存储库服务器。 我在服务器上使用“git branch -r”检查它,显示如下:
origin/HEAD
origin/develop
origin/neatUI
origin/iOS
...还有更多其他的
如果我用以下命令克隆这个存储库:"git clone [path_to_server]/ATS ATS",那么我只会得到一个包含"develop"的存储库。 "git branch -a" 显示如下:
* develop
remotes/origin/HEAD -> origin/develop
remotes/origin/develop
所有其他的分支都没有了。
如果我使用--mirror选项克隆存储库,所有分支都存在,但我不能使用它们。 "git branch -a" 显示如下:
remotes/origin/HEAD
remotes/origin/develop
remotes/origin/neatUI
remotes/origin/iOS
...以及其余部分
如果我尝试检出一个分支,Git会告诉我 "fatal: This operation must be run in a work tree"
我也尝试了“SourceTree”来克隆存储库,但是它也只创建了“develop”分支。
请问有人有想法吗?

镜像克隆是一个裸克隆,你不能在其中检出分支。 - Lasse V. Karlsen
你有一个服务器仓库。在该仓库中运行 git branch -r 命令不会列出该仓库中的分支,而是列出远程分支。例如,developiOSneatUI 都是从其他仓库克隆到你的服务器仓库中的分支。要列出服务器仓库中的分支,应该只运行 git branch 命令,不需要 -r 标志。 - Alderath
git分支只显示“develop”。看起来你走在了正确的轨道上! :) 我该如何添加其他分支? - Uwe Andersen
你可以将服务器仓库的源作为远程仓库添加到新克隆的仓库中: git remote add origin2 <url from which your remote repo was cloned> (这里的 origin2 只是一个名称,你可以选择任何你想要的名称)。然后你可以从该远程仓库获取分支 git fetch origin2。之后,在你的克隆仓库中执行 git branch -r,你应该会看到两个远程仓库的远程跟踪分支:origin/develop origin2/develop origin2/neatUI origin2/iOS - Alderath
完美!我必须承认,我没有使用命令,而是在"git gui"中实现了它。我在git gui中解决了它,通过:创建新分支 > 激活"匹配跟踪分支名称" > 从"跟踪分支"列表中选择所需的分支。 非常感谢您指点我正确的方向! - Uwe Andersen
5个回答

9
这里有几个相互关联的关键概念。
首先,虽然 Git 有“分支名称”,但 Git 不仅仅只有这些(而且说实话,“分支”这个术语是有歧义的:另请参见我们所说的“分支”到底是什么?)。Git 还有“标签”和 Git 所称的“远程跟踪分支名称”,所有这些都属于一个通用类别,称为“引用”。
  • 类似于master的分支名称只是一个引用,其全名以refs/heads/开头。

  • 类似于origin/iOS的远程跟踪分支名称是一个引用,其全名以refs/remotes/开头,后跟远程名称(origin)和另一个斜杠。最后一部分iOS通常是从其他Git中复制的。

    (远程部分是几乎任意的字符串。您可以发明自己的远程名称。但是,远程名称后面添加斜杠的事实与您在远程名称中使用斜杠时应该小心的原因有关。)

  • 要完成此特定列表,类似于v1.0的标签名称只是一个引用,其全名以refs/tags/开头。还有更多形式的引用(refs/notes/用于Git的git notes,GitHub例如使用refs/pull/),但是分支、标签和远程跟踪分支都是内置的、标准的,而且最重要的是高度可见的,所以您应该了解它们。

当您运行git branch时,Git会查找所有的refs/heads/参考名称,并将它们显示出来,但会剥离refs/heads/。当您运行git branch -r时,Git会查找所有的refs/remotes/参考名称,并将它们显示出来,但会剥离refs/remotes/。当您运行git branch -a时,Git会同时查找这两个并将第一个以refs/heads/剥离后显示,但将第二个仅以refs/剥离后显示。(为什么?谁知道!这就是Git的性格。 :-))
这就是为什么你看到的是什么,但不知道使用 git clone --mirror 发生了什么,也不知道为什么可以 git checkout iOS 突然出现一个新的 refs/heads/iOS;为此,我们需要两个更多的项目,关于refspecs(与git fetchgit push一起使用),以及关于Git在git checkout中所谓的DWIM,或Do What I Mean。 简而言之:一个refspec只是由冒号分隔的一对引用,有时会用*替换其中一部分。例如,refs/heads/*:refs/remotes/origin/*是一个refspec。您也可以在refspec前加上加号;这会设置--force标志。git fetchgit push都与refspecs一起使用(并且两者都有自己的--force标志,它有效地在命令行上给出任何refspecs添加了一个+)。冒号前的引用是源,冒号后的引用是目标,这很重要,因为在 git fetch git push 中涉及到两个 Git:您的Git和其他Git。
当您git fetch时,源引用是其他Git的引用,目标引用是您的引用。当您git push时,源引用是您的引用,目标引用是他们的引用。
使用git clone --mirror告诉您的Git设置一个仓库(这里我不做解释),并将+refs/*:refs/*设置为git fetch的refspec。这会复制来自origin所有引用,但这意味着您无法拥有自己的分支:您的Git现在是他们的精确副本,每次运行git fetch时,您都会替换您拥有的一切内容...再次成为他们的精确副本。

大多数git clone操作的主要目的是获取"他们的Git"的不完全副本。基本思想在于,您希望所有他们的分支名称成为您的远程跟踪分支名称。他们的master变成了您的origin/master;他们的iOS变成了您的origin/iOS

这样做就没有空间留给它们的origin/*,因为你的非精确复制有自己的origin/*。如果你想获取它们的远程跟踪分支,可以 - 但你需要给它们起一个不同的名字!

一旦你拥有了你的(非镜像)克隆版本,并且他们的whatever变成了你的origin/whatever,你可以git checkout whatever,然后我上面提到的DWIM操作(并链接)就会发挥作用,使用你自己从他们的whatever复制的origin/whatever创建一个新的本地whatever


5
这是一个很棒的关于Git概念的解释,回答了他们关于Y的问题。但是它并没有以任何方式回答关于问题X的原始问题:如何获取一个具有与所有远程分支状态匹配的本地分支的克隆。 - Atemu
1
@Atemu:那是因为答案是“不要这样做”。 :-) (第二个答案是:如果你必须这样做,请使用git clone --mirror,然后不要在克隆中工作。) - torek

1

如果你使用 git clone <url> 克隆代码库,可以放心,所有分支都在你的工作树中。当你想要切换到其他分支时,只需要去掉 origin/ 前缀就行了。例如,如果你想要切换到 iOS 分支,执行 git checkout iOS 命令。

git branch -r 显示代码库上的所有远程分支。

git branch -a 显示所有远程分支,以及本地代码库中创建的分支(如果有的话)。


如果我只是克隆repo(没有--mirror),那么就没有iOS分支。 “git checkout iOS”会产生“错误:pathspec 'iOS'不匹配git已知的任何文件”。 - Uwe Andersen
你是如何切换分支的? - Mayur Nagekar
我怎样才能确保所有的分支都在那里?就像我之前说的,“git branch -a”只显示“develop”... - Uwe Andersen
如果你能看到分支 git branch -r,只需检出你想要的那个即可。 - Mayur Nagekar
我看不到它们。 "git branch -r" 只显示了 develop。 - Uwe Andersen
显示剩余2条评论

1

我有同样的问题。 我之前用 --branch <分支名>--depth 1 选项克隆了我的存储库。
这将设置配置条目 remote.origin.fetch+refs/heads/<分支名>:refs/remotes/origin/<分支名>+refs/heads/<默认分支>:refs/remotes/origin/<默认分支>

<默认分支> 通常会是 mainmaster,或者在 OP 的情况下是 develop

您可以使用以下命令检查:

git config --get remote.origin.fetch

如果您的远程命名不同,请使用git remote -v查看并替换origin

您可以使用以下方式更新设置

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

您还可以使用git config -e在配置的编辑器中编辑配置。

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

现在git fetch应该可以获取所有远程分支(以及相关的标签)。
详细信息请参见@torek的回答

0

我在 github.com 上的 repo 中遇到了类似的问题,该 repo 有两个分支。下面的解决方案基于一个 演示 repository,该 repository 是为了回答这个问题而创建的。

demo.git repo 有两个名为 firstsecond 的分支,每个分支只包含一个文件 README.md,其内容在每个分支中都不同。

克隆该 repository,列出分支,切换到所需的分支。 注意:以下附加注释以 ## 为前缀。

## 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

参考资料:

  1. Git 参考手册
  2. 如何从 Github 克隆特定分支

-1

1- 安装 Github CLI

2- 使用您的帐户登录:gh auth login。按照流程操作。

3- 在任何地方创建一个文件夹。例如在根目录下创建 ~/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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接