如何获取所有的Git分支?

2285

我克隆了一个包含许多分支的Git代码库。然而,git branch 只显示了一个分支:

$ git branch
* master

如何在本地拉取所有分支,使得执行git branch命令时显示以下结果?

$ git branch
* master
* staging
* etc...

3
这个问题展示了如何在使用--single-branch克隆设置后获取所有分支:https://dev59.com/e2Mm5IYBdhLWcg3wT9mU(如果您只指定了一个分支,则`git fetch --all`永远不会起作用!) - Matthew Wilcoxson
3
您将永远看不到那个输出,因为星号代表当前所选的分支。由于一次只能有一个分支被选中,因此您的分支列表左侧只能有一个星号。 - Robino
1
下面排名最高的答案没能满足提问者的意图。我建议您查看 https://dev59.com/YXVD5IYBdhLWcg3wKYP-#72156。`git checkout -b <branch>` 看起来是最可能的答案。 - Reece
9
我看到了很多答案,但没有一个提到我认为可能是实现你想要的最简单方式:git clone --bare <repo url> .git (请注意,在克隆存储库时需要添加“--bare”和“.git”作为“bare”存储库),然后运行git config --bool core.bare false(将“bare”标志设置为false),接着执行git reset --hard(将HEAD移动到存储库的当前HEAD)。现在,如果你运行git branch,你应该能够看到从所克隆的存储库中获取的所有分支。 - Gabriel Ferraz
6
那么你正在滥用 Stack Overflow 上的评论功能。用户可以给你的评论点赞,但不能踩。 - pipe
显示剩余5条评论
35个回答

31

如果您正在寻找一种解决方案,以获取所有分支,然后将所有内容迁移到另一个Git服务器,请按照以下步骤操作。如果您仅想在本地获取所有更新的分支,请在第一个空行处停止。

git clone <ORIGINAL_ORIGIN>
git branch -r | awk -F'origin/' '!/HEAD|master|main/{print $2 " " $1"origin/"$2}' | xargs -L 1 git branch -f --track 
git fetch --all --prune --tags
git pull --all

git remote set-url origin <NEW_ORIGIN>
git pull
<resolve_any_merge_conflicts>
git push --all
git push --tags
<check_NEW_ORIGIN_to_ensure_it_matches_ORIGINAL_ORIGIN>

3
非常有帮助,正是我所需要的。唯一需要更改的是在第二行加上单引号,将'HEAD'和'master'括起来;可能是因为我使用的是zsh。谢谢! - sockmonk
基本上,这是在做以下操作:(1)获取远程分支的实际名称[不是head,也不是master];(2)完全告诉Git去跟踪它们[不是所有的解决方案都这样做];(3)从这些分支中获取和拉取所有内容[包括标签];(4)设置一个新的起点并遍历推送绝对所有内容。再次强调,大多数其他解决方案都无法移动所有文件,而这个方法可以实现全部。 - ingyhere
1
我移除了运行grep然后awk的反模式,并将grep命令压缩到awk命令中。感谢tripleee - ingyhere
阅读此内容,永远不要编写“git fetch git pull” https://dev59.com/8XVC5IYBdhLWcg3wcgqd#292359 - Green
Git的pull确实会首先执行fetch,但当独立地执行fetch时,更容易确定问题是来自pullfetch部分还是后续的merge部分。 - ingyhere
秘密酱是第二行(有时我在仓库上运行此命令以在本地创建所有远程分支):git branch -r | awk -F'origin/' '!/HEAD|master|main/{print $2 " " $1"origin/"$2}' | xargs -L 1 git branch -f --track - ingyhere

31

由于您没有跟踪它们,因此您看不到远程分支。

  1. 确保您正在跟踪所有远程分支(或者您想要跟踪的分支)。
  2. 更新本地分支以反映远程分支。

跟踪所有远程分支:

跟踪远程存储库中存在的所有分支。

手动执行:

您将使用 git branch -r 命令的输出中显示的分支名称替换 <branch>。

git branch -r
git branch --track <branch>

用bash脚本来完成:

for i in $(git branch -r | grep -vE "HEAD|master"); do git branch --track ${i#*/} $i; done

懒人的方法(这可能会因为合并冲突导致混乱,请小心):

git checkout master
git pull

更新本地计算机上远程分支的信息:

这将从您在本地存储库中跟踪的远程存储库中获取分支更新。这不会更改您的本地分支。您的本地 Git 存储库现在已经知道了远程存储库分支所发生的事情。例如,如果将新提交推送到远程主分支,则执行 fetch 现在将提示您,您的本地主分支已滞后 1 个提交。

git fetch --all

更新本地计算机上关于远程分支的信息并更新本地分支:

执行从远程到本地分支所有分支的获取操作,然后合并它们。例如,如果新提交被推送到远程主分支,则执行拉取操作将会更新本地仓库中关于远程分支的更改,并将这些更改合并到本地分支中。这可能会因为合并冲突而导致问题。

git pull --all

单个字符的变量容易混淆。我建议使用以下代码: for remoteBranch in $(git branch -r | grep -vE "HEAD|master"); do git branch --track ${remoteBranch#*/} $remoteBranch; done - A. Rick
通过使用 xargs 而不是 for 循环,您将根本不需要任何变量。 - bjhend
@bjhend,您能写一个例子吗?我很乐意更新! - basickarl
@basickarl 我会用类似 git branch -r | grep -vE "HEAD|master" | xargs -I remoteBranch -n 1 echo ...remoteBranch... 的命令替换循环,其中 echogit branch 命令替换,但我现在发现需要使用某种 sed 命令来删除 remoteBranch 中的远程分支,这可能会使它变得更加复杂。 - bjhend
这似乎给我制造了一个混乱局面。我相信需要提到的是,在每一轮命令之前,需要检出一个适当的分支。 - MadPhysicist

20

我相信你已经通过以下方式克隆了代码库:

git clone https://github.com/pathOfrepository

现在使用cd命令进入该文件夹:

cd pathOfrepository

如果你输入 git status ,你可以看到所有内容:

   On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

查看所有隐藏的分支类型:

 git branch -a

它将列出所有远程分支。

现在,如果您想要检出任何特定的分支,只需输入:

git checkout -b localBranchName origin/RemteBranchName

18

确保在.git/config文件中所有远程分支都是可获取的。

在这个例子中,只有origin/production分支是可获取的,即使你尝试执行git fetch --all,也只会获取production分支:

[origin]
fetch = +refs/heads/production:refs/remotes/origin/production

这一行需要被替换为:

[origin]
fetch = +refs/heads/*:refs/remotes/origin/*

然后运行git fetch等等...


3
检查:git config --get remote.origin.fetch,然后(具有破坏性地)设置它为:git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' - qneill
或者修改.git目录下的配置文本文件,这对我有用。 - FDIM

14

在你克隆主版本库之后,你只需要执行

git fetch && git checkout <branchname>

1
简单。并且成功地从远程源获取了一个分支。 - sirvon
5
这并没有回答原始问题:“如何将所有分支都拉到本地?” 这是一个一个地拉取它们,这种方法不具有可扩展性。考虑到有100个分支的情况。 - ingyhere

11

只需这三个命令即可获取所有分支:

git clone --mirror repo.git  .git     (gets just .git  - bare repository)

git config --bool core.bare false

git reset --hard

这实际上是 OP 问题的根源。如果克隆正确,他就不需要执行 pull --all。但如果仍然需要,那么下面另一个回答,由 @Johnno Nola 提供,假设所有分支都被跟踪,结合这个答案,是正确的方法。 - DrBeco

11

如何获取追踪单个远程的所有Git分支。

此方法已在Red Hat和Windows 10上的Git Bash上进行了测试并成功运行。


简述:

for branch in `git branch -r|grep -v ' -> '|cut -d"/" -f2`; do git checkout $branch; git fetch; done;

解释:

这个单行命令检查并获取除HEAD以外的所有分支。

列出远程跟踪分支。

git branch -r

忽略 HEAD。

grep -v ' -> '

将远程分支的名称删除。

cut -d"/" -f2

查看所有跟踪单个远程的分支。

git checkout $branch

获取已签出分支的内容。

git fetch

从技术上讲,新的本地分支不需要进行fetch。

这可以用于拉取或获取那些既是新分支又在远程分支中有更改的分支。

只需确保您仅在准备好合并时才执行pull操作。


测试设置

使用SSH URL检出存储库。

git clone git@repository.git

在此之前

检查本地分支。

$ git branch
* master

执行命令

执行单行命令。

for branch in `git branch -r|grep -v ' -> '|cut -d"/" -f2`; do git checkout $branch; git fetch; done;

检查本地分支是否包含远程分支。

$ git branch
  cicd
  master
* preprod

10

我尝试了循环,但好像没起作用,而且我想忽略 origin/master。以下是我成功的方法。

git branch -r | grep -v HEAD | awk -F'/' '{print $2 " " $1"/"$2}' | xargs -L 1 git branch -f --track

之后:

git fetch --all
git pull --all

1
这个变化是正确答案的一个变体,但在所有边缘情况下都不起作用。此外,分支名称可能很奇怪。所以我做了以下操作:git branch -r | grep -v HEAD | grep –v master | awk -F'origin/' '{print $2 " " $1"origin/"$2}' | xargs -L 1 git branch -f --track ; git fetch --all ; git pull --all ; 然后就解决了! - ingyhere
3
为了避免使用 grep | awk 的反模式,可以进行风格上的改进:git branch -r | awk -F 'origin/' '!/HEAD|master/{ ... 可以翻译为:对于避免使用 grep | awk 的反模式进行风格上的改进,可以使用以下命令:git branch -r | awk -F 'origin/' '!/HEAD|master/{ ...。 - tripleee

9

对于使用 PowerShell 的 Windows 用户:

git branch -r | ForEach-Object {
    # Skip default branch, this script assumes
    # you already checked-out that branch when cloned the repo
    if (-not ($_ -match " -> ")) {
        $localBranch = ($_ -replace "^.*?/", "")
        $remoteBranch = $_.Trim()
        git branch --track "$localBranch" "$remoteBranch"
    }
}; git fetch --all; git pull --all

这适用于名字带 / 的分支:git branch -r | ForEach-Object { # 跳过默认分支,此脚本假设 # 克隆存储库时已经检出该分支 if (-not ($_ -match " -> ")) { $localBranch = ($_ -replace "^.*?/", "") $remoteBranch = $_.Trim() git branch --track "$localBranch" "$remoteBranch" } } - Markus

6
这是我认为比较健壮的内容:
  • 不会更新已有分支的远程跟踪
  • 不会尝试将HEAD更新为跟踪origin/HEAD
  • 允许使用名称不同于origin的远程仓库
  • 正确地进行了Shell引用
for b in $(git branch -r --format='%(refname:short)'); do
  [[ "${b#*/}" = HEAD ]] && continue
  git show-ref -q --heads "${b#*/}" || git branch --track "${b#*/}" "$b";
done
git pull --all

不需要执行 git fetch --all 命令,因为在使用 git pull 命令时,会将 -all 参数传递给内部的 fetch 命令。感谢这个回答的提供者。

我正在尝试在另一种脚本语言(TypeScript)中复制这个操作,但不理解 ${b#*/} 这个 bash 语法的含义 - 请问有人可以解释一下吗? - kevstev01
发现了一个有用的资源 https://devhints.io/bash,其中显示 ${STR#*/} 扩展为 STR 的完整路径(即上面代码中的 b)。 - kevstev01
另外请注意,从Windows的cmd提示符中,git branch -r --format='%(refname:short)'将输出引号('),因此请使用双引号:git branch -r --format="%(refname:short)" - kevstev01

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