GIT-如何在合并冲突后从提交中删除文件?

时间:2020-05-15 12:58:12

标签: git

情况如下:我在本地计算机上有两次提交。在第一个文件中,我添加了两个我想丢弃的文件。我不在乎它们是否丢失,我也不在乎历史。在第二次提交中,我遇到了一些合并冲突,必须解决(尽管不在这两个文件中)。因此,由于合并冲突,我不知道软重置在这里是否是个好主意。也许最好重新整理所有内容,然后从存储库中删除文件? IDk ..但我不想再次处理合并冲突。谢谢。

1 个答案:

答案 0 :(得分:1)

假设您在自己的Git存储库中有两次提交,但从未允许任何其他Git存储库“看到”。例如,假设(a)您从未使用过git push来将它们发送给其他人,并且(b)您不允许随机用户进入笔记本电脑并读取所有文件。

在这种情况下,您的状态很好,因为没有人拥有这些提交。这意味着您具有每一个选项。

...我不想再处理合并冲突。

这会稍微减少您的选项集。

这里要记住的是:

  • Git与 commits 有关。提交具有哈希ID,因此您可以判断任何给定的Git存储库是否具有给定的提交。例如,您可以只运行git show hash-ID-我建议从其他地方剪切并粘贴哈希ID,因为正确输入哈希ID太难了-看看 this Git是否知道此哈希ID。

  • Git本身使用分支名称​​查找哈希ID。这就是Git分支名称的目的:查找哈希ID。 可以随便使用它们; Git 将使用每个名称来查找一个特定的提交哈希ID。

进行两次提交时,您从git checkout branch-name开始。 (如果您没有运行自己的git checkout,那么Git已经这样做了,所以您也可以这样做。)然后,您编辑了一些文件,照常使用git add,并运行git commit进行第一次提交。完成此操作后,您可能已经运行了另一个git checkout,或者没有运行;然后您运行git merge,或执行了git merge,然后进行了第二次提交,这是一次实际的合并提交-只有真正的合并才可能发生合并冲突。

值得借鉴您现在拥有的东西。您可以让git log为您执行此操作(请参阅Pretty git branch graphs,尤其是this answer),也可以自己绘制。 您应该这样做,而不是我,因为您拥有自己的Git存储库,而我没有,并且我的假设Git存储库的绘图可能与您的实际Git存储库不符。不过,您的提交可能看起来像这样:

...--F--G--H---I   <-- master, origin/master
      \         \
       \      L--M   <-- feature (HEAD)
        \    /
         J--K   <-- origin/feature

也就是说,您自己先进行了L的提交:

git checkout feature     # new branch `feature` identifies commit `K`
... do some work ...
git add ...
git commit               # creates commit L

然后,您使用git merge或也许git pull或类似的方式进行合并:

git merge origin/master  # creates commit M

一旦您绘制情况,谈论哪些文件位于哪些提交中就更容易了。

首先,我添加了两个我想丢弃的文件。

这两个文件是提交L中的新文件。也就是说,当比较提交K与提交L时,存储在KL下的快照中可能有任意数量的更改,但是L中肯定还有两个文件不在K中。

我不在乎它们是否丢失,我也不在乎历史。

这给您很多选择。

在第二次提交中,我遇到了一些合并冲突,这些冲突必须解决(不过,这两个文件中没有)。

这意味着合并提交M包含了您对 Git 在将文件视为快照-L与文件已视为-快照中的I(其中LI是合并提交M的两个父对象)。

由于您不想重复该合并工作,因此无论接下来选择什么选项,都应至少等待一段时间才能提交M

选项:添加新的提交

您只需在 M之后添加新的提交即可删除文件:

git rm file1 file2
git commit

这将添加一个新的提交N

...--F--G--H---I   <-- master, origin/master
      \         \
       \      L--M--N   <-- feature (HEAD)
        \    /
         J--K   <-- origin/feature

您的名字feature现在指向新的提交N,其中没有这两个文件。

优点很明显:这非常容易快捷。

缺点是,这两个文件在提交LM中仍然存在,并将永远存在。如果并且当您将提交N授予任何人时,还必须给他们提交LM,如果看起来,每个人现在都将在这两个提交中看到这两个文件。 / p>

如果那不是问题,这是您最简单的选择。

您可以构建两个新的提交

假设您不在乎 ,但是您会喜欢不会将这两个文件暴露给其他任何人。这很容易!您可以构建两个 new 提交,如下所示:

git checkout -b better-feature <anything that identifies commit K>

您可以使用原始哈希ID,或者在特定情况下(如图所示)使用名称origin/feature来标识提交K。您现在拥有:

...--F--G--H---I   <-- master, origin/master
      \         \
       \      L--M   <-- feature
        \    /
         J--K   <-- better-feature (HEAD), origin/feature

您现在可以复制提交L,但尚未提交结果:

git cherry-pick -n <hash-of-L>

(例如,使用git log中的剪切和粘贴来获取哈希ID)。 -n告诉Git 不要提交。现在,您可以删除两个有问题的文件:

git rm file1 file2

然后提交:

git commit

获取缺少两个文件的L的副本,我们将其称为L'

...--F--G--H---I   <-- master, origin/master
      \         \
       \      L--M--N   <-- feature
        \    /
         J--K   <-- origin/feature
             \
              L'  <-- better-feature (HEAD)

现在您必须重复合并。

我不想再次处理合并冲突。

这是该方法的缺点:您要做必须处理合并冲突。但是,您不必再次真正地解决,只需从现有提交M 复制现有解决方案即可。这是您可能的方法:

git merge origin/master     # just as before

Git现在可以打印很多东西,包括显示与以前相同的两个合并冲突。但是,您不必打开文件来进行编辑,也可以使用git mergetool或您上次所做的任何操作,而这次只是告诉Git:给我相同的答案上次

假设两个冲突的合并文件分别命名为conflicts/c1.txtconflicts/c2.txt。您现在将运行:

git checkout feature -- conflicts/c1.txt conflicts/c2.txt

现在可以使用以前的分辨率来解析文件!使用git status进行验证,然后在您喜欢的编辑器或文件查看器中查看文件,以查看更新的内容。

(在Git 2.23或更高版本中,您可能更喜欢在git restore--source feature-s两个选项中使用-w,而不是git checkout 。效果完全一样。)

假设可以解决所有问题,并且您对所有其他文件都采用了Git的分辨率,那么现在就可以完成合并了。

最终结果是一个新的合并M',这两个文件使用相同的分辨率。与提交M不同,但与提交L'类似,提交M'缺少您故意没有这次添加的两个文件,因此:

git diff feature better-feature

(将提交M与提交M'进行比较)显示被删除的那两个文件。

您现在可以完全删除名称 feature,将better-feature重命名为feature,并在必要时设置新feature的上游/等等。或者,您可以使用git checkout -B feature better-feature来强制名称feature指向新提交,然后删除名称better-feature,以获得:

...--F--G--H---I   <-- master, origin/master
      \         \
       \      L'-M'  <-- feature (HEAD)
        \    /
         J--K   <-- origin/feature

现有的提交LM仍然存在,但是由于不再有用于查找它们的名称,因此git log --all --decorate --graph --oneline不会显示。运行git push origin feature会将originM'的提交发送到L',但不会提交ML的提交。

您可以想到的其他选择也很多

还有许多其他方法可以实现您喜欢的结果。 Git是一组工具,而不是一个特定问题的特定解决方案。不过,使用Git提供的工具集制作的这两种解决方案应该可以解决您的特定问题。