我们有两个仓库,仓库1和仓库2。看起来“有人”将Repo2推到了Repo1 / origin,现在Repo1包含Repo1和Repo2。有两个单独的根节点,没有任何东西被合并(幸运的是)。 Repo1也被Repo2的一大堆标签/分支污染。
一个人怎么可以完全否定具有特定祖先的任何提交(及其标记/分支)(Repo2的根节点又称为“初始提交”)?还是用另一种/更简便的方式来拼接这两个存储库?
请注意,这两个存储库都需要花费很多年的时间(因此手动查看每个提交并不可行),但是,对于需要使用Repo1重新克隆的每个人来说都是实用的。
答案 0 :(得分:1)
从您的文字描述中,我想您要说的意思是,您有一个单一的存储库,其中包含两个独立的提交子图(在技术上是不相交的)。例如,以下是这种存储库的示意图:
C--D
/ \
A--B G--H <-- branch1
\ /
E--F <-- branch2
I--J--K--L <-- master
\
M--N <-- develop
此特定图具有四个“入口点”,即在以F
为根的子图中提交H
和A
,并在L
和N
中提交子图的根源为I
。
尽管这样的存储库从根本上没有错,也没有破坏,但将其拆分为两个独立的存储库相对容易。只需从两个克隆开始,两个克隆都看起来像这样。 (您可以使用git clone --mirror
来创建保留所有引用的镜像克隆。请确保擦除其origin
,以免它们都指向原始组合的存储库。)
在一个这样的克隆中,删除两个子图的 one 中的所有提交的所有外部标签(分支名称,标记名称和其他引用,如果存在其他引用):
C--D
/ \
A--B G--H <-- branch1
\ /
E--F <-- branch2
I--J--K--L [abandoned]
\
M--N [abandoned]
请确保在故意放弃的子图中包含任何标记或其他名称。普通的图形查看命令,例如git log
,不会显示未引用的子图:它会出现,但实际上仍会存在。最终,未引用的子图将消失,或者您可以使用git gc
更快地将其删除。从该存储库中 制成的克隆将没有未引用的子图。
在两个克隆中的另一个中,删除对 other 子图的所有引用:
C--D
/ \
A--B G--H [abandoned]
\ /
E--F [abandoned]
I--J--K--L <-- master
\
M--N <-- develop
和以前一样,未引用的子图最终将消失。
请注意,原始的两个独立子图存储库 的任何克隆都可以用于git push
至这两个分开的克隆中的任何一个。为此,任何第三个完全独立的存储库也可以 用于推送到这两个克隆中的任何一个。任何为独立子图中的提交添加名称的推送都会使整个独立子图进入推送的接收者。 As you surmise in a comment,我怀疑这就是这种情况的产生。
您可以添加一个拒绝接收添加新的根提交的新名称的预接收钩子,尽管我不知道这种形式的方便的预接收钩子。这很容易,但是很慢:运行git rev-list --all --max-parents=0 --count
来计算现有的根,再运行git rev-list --all --max-parents=0 --count <hash>
来计算如果您接受了{{ 1}}。如果计数增加,则新的推送将添加新的根。
请注意,可以添加不相交子图的 not 部分的新根。例如,考虑“之前和之后建议”图:
git push
这种预接收钩子会拒绝这种推动。那可能就是您想要的,但可能不是。请注意您要编程的内容。 :-)
答案 1 :(得分:0)
将其发布给TLDR人群,这一切都归功于torek的出色回答。
我运行了此程序(在Windows MINGW64 git cli上,其他终端上的引用/转义可能有所不同),对其进行了检查,然后运行了它输出的所有命令。
var options = {
...
adjustWidth: false,
...
};
$("#example").easyAutocomplete(options);
添加一些git for-each-ref --contains <root_commit_hash> --format="%(refname:short)" refs/tags | xargs -I % echo git tag -d % \&\& git push --delete origin %
和/或git gc
以达到良好的效果。