Git允许在合并冲突期间丢失文件更改历史记录

时间:2013-06-20 00:40:27

标签: git

我正在使用Git很长一段时间,但最近遇到了一个有趣的技巧,允许你在合并期间恢复文件更改历史记录。以下是重现的步骤:

我有两个文件和一个提交的git存储库:

$ git branch   
  * master
$ git log --oneline 
  80c8d5a Initial commit
$ git log --oneline -- README
  80c8d5a Initial commit
$ ls
  README conflict_file

我正在创建新的实验分支并更改README和conflict_file文件:

$ checkout -b experiment 
  Switched to branch 'experiment'
$ vim README 
$ vim conflict_file 
$ git commit -am "Experimental changes"
  [experiment cdbc988] Experimental changes
  2 files changed, 2 insertions(+)
$ git log --oneline -- README
  cdbc988 Experimental changes
  80c8d5a Initial commit

返回主分支并编辑conflict_file(以便在合并期间产生冲突):

$ git checkout master 
  Switched to branch 'master'
$ vim conflict_file 
$ git commit -am "Master changes"
  [master ad8b68e] Master changes
  1 file changed, 1 insertion(+)

我的存储库的状态如下:

$ git log --oneline --decorate --graph --all
  * ad8b68e (HEAD, master) Master changes
  | * cdbc988 (experiment) Experimental changes
  |/  
  * 80c8d5a Initial commit

尝试与实验分支合并:

$ git merge experiment 
  Auto-merging conflict_file
  CONFLICT (content): Merge conflict in conflict_file
  Automatic merge failed; fix conflicts and then commit the result.
$ git mergetool 
  <merging conflict in conflict_file>

这是诀窍:

$ git reset HEAD README
  Unstaged changes after reset:
  M      README
$ git commit 
  [master 909139f] Merge branch 'experiment'
$ git log --oneline -- README
  80c8d5a Initial commit

我丢失了实验性更改提交中实验性分支中引入的 README 文件的更改和历史记录。任何人都可以评论它与Git知道所有变化的想法有何关联?这有可能避免这种情况吗?它可能会成为我们公司的一个问题,因为合并允许开发人员操作,但他们偶然会删除某人的更改。

2 个答案:

答案 0 :(得分:8)

没有丢失历史记录:对README在实验分支上所做的更改仍包含在提交210fdc1中。它不是合并提交909139f的一部分,完全是因为您在最终合并之前明确还原了它。

你没有说出你预期会发生什么,所以我只能猜到你到底有什么惊讶。我只想指出两个可能的候选人。

  1. 合并提交不仅限于修改自合并库以来触及的文件,甚至只修改具有冲突更改的文件。事实上,它可能与其所有父母完全不同。

    “完全不同”当然不是人们所推荐的,因为它会打破每个人对合并所做的假设。但是,在合并提交中扩展文档文件非常有意义,解决某些合并冲突可能需要更改其他文件。

  2. 当您致电git log -- some_path时,会调用名为历史记录简化的流程。在手册页描述它时,git log将尝试仅显示那些“足以解释与指定路径匹配的文件是如何”的提交。在您的情况下,初始提交足以解释README的当前状态(因为README仍然或者再次具有相同的内容),所以它就是显示的全部内容。

    您可能希望使用--full-history,可能与--simplify-merges一起使用,或使用其他一些历史记录简化选项。它们以及包含提交的确切规则(比上面隐含的更复杂)是described in the git log man page,并有一个扩展示例。

答案 1 :(得分:1)

您实际上已丢失更改,您尚未检查文件README的更改,因此它们不在您git log显示的任何提交中命令:

*   9b8ede8 (HEAD, master) Merge branch 'experiment'
|\  
| * 210fdc1 (experiment) Experimental
* | d0c1637 Master changes
|/  
* b558d42 Initial commit

(我的SHA当然不同)和:

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   README
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   conflict_file.orig
no changes added to commit (use "git add" and/or "git commit -a")

正如@Chronial在评论中指出的那样,你明确告诉git对当时的git reset --mixed文件--mixed READMEHEAD是默认值),是(在你的情况下)ad8b68e

如果你在冲突的合并中(git status之前)运行git mergetool,你会看到这个:

$ git status
# On branch master
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Changes to be committed:
#
#   modified:   README
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#   both modified:      conflict_file
#

git mergetool步骤解决冲突,将conflict_file移动到与上面的README相同的准备提交状态 - 但在reset --mixed之后,{{1从“要提交的更改”移动到“未提交的更改”。