情况如下:我在本地计算机上有两次提交。在第一个文件中,我添加了两个我想丢弃的文件。我不在乎它们是否丢失,我也不在乎历史。在第二次提交中,我遇到了一些合并冲突,必须解决(尽管不在这两个文件中)。因此,由于合并冲突,我不知道软重置在这里是否是个好主意。也许最好重新整理所有内容,然后从存储库中删除文件? IDk ..但我不想再次处理合并冲突。谢谢。
答案 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
时,存储在K
和L
下的快照中可能有任意数量的更改,但是L
中肯定还有两个文件不在K
中。
我不在乎它们是否丢失,我也不在乎历史。
这给您很多选择。
在第二次提交中,我遇到了一些合并冲突,这些冲突必须解决(不过,这两个文件中没有)。
这意味着合并提交M
包含了您对 Git 在将文件视为快照-L
与文件已视为-快照中的I
(其中L
和I
是合并提交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
,其中没有这两个文件。
优点很明显:这非常容易快捷。
缺点是,这两个文件在提交L
和M
中仍然存在,并将永远存在。如果并且当您将提交N
授予任何人时,还必须给他们提交L
和M
,如果看起来,每个人现在都将在这两个提交中看到这两个文件。 / 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.txt
和conflicts/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
现有的提交L
和M
仍然存在,但是由于不再有用于查找它们的名称,因此git log --all --decorate --graph --oneline
不会显示。运行git push origin feature
会将origin
和M'
的提交发送到L'
,但不会提交M
和L
的提交。
还有许多其他方法可以实现您喜欢的结果。 Git是一组工具,而不是一个特定问题的特定解决方案。不过,使用Git提供的工具集制作的这两种解决方案应该可以解决您的特定问题。