两个git仓库不小心合并了,如何清理

Tha*_*all 2 git

我的一个客户不小心在他的文件中将另一个项目设置为远程项目.git/config,然后拉取、提交和推送。

这意味着存储库“A”(主要文件)中的所有文件现在都位于存储库“B”(辅助文件)中。不幸的是,已经有几个人从“B”退出了。

从“B”中删除“A”的所有文件、提交和历史记录的最佳方法是什么?

Sch*_*ern 5

我假设您的存储库看起来像这样,其中 AC 提交到正确的存储库中,而 1-3 提交到错误的存储库中。D 是由于拉取而导致的两者之间的合并点(大概pull --force您不应该这样做,除非您知道已经进行了变基)。

... A - B - C - D [master] [origin/master]
               /
... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

解决这个问题所需要做的就是将 master 移回 C。由于 Git 中的分支只是指向提交的标签,因此移动它们的成本很低。这就是git resetgit reset --完全做其他事情)的作用。

git checkout master
git reset --hard C
Run Code Online (Sandbox Code Playgroud)

--hard表示丢弃索引并使工作目录也与提交匹配。现在你的存储库看起来像这样。

... A - B - C [master] - D [origin/master]
                        /
           ... 1 - 2 - 3
Run Code Online (Sandbox Code Playgroud)

现在git push --force在远程存储库中进行相同的操作。如果没有其他东西引用它,有问题的提交最终将被垃圾收集。

... A - B - C [master] [origin/master]
Run Code Online (Sandbox Code Playgroud)

如果工作是在错误的合并之上完成的,那么事情会变得更加复杂。

... A - B - C - D - E - F - G [master] [origin/master]
               /
... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

您想做与以前相同的事情,但保留 G。您可以通过写下提交 ID 来完成此操作,也可以将其标记为安全。

git tag old-master master
Run Code Online (Sandbox Code Playgroud)

看起来像...

... A - B - C - D - E - F - G [master] [origin/master] (old-master)
               /
... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

像以前一样进行重置...

... A - B - C [master] - D - E - F - G [origin/master] (old-master)
                        /
         ... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

但现在你想将 E、F 和 G 挂在 C 上。你可以通过变基来做到这一点。这会将 E、F 和 G 作为补丁,并将它们一一应用到 C 上。

git rebase --onto master D old-master
Run Code Online (Sandbox Code Playgroud)

更改将有新的提交 ID,因为 git 中的每个提交 ID 都取决于其父级的 ID(这就是推拉速度如此之快的原因)。

              E1 - F1 - G1 [master]
             /
... A - B - C - D - E - F - G [origin/master] (old-master)
               /
... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

现在您可以push --force掌握和删除旧的掌握。

... A - B - C - E1 - F1 - G1 [master]
Run Code Online (Sandbox Code Playgroud)

由于存储库从他们的控制下发生了变化,因此已经从存储库中提取的每个人都必须这样做git pull --force。他们也许应该git pull --rebase --force。拉取通常是获取和合并。 --rebase将其转变为获取和变基。使用 rebase 会将用户未推送的工作作为补丁应用到新存储库之上。这可以防止错误的存储库通过拉取/合并返回。

例如,用户的存储库可能如下所示,其中 H 和 I 是他们自己的未推送更改。我还将放置固定的远程存储库以进行比较。

[local]
... A - B - C - D - E - F - G [origin/master] - H - I [master]
               /
... 1 -  2 -  3

[remote]
... A - B - C - E1 - F1 - G1 [master]
Run Code Online (Sandbox Code Playgroud)

修复远程存储库后,如果他们拉取 Git 将拒绝合并,因为 G 不是 G1 的祖先,他们必须强制。单独显示获取和合并/变基更简单。所以git fetch origin会导致...

[local]
              E1 - F1 - G1 [origin/master]
             /
... A - B - C - D - E - F - G - H - I [master]
               /
... 1 -  2 -  3

[remote]
... A - B - C - E1 - F1 - G1 [master]
Run Code Online (Sandbox Code Playgroud)

git merge origin/master,这就是git pull --force接下来要做的,会导致这个......

               - - - - - - E1 - F1 - G1 [origin/master]
             /                         \
... A - B - C - D - E - F - G - H - I - J [master]
               /
... 1 -  2 -  3
Run Code Online (Sandbox Code Playgroud)

我们不希望这样,它会从错误的存储库中恢复历史记录。 git pull --force --rebase相反,将执行 a git rebase origin/master,将 H 和 I 置于 origin/master 之上。

[local]
... A - B - C - E1 - F1 - G1 [origin/master] - H1 - I1 [master]
Run Code Online (Sandbox Code Playgroud)

现在他们可以正常工作(无需立即推送)。