Git Merge - 不完整、丢失文件和文件夹
我试图将 dev 分支合并到 master 中。
git checkout master
git pull . dev
一切似乎都很顺利,尽管存在一些冲突,我解决了这些问题并承诺了。但是,当我检查这个新合并的工作树时,缺少来自 dev 的许多文件夹和文件。
git status // Shows conflicts & doesn't list some files/folders.
git commit -a
Created commit 55ffdd1: Merge branch 'dev' into master
git diff dev --name-status
产生:
D folders/lm.gif
D folders/lmh.gif
...
因此未显示在“git status”上的文件/文件夹。当我修复合并的冲突时,它最终也没有出现。
另外,当我尝试再次合并时,它会显示:
git merge dev
Already up-to-date.
然而主分支显然缺少开发分支中的文件/文件夹。这是为什么?不应该添加该文件夹及其所有内容吗? “文件夹”正在开发分支上进行跟踪,所以当我进行合并时,它不应该被拉过来吗?
当早些时候发生合并冲突时,git 是否停止了合并过程并跳过了一堆文件/文件夹?
dev 分支有相当多的变化,我过去是否把 git 弄乱了,现在某些文件/文件夹不会合并?
(当我第一次创建 dev 分支时,我不知道自己在做什么,并且做了一些疯狂的事情,例如重置、恢复等。)
希望你们中的一位 git 大师在堆栈溢出上知道答案。 :)
谢谢, Quang
回答
谢谢 Walter,是的,就是这样。
经过一番调查后,我发现发生的事情有点复杂。事实证明。
- dev 从 master 分支出来,它拥有所有文件。
- 第三个分支,我们称之为“cleaned”,是从 dev 分支出来的。
- clean分支删除了所有文件。
- 已清理的分支与 master 合并(或其他什么?)。此时,文件已从 master 上删除。然后“清理”的分支就消失了。
- 在开发中,文件仍然存在,我继续添加到这个分支,编辑文件相当长一段时间。
- dev 与 master 合并,之前被 clean 删除的所有文件都消失了。
希望这对我以外的人有所帮助,他们学到了很多关于如何使用 git log、git show、git reflog 来尝试调试发生的事情。
谢谢!
如何修复
因此,这就是我所做的,将 dev 中先前删除的所有内容合并回 master 上。
- 获取所有已删除的文件/文件夹(在 dev 上,但不在新合并的 master 上) git diff dev --name-status | grep D > deleted_files
- 所有文件和文件夹的输出列表
git log --name-status> file_history
将使用它来找出已删除文件的最后更新版本。 - 逐一遍历deleted_files列表,找到file_history中最新的版本并恢复。示例:
git checkout 25b8a44 view.php
25b8a44... 是 view.php 最后更新版本的提交。我尝试了cherry-pick
和直接的git checkout dev view.php
但我发现显式使用提交 ID,它合并了更多的历史记录。 (包括首先导致文件被删除的提交。) - 所有删除的文件都恢复后,快速检查 git diff dev --name-status | grep D 显示所有文件都被复制过来。然后就像 Walter 所说的修正提交
git commit --amend
:)
I was trying to merge a dev branch into master.
git checkout master
git pull . dev
Everything seemed to go well, although there were conflicts I fixed these and commited. But when I checked this newly merged working tree is missing a lot of folders and files from dev.
git status // Shows conflicts & doesn't list some files/folders.
git commit -a
Created commit 55ffdd1: Merge branch 'dev' into master
git diff dev --name-status
Produces:
D folders/lm.gif
D folders/lmh.gif
...
So the files/folders that didn't show up on 'git status'. It also didn't show up at the end when I fixed the merged conflicts.
Also when I try to merge again it says:
git merge dev
Already up-to-date.
Yet the master branch clearly is missing files/folders from the dev branch. Why is that? Shouldn't that folder and all it's contents be added? 'folders' is being tracked on the dev branch, so shouldn't it have gotten pulled over when I did the merge?
When there was a merge conflict earlier did git stop the merge process and skipped a bunch of files/folders?
The dev branch had quite a lot of changes, could I have messed something up with git in the past that now certain files/folders wouldn't have merged?
(When I first created the dev branch I didn't know what I was doing and did crazy things like reset, reverts etc.)
Hoping one of you git guru's here on stack overflow knows the answer. :)
Thanks,
Quang
Answer
Thanks Walter, Yes this is what happened.
After doing some investigating I found out it was a little complicated what happened. It turned out that.
- dev branched from master, it had all the files.
- A third branch, lets call it "cleaned", branched off of dev.
- cleaned branch deleted all the files.
- cleaned branch merged (or something?) with master. At this point the files were deleted off of master. And the 'cleaned' branch disappeared.
- on dev, the files are still there and I continued adding to this branch, editing files for quite some time.
- dev merged with master and all the files that was deleted previously by cleaned were gone.
Hope this helped someone besides me who learned quite a lot about how to use git log, git show, git reflog trying to debug what happened.
Thanks!
How to Fix
So this is what I did to merge all of the contents in dev that was previously deleted back onto master.
- Got all the files/folders that was deleted (on dev but not on the newly merged master)
git diff dev --name-status | grep D > deleted_files
- Output list of all files and folders
git log --name-status > file_history
Gonna be using this to figure out the last updated version of the deleted file. - Go through the list of deleted_files one by one, find the the most updated version in file_history and restore it. Example:
git checkout 25b8a44 view.php
25b8a44... was the commit with the last updated version of view.php. I triedcherry-pick
and just a straightgit checkout dev view.php
but i found explicitly using the commit id, it merge more of it's history. (Including the commit that cause the file to be deleted in the first place.) - Once all the deleted files are back a quick check
git diff dev --name-status | grep D
shows that all files are copied over. Then like Walter said an ammend commitgit commit --amend
:)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来 git 认为丢失的文件在 master 上从 dev 分支到预合并头之间的某个时刻被删除了。这是我能想到的 git 在合并过程中默默删除跟踪文件的唯一原因。
不幸的是,我不知道解决这个问题的好方法。我可能只是手动从 dev 分支重新添加所有已删除的文件(或使用一点 bash 脚本),然后添加到 git commit --amend 来将合并提交修改为包括他们。
It sounds like git thinks that the missing files were deleted on the master at some point between where it branches from dev and the pre-merge head. That's the only reason I can think of for why git would silently drop tracked files during a merge.
Unfortunately, I don't know a good way to fix that. I'd probably just re-add all the deleted files from the dev branch manually (or with a little bit of bash scripting), and then to a
git commit --amend
to revise the merge commit to include them.为了避免这种情况 - 使用带有 --no-ff 选项的合并(合并而不快进)。有关 --no-ff 标志的更多详细信息,请参见此处 https://betterdev.blog /turn-off-git-fast-forward-merge/,https://hackr.io/blog/difference- Between-git-merge-and-git-merge-no-ff
一般来说 - 快进合并适合合并简单功能或错误修复,但如果分支单独开发一段时间(例如大功能或发布分支) - 您需要避免它。
因此,对于您的情况,它看起来像:
修复冲突并提交,
此时某些文件已从 master 中删除(已清理的更改),但在 dev 中仍然存在(并且可能已修改),
您将面临从中删除的文件的冲突master 但再次从 dev 收到,需要通过接受来自 dev 的更改来修复它们
最终您将收到透明的历史记录,如果您在解决冲突时错过或丢失了某些内容 - 您可以使用包含 3 个提交合并信息的合并提交轻松恢复它。
To avoid such a situation - use merge with --no-ff option (merge without fast forwarding). More details about --no-ff flag here https://betterdev.blog/turn-off-git-fast-forward-merge/, https://hackr.io/blog/difference-between-git-merge-and-git-merge-no-ff
In general - fast forward merge is suitable for merging simple features or bug fixes, but in case when branches developed separately for a while (ex. big feature or release branches) - you need to avoid it.
So for your case it'll look like:
fix conflicts and commit
at this moment some files are removed (changes from cleaned) from master but still present (and maybe modified) in dev
here you'll face conflicts on files which were removed from master but received from dev again, need to fix them by accepting changes from dev
Eventually you'll receive transparent history and if you missed or lost something while resolving conflicts - you can easily restore it using merge commit containing 3 commit merge info.