5

在我的主分支中,我有 2 个文件:

file1.txt
file2.txt

我从那里创建了名为 b1 的新分支。在 b1 中,我修改了 file2.txt,并意外删除了 file1.txt(从磁盘中,当我打开 Windows 资源管理器到源文件夹时,file1.txt 不存在)。现在我想保留 file2.txt 中的更改并从 master 恢复 file1.txt(我不需要删除的版本)。我切换到master,合并到b1,没有发生冲突,它说'all up-to-date'但file1.txt不存在。我应该怎么做?谢谢。

4

2 回答 2

12

我想你在这里问了几个问题。第一个似乎是“我该如何恢复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,然后更改picksquash. 例如,我在运行时得到这个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 checkoutgit rebase

于 2012-09-26T10:13:09.880 回答
3

在这种情况下合并不是你做的事情,Git 在合并回 master 时保留删除是正常的。如果你想从另一个分支或标签获取文件,它是git checkout master -- filename.

在您的情况下,您需要在之前取消合并:

  1. 确保您在 master 上,并且您的工作目录是干净的(git status显示没有变化)
  2. 取消您所做的合并

     git reset --hard master@{1}
    
  3. 回到b1

    git checkout b1
    
  4. file1.txt在您的工作副本中从 master结帐 :

    git checkout master -- file1.txt
    
  5. 提交或修改你之前的提交,或者你想做的任何事情
于 2012-09-26T10:08:15.710 回答