我想你在这里问了几个问题。第一个似乎是“我该如何恢复file1.txt
?” 假设您的修订图如下所示:
M
(master) o -- o --- o ------o HEAD
\ /
(b1) o -- o -- o
A B C
file1.txt
您可以通过以下方式获取以前的副本git checkout
:
git checkout HEAD~1 -- file1.txt
file1.txt
这将在您的工作副本中复活并暂存。您可以,git commit
并且文件将返回。注意:HEAD~1
表示取 的第一个父级HEAD
,它指向合并 b1 之前的 master 状态。如果您知道提交 ID,则可以使用它来代替HEAD~1
。
您似乎在问的另一个问题是“我应该在分支 b1 中做什么来避免这种情况?” 最明显的选择是file1.txt
一开始就不删除。但是让我们假设您认为您需要这样做,并认为该选择是错误的。接下来,假设您没有通过将更改推送到某处来共享分支 b1。如果您注意到您立即删除了该文件,您可以执行以下操作:
git checkout HEAD~1 -- file1.txt
git commit --amend
那就是说,“把 file1.txt 还给我,然后将该文件合并到最新的提交中。” 这看起来就像您从未删除过该文件一样。
如果您没有注意到该文件被立即删除,并且您之间有几次提交,那么您可能希望查看使用git rebase
来修复问题。
如果您在其自己的提交中删除了该文件,那么您可以使用git rebase -i
从分支的历史记录中删除该提交。让我们假设这B
是删除文件的提交,这是该提交中唯一完成的事情。在 b1 上,您将运行以下内容:
git rebase -i B~1
删除包含有问题的提交 ( B
) 的行,保存并退出。您的分支刚刚重写了它的历史,而没有B
其中的内容。例如,我跑了git rebase -i
,这在编辑器中显示:
pick 40f76a7 removed bar
pick 30a25f5 modified foo
然后我从列表中删除40f76a7
,然后给我留下:
pick 30a25f5 modified foo
合并后的历史现在看起来像这样:
M
(master) o -- o --- o ------o HEAD
\ /
(b1) o ------- o
A C'
请注意,提交 idC'
不同于C
因为B
不再存在,并且父 sha1 是提交 id 的一部分。IOW,C 的 sha1 改变了,因为我们重写了历史。
如果您file1.txt
在同一个提交中删除并进行了许多其他更改,那么还有几个步骤。首先,带回文件并提交:
git checkout B~1 -- file1.txt
git commit -m "Reinstate file1.txt"
我们称之为新的提交D
。我们的修订图现在看起来像
M
(master) o -- o --- o -----------o HEAD
\
(b1) o -- o -- o -- o
A B C D
现在,做:
git rebase -i B~1
并将包含提交 id 的行移动到提交 idD
之后B
,然后更改pick
为squash
. 例如,我在运行时得到这个git rebase -i B~1
:
pick 40f76a7 removed bar plus other changes
pick 30a25f5 modified foo
pick 6177cb7 add bar
6177cb7
是恢复 bar 的提交。所以我将它移到下面40f76a7
并将命令更改为squash
:
pick 40f76a7 removed bar plus other changes
squash 6177cb7 fix bar
pick 30a25f5 modified foo
保存并退出。它会要求您修复提交消息。去做。完成后,您最终会得到如下所示的历史记录:
M
(master) o -- o --- o -----------o HEAD
\
(b1) o -- o -- o
A B' C'
新的B'
不再删除file1.txt
。此时,您已准备好与 master 合并。
几句结束语。小心git rebase
。如果你不小心,你可能会失去历史。确保阅读git rebase手册页。那里有很多有用的信息。注意:只有当您想删除从历史记录中删除文件的事实时,git rebase
才需要进行所有这些工作。如果您同意提交显示您将文件带回,那么请务必使用恢复文件并提交它。对于新的 git 用户来说,它不那么乏味,而且更容易。 相当先进,需要一些练习。但是,如果您投入时间并学好它,它确实非常有用。git checkout
git rebase