Git:如何在合并冲突损坏后进行还原

10

作为一个有20年经验的SVN和CVS专家,我发现git非常具有挑战性。 我阅读了很多指南,但没有找到一篇易于理解的文章。对于我在使用git时的愚蠢,请多多包涵。

我们只使用主干,没有使用分支。Git是被强制使用的。

我有一个js文件,我是唯一的“所有者”,其他人不应该触碰它。但是某个人却修改了它并将其检入。我试图检入我的副本,但失败了。所以我拉取了更新的版本,并且它用大量的<<<和>>> 来“破坏”我的副本。

基本上,我想拒绝他的所有更改,并用我的内容覆盖它们。对于SVN,我只需复制我的本地js文件,删除它,在存储库中检出获取有问题的文件,将我的文件复制回去,然后检查结果即可。非常简单。

我还没有找到在git中执行此操作的方法,因为如果您删除该文件,它会认为您要删除该文件。

所以我尝试编辑合并后的文件,但是搞混了哪些行是新的,哪些是旧的。现在这个文件无法使用了。我已经“失去”了本地文件副本。

我阅读了“git push origin master --force”的相关信息,但:

  1. 现在为时已晚,我已经失去了我的版本。
  2. 我读到另一篇文章说不要这样做,因为它会破坏其他人的拉取,但他们没有提供拒绝某人的检入,并用自己的文件替换一个文件的“正确”方法。
我假定我需要回到之前的本地提交来恢复那个文件。唯一我找到的方法是 "git checkout [revision] ."。但如果我这么做了,我就不在主分支上了,也不知道如何回到主分支。而且,我预计它不会让我这么做,因为我编辑和保存了有问题的文件,所以它不会让我检出以前的版本。我假设我得提交有问题的文件,然后尝试回退两个提交、备份文件,然后在一个新目录中再次检出主分支,覆盖文件,然后检入。

所以我有两个问题:

  1. 如何找回我的文件。
  2. 一旦我拿回它,如何用自己的文件覆盖其他人检入并推送的文件,而不影响他们检入和推送的其他内容?

我一直在寻找如何合并一个被他人更改过的简单文件。我找到的所有指南和文章都只讨论如何合并分支。我不想合并分支,我只想在同一个(head)分支上合并一个文本文件。一旦我成功获取了正确的文件版本,我仍然无法提交它,因为它说它没有被合并等。现在我已经开始在进行拉取之前复制所有文件,这样我就可以拯救我想要推回的文件,覆盖其他人的更改,但仍然不知道下一步是什么(如何提交)。 - John Little
看看这个视频:https://www.youtube.com/watch?v=1ffBJ4sVUb4 我真的觉得它有助于理解git的概念。 - skelliam
3个回答

26

你的两个问题可以用同样的方法解决:

git checkout HEAD my/filename.js

其中 HEAD 是字面意思(Git 的当前分支名称的缩写),my/filename.js 应该被实际文件名替换。这将恢复您的文件,使其回到更新之前的状态,有效地“撤消”来自其他人的更改。在本地提交此结果,然后像往常一样推送(如果您已从中央存储库更新,则不需要--force)。

通常,解决合并冲突的方法是编辑文件,直到它符合您的要求,然后运行 git add。Git (和 SVN )在合并或更新失败后留下“<<<”和“>>>"结果,以帮助您或您的工具解决合并冲突。设置一个工具来帮助您进行此操作可能非常值得,但遗憾的是它不能立即使用。

顺便说一下,您从 SVN 开始时用您知道的好文件替换不想要的文件也可以正常工作,只需添加一个步骤:删除文件后,还原好的文件并运行 git add my/filename.js。在这种情况下,checkout 也会将其添加到索引中(使用 git status 再次检查),因此您可以立即提交(本地)然后将(现已解决)合并冲突推回到中央存储库。


这很有道理,谢谢。不幸的是,我把它弄得更糟了。我读到获取文件的方法是还原,于是我用Tortoise Git进行了还原,现在我的文件回来了。但是它“破坏”了其他人检入的未发生冲突的文件。当我执行git status时,它说“你的分支和origin/master已经分叉(不知道什么意思),并且你们各自有1个和19个提交”。然后它说“要提交的更改:”,并列出了我从Pull中获取的两个文件,它们是没问题的 - 也就是说,它想提交那些我没有更改的奇怪版本的文件。 - John Little
Git pull 提示“您尚未完成合并”,而 git commit 则表示:1)我修复的文件仍处于冲突状态,2)我没有修改的文件在本地被修改了,但实际上它们并没有被修改。 - John Little
我想补充一点,在SVN中,如果出现了这种问题,我会直接删除我的目录,从头开始重新检出整个项目,然后手动将我的更改再次添加进去。Git并不像SVN那么简单,因为它有一个本地数据库。 - John Little
哦...还原操作特别棘手,因为在SVN和git之间它的意思完全不同。在SVN中,还原操作会丢弃本地更改以恢复干净的检出状态。而在git中,还原操作会创建一个新的提交,"反转"先前提交的所有更改。这就是为什么它会"破坏"其他人检入的文件。当你在git中意外地还原了某些东西并推送它时,唯一修复它的方法是还原还原操作,这将创建另一个提交,"反转"上一个提交。(呕吐)如果你还没有推送它,有其他的方法来修复它。 - user3033893
一个文件会一直处于“冲突”状态,直到你在它上面运行 git add 命令。在你实际解决所有冲突(删除“<<<”和“>>>”行)之前,不应该运行 git add 命令。解决冲突的一种方法是我最初给出的 checkout 命令。那些你没有修改过的文件可能是来自中央仓库的更新,没有任何冲突。 - user3033893
此外,您可以删除您的目录并从中央存储库重新克隆。这样做会丢失存储在本地数据库中(源树根目录下的隐藏.git目录)的任何分支和提交,但尚未推送。由于您提到只在主分支上工作(没有功能分支等),因此您只会丢失本地未保存的更改。可能还会丢失.git / config文件中的一些个人设置(例如别名)。 - user3033893

6

你可能只是想撤销他人的提交。在使用 Git 时,重要的是不要在本地有未提交的更改时运行 pull 命令。如果这样做,可能会产生非常难以撤销的合并。

git merge --abort

运行此命令将中止您已经开始的合并操作,该合并操作是通过将其他人的更改拉取到您的代码中实现的。这样做可能会恢复您在开始拉取之前未检查的更改。如果文件中有大量更改,请在其他地方备份并手动合并它们(如果此方法不起作用)。

运行

git log --stat

并找到更改了您的文件的提交。运行

git revert <commit id>

其中,id是更改您的文件的提交ID。这将创建一个提交,将其他人的提交回滚,然后将其推送。如果其他人在提交中有其他内容,则可以通过撤销您的还原并编辑提交以删除文件中的更改,然后再次推送更改来重新制作他们的补丁。

在将来,在拉取时不要有未检入的更改,这会引起麻烦。

您还可以考虑在服务器上设置提交挂钩,以阻止除您以外的其他人提交该文件。


4

要完全放弃合并冲突中的外部更改,您可以使用以下方法:

git checkout --ours -- <path-to-file> && git add <path-to-file>

使用您的版本解决了与特定文件的冲突。添加操作是告诉git冲突已经被解决。


这是你解决冲突的方式吗 - 你必须在后面添加吗?非常有用,谢谢。 - John Little

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