我正在使用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知道所有变化的想法有何关联?这有可能避免这种情况吗?它可能会成为我们公司的一个问题,因为合并允许开发人员操作,但他们偶然会删除某人的更改。
答案 0 :(得分:8)
没有丢失历史记录:对README
在实验分支上所做的更改仍包含在提交210fdc1
中。它不是合并提交909139f
的一部分,完全是因为您在最终合并之前明确还原了它。
你没有说出你预期会发生什么,所以我只能猜到你到底有什么惊讶。我只想指出两个可能的候选人。
合并提交不仅限于修改自合并库以来触及的文件,甚至只修改具有冲突更改的文件。事实上,它可能与其所有父母完全不同。
“完全不同”当然不是人们所推荐的,因为它会打破每个人对合并所做的假设。但是,在合并提交中扩展文档文件非常有意义,解决某些合并冲突可能需要更改其他文件。
当您致电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
README
(HEAD
是默认值),是(在你的情况下)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从“要提交的更改”移动到“未提交的更改”。