如何将缺失的分支添加到克隆存储库的克隆中?
How do you add missing branches to a clone of a cloned repository?
git clone 和 git clone --mirror 完全不同:
标准 git 克隆可以用作工作区。
源已知的一组分支可供检查和处理。
镜像更像是备份。您不能直接将其用作工作区。
现在假设您克隆了一个已经被克隆的存储库
根据这个问题:
生成的存储库 (clone2) 只有在第一个克隆 (clone1) 中使用过的分支。但是,clone1 仍然知道起源处的分支。有没有办法将 clone1 已知的分支添加到 clone2 而无需将(原始)原点设置为远程?
如果不清楚,我们有:
repo1:
- 分支 1
- 分支 2
- 分支 3
- 分支 4
clone1 = git 克隆 repo1.git:
- 分支 1 - 签出
- branch2 - 之前签出
- branch3 - 未签出但可以随时签出
- branch4 - 未签出但可以随时签出
clone2 = git 克隆 clone1.git:
- 分支 1 - 签出
- branch2 - 未签出但可以随时签出
clone2 似乎不了解 branch3 或 branch4,因此无法检查它们。
我们如何从 clone1 获取该信息?
其实这里有两个问题:
- 我们如何获取有关从 clone1 到 clone2 的一个分支的信息?
- 我们如何获取有关从 clone1 到 clone2 的所有可能分支的信息?
我相信 branch3 和 branch4 可用于 clone1 而 repo1 处于离线状态。
有几个用例:
- repo1 不可用,我们希望重新创建它
(如果您知道从 clone1 重新创建 repo1 的方法,则加分)
- repo1 暂时不可用,我们希望在不同的分支上工作
从已经克隆了 repo1 的人那里获取该信息。
- 在将它们推送到共享存储库 (repo1) 之前测试一些涉及存储库黑客攻击的更改。
我相信这应该没什么区别,但我正在使用本地文件而不是 URL 对此进行测试。所以clone2实际上是通过git clone /local/path/.git
制作的
更新
有一个我最初没有注意到并报告的并发症:
git分支-r
在 clone2 上应该按照答案中的建议将 clone1 上的分支列为 origin/branch3 和 origin/branch4 。但是,对于这个特定的回购协议,它没有。不知道为什么。
这个 repo 的特殊之处包括:
- 使用.git/refs/replace
用 git pull origin 'refs/replace/*:refs/replace/*' 拉替换没有区别。
还有其他建议吗?
我已经确定了 git branch -r 工作的回购和不工作的回购之间可能存在的显着差异。
clone1 和 clone2 都应该在 .git/packed-refs 中列出遥控器,其中的行类似于 (/path/to/clone1/.git/packed-refs):
2c3c761fbac82556c2178cb28a4e728360093e67 refs/remotes/origin/branch1
出于某种原因,受影响存储库上的 clone2 没有 .git/packed-refs 中应有的所有条目。
我检查了 packed-ref 文件(在 clone2 中)引用的一些提交 ID 存在于克隆的存储库 packed-ref(clone2)中,但有些不存在。
我们似乎既失去又获得了分支!
如果我实验性地将 packed-ref 文件从 clone1 复制到 clone2,分支会出现在
git branch -r
下,它们可以被签出,但会导致分离头状态。
这是 'affected' 存储库的 git 配置。
>cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = /path/to/clone1/.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "develop"]
remote = origin
merge = refs/heads/develop
用于抓取所有远程跟踪分支的 [https://git.wiki.kernel.org/index.php|standard 说明] 即使对于损坏的 repo 也有效:
git clone --mirror original-repo.git /path/cloned-directory/.git
cd /path/cloned-directory
git config --bool core.bare false
git checkout anybranch
因此,即使是损坏的存储库也有多种解决方法。
Git 可以有多个远程连接。它不像其他一些类似系统那样仅限于单个主存储库。您可以将 repo1 添加为另一个远程存储库:
git remote add repo1 /path/to/your/original/complete/repository
然后你就可以像往常一样得到你的分支了:
git fetch repo1 branch3
git fetch repo1 branch4
如果需要,您稍后可以签出以进行处理:
git checkout branch4
首先:您只能看到上次 git fetch
或 git pull
.
时的 repo1
视图
repo1
中存在的所有分支将存储在 clone1
中的 origin
下。
您可以列出这些分支:git branch -r
。
在我看来,您正在查看具有 --mirror
和不具有克隆的非常不同的典型用例,让您认为它们根本不同。其实它们只是一个更普遍的事物的常用特例。
这主要是题外话,但我认为如果你研究 git 概念并着眼于真正理解上述陈述,那么其余部分可能也会更加清晰。
所以:在clone1
中,其他分支的"knowledge"是remote branch refs的形式(refs/remotes/origin/branch3
, ...)检出的分支有,此外,"local" 分支引用 (refs/heads/branch1
, ...)。克隆(无论是镜像还是其他)中使用的默认 refspec 设置为获取 refs/heads/*
。 (区别在于 mirror
在本地将它们映射为 refs/heads/*
而 "regular" 克隆默认将它们映射到 refs/remotes/origin/*
。)
您可以在 clone2
中设置 refspec - 通过设置,或在特定 fetch
或 pull
的参数中 - 从中读取 refs/remotes/origin/*
引用clone1
。但是还有一些问题需要思考。
首先,如果您要从 clone1
映射本地和远程引用,那么您需要在 clone2
中为它们提供不同的命名空间。也就是说,clone1
中的 refs/heads/master
与 clone1
中的 refs/remotes/origin/master
不同,它们可能在任何给定时间引用不同的提交;所以他们不能 both 映射到 clone2
.
中的相同名称
其次,clone2
关于 - 例如 - branch3
的知识在这一点上是相当间接的。 "The last time I spoke to clone1
, it told me that the last time it spoke to repo1
, branch3
was at commit XYZ
." 了解 branch3
"from the horse's mouth" 可能更有意义。您可以通过在 clone2
.
上添加 repo1
作为第二个遥控器来做到这一点
无论您是通过添加 repo1
作为来源,还是通过使用非默认 refspecs 从 clone1
复制信息,最终在 clone2
中您将拥有对应于某些分支名称的多个远程引用(例如 refs/remotes/origin/branch3
和 refs/remotes/repo1/branch3
)。这意味着可能并不总是很清楚哪个分支应该被视为本地 refs/heads/branch3
的 "upstream"。您可以通过配置来管理它,and/or 通过特定 push
和 fetch
命令的参数来告诉他们您在该实例中作为上游的意图。
将所有这些转化为特定的命令实际上取决于您要完成的任务;有太多的可能性,无法将它们全部列出并解释何时使用其中任何一个。如果您需要那种程度的详细信息,我建议您可以从 git config
、git fetch
、git push
以及 git pull
的文档开始。
这应该是一条评论,但我需要格式化,我无法在评论中做到这一点(而且又变得冗长了:-))。
除了 (这是正确的,你应该阅读它),我认为,你的措辞中的这一点揭示了理解这一点的关键:
branch3 - not checked out [on clone1] but can be at any time
关键是在这个状态下,branch3不存在.
这是我在其他答案中说过的话,我会重复:远程跟踪分支不是分支。它是远程跟踪分支名称:名称,如origin/branch3
,是以refs/remotes/
开头的全名的缩写形式(与分支名称[=49相比) =] 就像 branch3
一样,它是以 refs/heads/
).
开头的全名的缩写形式
(事实上,"a branch"在Git中并不总是"a branch",因为Git作者习惯用不同的词重用相同的词含义——公平地说,这在英语中也一直存在,这是我们获得 puns. See also What exactly do we mean by "branch"? 的一种方式,在这种特殊情况下,我们所说的 "a branch" 是一个分支 name ,即全名以refs/heads/
开头的引用。)
当您要求 git checkout
签出一个不存在的分支时,例如 branch3
,Git 将扫描您所有的远程跟踪分支名称。如果恰好有 "resembles" branch3
正确,git checkout
将 创建 一个,使用远程跟踪分支名称派生新分支的初始哈希 ID 值。
对于存储库中存在的分支名称,该存储库必须有一个全名以 refs/heads/
开头的引用。第二个斜线之后出现的是分支的名称。要列出某些存储库中的所有引用,运行 git for-each-ref
,其默认输出是每个引用的列表、其哈希 ID 以及由该哈希标识的 Git 对象的类型。
当你制作一个克隆时,你告诉你的 Git——制作克隆的那个——如何操作它从另一个 Git 获得的引用。这是 --mirror
所做的关键:它说 使用他们的引用来制作我的引用,根本没有任何更改。 普通克隆不会那样做,因为一旦你做 那样做,当你从另一个 Git 重新获取时,你会遇到问题:你已经完全被它奴役了;您在自己的副本中更改的任何引用,您用它们的值替换您的值,并且 return 成为纯副本。
git clone 和 git clone --mirror 完全不同:
标准 git 克隆可以用作工作区。 源已知的一组分支可供检查和处理。
镜像更像是备份。您不能直接将其用作工作区。
现在假设您克隆了一个已经被克隆的存储库
根据这个问题:
生成的存储库 (clone2) 只有在第一个克隆 (clone1) 中使用过的分支。但是,clone1 仍然知道起源处的分支。有没有办法将 clone1 已知的分支添加到 clone2 而无需将(原始)原点设置为远程?
如果不清楚,我们有:
repo1:
- 分支 1
- 分支 2
- 分支 3
- 分支 4
clone1 = git 克隆 repo1.git:
- 分支 1 - 签出
- branch2 - 之前签出
- branch3 - 未签出但可以随时签出
- branch4 - 未签出但可以随时签出
clone2 = git 克隆 clone1.git:
- 分支 1 - 签出
- branch2 - 未签出但可以随时签出
clone2 似乎不了解 branch3 或 branch4,因此无法检查它们。 我们如何从 clone1 获取该信息?
其实这里有两个问题:
- 我们如何获取有关从 clone1 到 clone2 的一个分支的信息?
- 我们如何获取有关从 clone1 到 clone2 的所有可能分支的信息?
我相信 branch3 和 branch4 可用于 clone1 而 repo1 处于离线状态。
有几个用例:
- repo1 不可用,我们希望重新创建它 (如果您知道从 clone1 重新创建 repo1 的方法,则加分)
- repo1 暂时不可用,我们希望在不同的分支上工作 从已经克隆了 repo1 的人那里获取该信息。
- 在将它们推送到共享存储库 (repo1) 之前测试一些涉及存储库黑客攻击的更改。
我相信这应该没什么区别,但我正在使用本地文件而不是 URL 对此进行测试。所以clone2实际上是通过git clone /local/path/.git
制作的更新
有一个我最初没有注意到并报告的并发症: git分支-r 在 clone2 上应该按照答案中的建议将 clone1 上的分支列为 origin/branch3 和 origin/branch4 。但是,对于这个特定的回购协议,它没有。不知道为什么。
这个 repo 的特殊之处包括:
- 使用.git/refs/replace
用 git pull origin 'refs/replace/*:refs/replace/*' 拉替换没有区别。
还有其他建议吗?
我已经确定了 git branch -r 工作的回购和不工作的回购之间可能存在的显着差异。
clone1 和 clone2 都应该在 .git/packed-refs 中列出遥控器,其中的行类似于 (/path/to/clone1/.git/packed-refs):
2c3c761fbac82556c2178cb28a4e728360093e67 refs/remotes/origin/branch1
出于某种原因,受影响存储库上的 clone2 没有 .git/packed-refs 中应有的所有条目。
我检查了 packed-ref 文件(在 clone2 中)引用的一些提交 ID 存在于克隆的存储库 packed-ref(clone2)中,但有些不存在。 我们似乎既失去又获得了分支!
如果我实验性地将 packed-ref 文件从 clone1 复制到 clone2,分支会出现在
git branch -r下,它们可以被签出,但会导致分离头状态。
这是 'affected' 存储库的 git 配置。
>cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] url = /path/to/clone1/.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "develop"] remote = origin merge = refs/heads/develop
用于抓取所有远程跟踪分支的 [https://git.wiki.kernel.org/index.php|standard 说明] 即使对于损坏的 repo 也有效:
git clone --mirror original-repo.git /path/cloned-directory/.git cd /path/cloned-directory git config --bool core.bare false git checkout anybranch
因此,即使是损坏的存储库也有多种解决方法。
Git 可以有多个远程连接。它不像其他一些类似系统那样仅限于单个主存储库。您可以将 repo1 添加为另一个远程存储库:
git remote add repo1 /path/to/your/original/complete/repository
然后你就可以像往常一样得到你的分支了:
git fetch repo1 branch3
git fetch repo1 branch4
如果需要,您稍后可以签出以进行处理:
git checkout branch4
首先:您只能看到上次 git fetch
或 git pull
.
repo1
视图
repo1
中存在的所有分支将存储在 clone1
中的 origin
下。
您可以列出这些分支:git branch -r
。
在我看来,您正在查看具有 --mirror
和不具有克隆的非常不同的典型用例,让您认为它们根本不同。其实它们只是一个更普遍的事物的常用特例。
这主要是题外话,但我认为如果你研究 git 概念并着眼于真正理解上述陈述,那么其余部分可能也会更加清晰。
所以:在clone1
中,其他分支的"knowledge"是remote branch refs的形式(refs/remotes/origin/branch3
, ...)检出的分支有,此外,"local" 分支引用 (refs/heads/branch1
, ...)。克隆(无论是镜像还是其他)中使用的默认 refspec 设置为获取 refs/heads/*
。 (区别在于 mirror
在本地将它们映射为 refs/heads/*
而 "regular" 克隆默认将它们映射到 refs/remotes/origin/*
。)
您可以在 clone2
中设置 refspec - 通过设置,或在特定 fetch
或 pull
的参数中 - 从中读取 refs/remotes/origin/*
引用clone1
。但是还有一些问题需要思考。
首先,如果您要从 clone1
映射本地和远程引用,那么您需要在 clone2
中为它们提供不同的命名空间。也就是说,clone1
中的 refs/heads/master
与 clone1
中的 refs/remotes/origin/master
不同,它们可能在任何给定时间引用不同的提交;所以他们不能 both 映射到 clone2
.
其次,clone2
关于 - 例如 - branch3
的知识在这一点上是相当间接的。 "The last time I spoke to clone1
, it told me that the last time it spoke to repo1
, branch3
was at commit XYZ
." 了解 branch3
"from the horse's mouth" 可能更有意义。您可以通过在 clone2
.
repo1
作为第二个遥控器来做到这一点
无论您是通过添加 repo1
作为来源,还是通过使用非默认 refspecs 从 clone1
复制信息,最终在 clone2
中您将拥有对应于某些分支名称的多个远程引用(例如 refs/remotes/origin/branch3
和 refs/remotes/repo1/branch3
)。这意味着可能并不总是很清楚哪个分支应该被视为本地 refs/heads/branch3
的 "upstream"。您可以通过配置来管理它,and/or 通过特定 push
和 fetch
命令的参数来告诉他们您在该实例中作为上游的意图。
将所有这些转化为特定的命令实际上取决于您要完成的任务;有太多的可能性,无法将它们全部列出并解释何时使用其中任何一个。如果您需要那种程度的详细信息,我建议您可以从 git config
、git fetch
、git push
以及 git pull
的文档开始。
这应该是一条评论,但我需要格式化,我无法在评论中做到这一点(而且又变得冗长了:-))。
除了
branch3 - not checked out [on clone1] but can be at any time
关键是在这个状态下,branch3不存在.
这是我在其他答案中说过的话,我会重复:远程跟踪分支不是分支。它是远程跟踪分支名称:名称,如origin/branch3
,是以refs/remotes/
开头的全名的缩写形式(与分支名称[=49相比) =] 就像 branch3
一样,它是以 refs/heads/
).
(事实上,"a branch"在Git中并不总是"a branch",因为Git作者习惯用不同的词重用相同的词含义——公平地说,这在英语中也一直存在,这是我们获得 puns. See also What exactly do we mean by "branch"? 的一种方式,在这种特殊情况下,我们所说的 "a branch" 是一个分支 name ,即全名以refs/heads/
开头的引用。)
当您要求 git checkout
签出一个不存在的分支时,例如 branch3
,Git 将扫描您所有的远程跟踪分支名称。如果恰好有 "resembles" branch3
正确,git checkout
将 创建 一个,使用远程跟踪分支名称派生新分支的初始哈希 ID 值。
对于存储库中存在的分支名称,该存储库必须有一个全名以 refs/heads/
开头的引用。第二个斜线之后出现的是分支的名称。要列出某些存储库中的所有引用,运行 git for-each-ref
,其默认输出是每个引用的列表、其哈希 ID 以及由该哈希标识的 Git 对象的类型。
当你制作一个克隆时,你告诉你的 Git——制作克隆的那个——如何操作它从另一个 Git 获得的引用。这是 --mirror
所做的关键:它说 使用他们的引用来制作我的引用,根本没有任何更改。 普通克隆不会那样做,因为一旦你做 那样做,当你从另一个 Git 重新获取时,你会遇到问题:你已经完全被它奴役了;您在自己的副本中更改的任何引用,您用它们的值替换您的值,并且 return 成为纯副本。