Xcode 合并冲突后 Discard All Changes 导致代码丢失问题

2017-10-15 22:10:12 +08:00
 cielpy
https://imciel.com/2017/10/13/xcode-discard-change-and-git-merge-issue/

最近被这个问题坑的不轻,就写了下来,大家可以看看避免踩同样的坑
5476 次点击
所在节点    iDev
13 条回复
msg7086
2017-10-16 04:48:14 +08:00
这就是为什么我一直建议重度 Git 使用者挑选一个顺手的强大的 GUI。
alang
2017-10-16 06:14:37 +08:00
必须命令行啊,gui 都是不靠谱的
xpol
2017-10-16 08:40:42 +08:00
Sourcetree 党表示 GUI 是必须的。
xpol
2017-10-16 08:47:59 +08:00
怎么可能丢失代码?

合并前都是要求当前分支无变更啊(包括不能有 stage 代码)。
这就意味着要么你提交了,要么你 stash 了。

随便 discard 啊。原来的代码不在分支上就在 stash 里面啊。

看了一下链接,原来是带着 stage 但是未 commit 代码合并……
别怪工具,怪用工具的人,下次记得在干净的工作目录里面合并。
cielpy
2017-10-16 22:46:34 +08:00
@xpol

文章最后有 demo,有空的话你可以试一下

stage 是空的

合并前是这样的

https://i.loli.net/2017/10/16/59e4c5a94bd96.png

若有幸是刚打开 SourceTree

合并后再 Discard 是这样的

https://i.loli.net/2017/10/16/59e4c26462ecf.png

可以看到 commit 输入框有内容,能引起注意

若是已经用 SourceTree commit 过,并停留在 commit 后的界面没动,合并后是这样的

https://i.loli.net/2017/10/16/59e4c32cf2bcb.png

Discard 后是这样的

https://i.loli.net/2017/10/16/59e4c369d9b3a.png

修改后是这样的

https://i.loli.net/2017/10/16/59e4c5004c2d2.png

commit 后是这样的

https://i.loli.net/2017/10/16/59e4c50048381.png

请问最后一次 commit 哪里可以看出来有别的东西合并进来了
cielpy
2017-10-16 22:53:38 +08:00
@msg7086
@alang
@xpol

我个人觉得各有各的优势,GUI 在查看历史记录合并历史等等操作的时候比较直观,命令行强在各种功能组合,如果理解每一个选项的作用,一个命令的效果是比 GUI 鼠标点起来更直观,GUI 不够透明,不知道做了什么隐藏的操作,对仓库有什么影响,不过刚发现 SourceTree 的命令历史,这方面的缺陷可以查看命令弥补,我是配置用的,大部分操作用命令,偶尔用 SourceTree 查看历史记录,切换分支之类的
msg7086
2017-10-17 06:21:24 +08:00
@cielpy 我自己是用的 SmartGit,而且我在我司团队里推广使用过,效果很好。
GUI 是不够透明,不过幸好 SmartGit 里几乎所有的操作都会在 Log 里打出使用过的命令,有些时候我甚至是在跟着 GUI 学 Git。
如果只是轻度使用 Git 的话倒是无所谓,我对源代码管理要求比较高,Branching Rebasing Merging 非常频繁,而且要求 Interactive Rebase 整理源代码历史记录以方便后期 Blame 和 Revert,没有 GUI 感觉是如履薄冰。
cielpy
2017-10-17 09:41:04 +08:00
@msg7086 嗯嗯,根据使用场景选合适的工具就好啦
xpol
2017-10-17 20:40:36 +08:00
没有验证过 Xcode 里面的 Discard all changes 做了哪些操作。但是放弃 merge 的正确的命令行应该是 git merge --abort ( git > 1.7.4 https://stackoverflow.com/questions/5741407/how-to-undo-a-git-merge-with-conflicts ) 。

我看了一下 demo,了解了:

1. 当前在 master,将 test 合并过来
2. 合并发现冲突
3. 用 Xcode 的 Discard all changes 或者 git reset --hard HEAD,重置 index 和 working copy 到 HEAD 的状态(即 master 分支在合并前的状态,也就是 demo 中 test 0 这个提交的状态)
4. 提交,由于当前还处于 merge 状态,所以这个提交的状态被当成合并后结果

简言之,由于 Xcode 的 Discard all changes 或者命令行的 git reset --hard HEAD 都终止 merge 状态。稍后的提交会被当成合并的结果。
xpol
2017-10-17 20:44:22 +08:00
你可以本地退回到 master 上的 test 0 这个版本,然后和 test 上的 test 2 版本进行合并,然后选择 test 2 的版本,然后提交。最后 git push origin +master 强制 push。
xpol
2017-10-17 21:05:55 +08:00
另外,代码并没有丢失。正确的版本依然安安静静地躺在 test 分支上。

问题的根源是下面这一个错误的认识:

『若想丢弃此次合并,可以使用命令重置,回到当前分支的 HEAD,命令如下:git reset --hard HEAD 』

正确的认识是:

若想丢弃此次合并,可以使用命令放弃合并,命令如下:

git merge --abort,

或者 Sourcetree 里面选中合并前当前分支合并前的版本 -> 右键 -> Reset <branch_name> to this commit -> using mode 选择 hard 』
xpol
2017-10-17 21:39:01 +08:00
@cielpy 我是来认错的。我上一条关于 git reset --hard HEAD 不能放弃合并的说法才是错误的,对不起~~

根据 https://git-scm.com/book/tr/v2/Git-Tools-Advanced-Merging 的描述 git reset --hard HEAD 确实也可以用来放弃合并。

你说的对,应该只是 Xcode 中的 Discard all changes 不能放弃合并。
cielpy
2017-10-17 23:47:36 +08:00
@xpol 根据实际操作结果来看的话,git reset --hard HEAD 是会放弃合并的,而 Discard all changes 不会,造成了这个问题

当然我说的「代码丢失」意思其实不是真正的丢了,因为 commit 记录还在嘛,只是在合并后的分支上,看不到了这个 commit 相关的修改的一种异常状态

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/397855

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX