Xcode Git 管理导致代码丢失的问题

Xcode 吸吮。git reflog 保存了我的生活。

我在两天之内遇到了Xcode 的两个致命问题。

首先,昨天在 Xcode 上check out 一个之前的 commit 时,出现了.xcworkspace 文件不存在的提示,并且提供了 Close 和Re-Save 的选项。

The workspace file that was at “” has disappeared. Do you want to re-save the container, or close it?

考虑到有人会直接Google 提示信息,所以我把提示信息复制过来便于被Google 到。

Xcode .xcworkspace 文件丢失提示

我在 Finder 里确认了文件存在,于是选择了 Close。但当我再打开项目时,所有文件索引和 Git 索引都在 Xcode 里不见了:

Xcode 丢失 Git 仓库索引
Xcode 丢失文件索引

虽然这些文件依然存在本地,理论上可以在命令行里直接使用 Git 的命令来恢复,但由于 Xcode 里的 Git 选项里所有 Git 仓库信息丢失,不能直接用图形化的界面来恢复到之前的样子。

开始我以为是iCloud 的锅,但今天我把工程放到本地空间来编写依然遇到了同样的问题。所以我猜测这个问题的出现是因为Xcode writes to file 的时候并没有以 atomically 的方式?(正好前两天在看 write 到 Document Directory 的相关接口)无论如何,既然不是 iCloud 的问题,这应该就是 Xcode 的问题了。好在我在 check out 前的那次 commit 的同时也Push 到了Github,因此直接把仓库重新 Clone 了下来。

这个问题的解决方法是:弹出提示时应该选择 Re-Save 而不是 Close,即使实际上 Finder 里文件存在。

第二个问题是,如果直接在 Xcode 的 Git 分支 A 的 commit B 处右键选择 check out(下图1),而不是在分支 A 处选择 check out(下图2,因为已 check out 到该 branch,所以这里是灰色),那么…

img

那么,首先我们会看到,没有任何一个 branch 后面会显示“(current)”,如下,可与上面的图对比。

img

其次,如果你同时载入了远程仓库,你会在 Push 的时候看到 Xcode 一直在 loading,无法加载出远程的 branch供你选择。

Xcode 无法加载远程 branch

再次,也是更严重的,假如你在这次 check out 后对代码进行修改,然后 commit,你会发现 Xcode 确实能暂时提交并显示此次 commit:

img

但你也发现了,由于你没从 main branch check out 过去,这个 commit 并没有提交到 main。

我刚发现这个问题的时候,如何补救这个场面呢?肯定想把最新的那次 commit 代表的 branch 给 merge 到 main branch。但想要在 Xcode 里 merge A branch 到 B branch,必须先 check out 到B ,之后选择 merge A branch into B branch。

所以,我 check out 到了 main branch。

这下好了,我发现刚刚的那个 commit 彻底在 Xcode 中消失了。我无从 merge:

img

而刚刚 Xcode 根本无法加载远程仓库,所以我刚刚的改动并没有被 Push 到远程仓库上。

所以,我对 Initial commit 更改后的 commit,全部“丢失”了。

——但也不是彻底丢失。以下是我补救的过程:

首先,我搜到了 jameskaron 在2017 年写的一篇博客:[IOS][git]使用XCODE9时使用git commit导致代码丢失问题

很遗憾,按照原文的方法,使用 git log 命令并没有看到修改后的 commit,只有 Initial commit。这说明似乎 Xcode 并没有提交那次 commit ?

img

本来刚刚燃起希望的我以为我已经完全丢失这份 commit 了。

然后在 StackOverflow 上搜到了一个好像不太相关,但确实派上了用场的问题:How to get back to the latest commit after checking out a previous commit?

作为对Git 没有太多了解的小朋友,第一次知道reflog。于是我抱着试一试的心态,输入了git reflog,查看了指代日志(?应该是这样翻译的吧)。

Hooray!

注意第4行99eb23

虽然 commit 的log 里面啥都没有,但 reflog 里出现了修改 Initial commit 之后的那次 commit 的7 位 Hash 。

最后通过git checkout hash(这里的hash 是99eb123),成功回到了这个“丢失”的 commit。

这时如果需要使用 Xcode 的图形界面来把这个 commit 的分支 merge 到 main,需要新建一个branch,然后 check out 到 main,然后把新 branch merge 到 main:

img

至此,这个问题解决了。

由于我并没有非常深入地学习过 Git,因此我不太确定这些问题出现的具体原因。但Xcode 确实允许直接 check out 到某一个 commit (而不是 branch),并且允许之后对它修改,然后再 commit,95%以上的开发者在这一步发现之前 check out 错了时都会check out 到相应的分支以便 merge,谁知 check out 之后就无法在 Xcode 的界面里看到新的 commit 了。这很可能会导致开发者以为自己丢失了修改。

同样也因为我没有非常深入地学习过 Git,很可能这整篇文章都是个错误。如果你认为我有什么写的不对的地方,欢迎你提出来。

Xcode sucks.

Hope this help.

加入对话

9条评论

  1. 博主是生活在美国吗?文章里中英夹杂,可读性真的很差,虽然这些都是很简单的 Git 专有名词,但是文章里一下英语一下中文的,读一遍脑子真的转不过来
    Commit:提交
    Initial Commit:初次提交
    Branch:分支
    Merge:合并

      1. 但是技术文档里面,基本上都是用的本地化语言。

        日常聊天当然不在乎这些,但是如果放在比较严谨的场合,还是建议第一次出现的时候用 中文(英文),然后后面提到这个的时候,统一使用中文名称,这样就不会显得文章过于混乱了

    1. 中英夹杂不是问题,我赞同专有名词保留原文。不过中西文混排时的格式不一致,容易引发阅读时的停滞感。(指的是空格时有时无……)
      看到有网友推荐工具「pangu.js」 或者 「Han.css: the CSS typography framework optimised for Hanzi」来提供更流畅的阅读体验。

      1. 谢谢,当时确实没有注意空格的问题。(其实除此之外也有大小写等等的问题。)

        1. 不客气!阁下的文章内容「干货」很多,剖决如流,我觉得很适合投稿!情不自禁想分享给更多人、让更多人看到认真思考的成果。加油!

    2. 感谢提出。没有生活在美国。因为 Xcode 本身是英文的,按钮的标题还是保留了原文,以免遇到问题的读者还要翻译回去。
      除此之外,这一句中的“writes to file”确实中英夹杂得有点突兀了:“所以我猜测这个问题的出现是因为Xcode writes to file 的时候并没有以atomically 的方式?(正好前两天在看write 到Document Directory 的相关接口)”。
      但“atomically”“Document Directory”也是因为前述原因,忠于了 API 的原文本,避免读者还要重新翻译回去。
      现在回看,这篇文章里的大小写和空格也确实有很多问题。

留下评论

回复 印刷排版行业中一直有着在中西文字体之间添加空白的习惯 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注