如何在Xcode中使用svn合并冲突(文件project.pbxproj)?

85
我们团队有两名成员,使用Xcode的SCM(使用SVN)来管理我们的源代码文件。我们都将文件添加到Xcode项目中,他已经向SVN服务器提交了代码。当我更新代码时,Xcode发现project.pbxproj文件存在冲突。然后我选择退出Xcode并手动合并冲突。接着我开始编辑我的project.pbxproj文件,合并我们的更改。实际上我不知道Xcode如何管理文件,我只是在project.pbxproj文件中添加了一些它原本没有的文本。当我完成后,我的项目无法打开。我猜想这是因为project.pbxproj文件不能手动编辑导致的。
因此,我想知道,当你遇到这个问题时,project.pbxproj文件存在冲突,应该如何解决?
谢谢!
13个回答

159

我使用Git,但我们遇到了相同的问题——如果两个人都添加了文件,则会出现合并冲突。

通常情况下,编辑很容易。只需使用文本编辑器打开project.pbxproj文件,并查找合并冲突部分——通常这部分会被标记为类似于“<<<<<<<<”的内容。

>>>>>>>
Stuff 1
======
Stuff 2
<<<<<<<<

在99%的Xcode项目合并冲突情况下,您只需要接受合并的两个版本(因为两个人添加了不同的文件)- 所以您只需删除合并标记,就像上面的情况一样:

Stuff 1
Stuff 2

正如我所说的,在大多数情况下,这个方法非常有效。如果Xcode在合并后无法读取项目文件,只需获取最新未合并版本,并手动添加您的文件即可。

2023年跟进

这条建议仍然适用,但最近我一直在处理一个非常大而且旧的应用程序,具有复杂的Xcode项目文件和几位团队成员时常会添加大量内容。

手动检查合并冲突仍然是主要方法。多人添加新文件通常与使用合并冲突的两侧同样容易。

还有一种紧急备选方案,就是将您尝试合并到分支中的项目文件作为副本导入,并使用带有冲突的Xcode项目的副本来手动添加回您的更改。

特别是有几种情况可能会带来挑战,其中一个解决方案非常不明显...

首先,有时候,多个人同时编辑同名文件可能会导致包含该文件的组中出现多个具有不同标识符的条目。对于此问题,请在将文件包含的组中查找文件ID,并选择保留哪个文件ID以及舍弃哪个文件ID。

其次,引入类似位置的新组可能会导致冲突分割组。在这种情况下,您可能需要完全将合并冲突区域的一侧内容移出,并将其正确引入到项目文件中的其他组中。

最后,正是这个不明显的解决方案促使我更新了这个答案。有时候,您可能会遇到一个冲突,其中所有CoreData版本的条目都有完全不同的标识符。例如,如果两个团队同时增加了模型版本,则可能会发生这种情况。

在这种情况下,似乎您可以选择其中一侧,仅使用这些标识符。这有时有效。

但在某些情况下,如果我这样做,在加载项目时我将看不到任何模型版本 - Xcode会将它们全部删除。

解决方法再次是将合并的两侧保留下来,这意味着Core Data模型将有两个条目!如果这样做,Xcode在加载项目时将为所有模型选择有效的标识符,并保存一个正确的版本,而不是允许两个版本同时存在。

对于具有多个正在进行的版本增量的大型团队,我们发现有一个技巧能够帮助平滑过渡,那就是使用单独的分支进行CoreData模型更改。这样所有团队都将使用相同的CoreData版本,并具有相同的当前模型标识符和内部Xcode项目ID。该分支仅持有CoreData模型本身,而不包括任何与模型相关的类(尽管它可以有)。


1
另一个回答类似问题的论点,主张将pbxproj文件视为二进制文件:https://dev59.com/hnI_5IYBdhLWcg3wDOhC#1549590 - Josh Metcalfe
5
他们完全错了。为什么任何文本格式在自动合并方面都会比代码本身更难处理呢?这毫无意义。我已经和其他人一起在XCode项目上工作多年了,每次都使用上述的合并策略(尽管现在我只告诉合并工具接受任何冲突的双方)。这种方法完全可行。至于故事板,我需要更多的实验才能断言它是否有效。 - Kendall Helmstetter Gelner
2
这对于至少Xcode 5是行不通的。似乎它使用了一些魔数,并在项目中添加某些内容时重新生成它们。当发生冲突时,您应该同时删除两个冲突资源,然后手动添加它们,以便Xcode可以再次生成那些魔数。 - Morteza Milani
我从未见过这种情况。在最近的一个项目中,当添加新资源时,只有新资源会获得新的编号(标识符)。在使用XCode 5进行多个人共享的项目工作了几个月后,我的建议仍然保持不变。 - Kendall Helmstetter Gelner
1
@cumanzor 我想跟进一下这个问题,因为我目前正在处理一个非常大、非常老的应用程序,它有一个复杂的Xcode项目文件和几个团队成员。从中学到的信息足够多,我会在答案中追加一些棘手的情况;但基本总结是,即使在2023年使用Xcode 14,手动检查和解决冲突仍然是最好的方法。 - Kendall Helmstetter Gelner
显示剩余3条评论

32

很遗憾,你只能手动在一个检出中进行更改,然后检入新的“合并”项目,别无他法。


1
在花费了一个小时的时间寻找神奇的解决方案后,这似乎是我唯一可以接受的答案。 - Kiran Ruth R
通过使用“他们”的更改来解决。尝试运行它。如果有关于缺少东西的错误,那么这将是您缺少的东西,您知道应该放在哪里。 - iOS Blacksmith

21

这个解决方案仅适用于git,但您可以向您的项目添加一个.gitattributes文件,然后在该文件中添加以下行:

*.pbxproj merge=union

这将告诉git保留合并的两个版本,这通常是您想要的大多数情况。


这在过去对我非常有效。绝对推荐。曾经试图记住我在过去项目中使用的设置,这就是它。感谢提醒。 - LunaCodeGirl
这是一个不错的解决方案,但不幸的是它并不能一直工作。 - Piotr Wittchen

13

手动解决合并冲突,需要检查每个冲突项的UUID

例如:

<<<<<<< HEAD
    6B01C4B72008E70000A19171 /* ExistingFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B01C4B62008E70000A19171 /* ExistingFile.swift */; };
    3F01C4B72008E70000889299 /* NewFileA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F01C4B72008E70000889299 /* NewFileA.swift */; };
=======
    6B01C4B72008E70000A19171 /* ExistingFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B01C4B62008E70000A19171 /* ExistingFile.swift */; };
    4DF01C4B72008E70000882ED /* NewFileB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF01C4B72008E70000882ED /* NewFileB.swift */; };
>>>>>>> branch_to_merge

检查每个 UUID:

  • 如果它在两个版本中都出现,则在一个版本中删除它:ExistingFile.swift
  • 如果它在比较分支上不存在,则保留它:NewFileA.swiftNewFileB.swift
  • 如果它在文件中没有被其他地方引用,即您只能在整个project.pbxproj文件中找到一个出现,则我会认为它是一个无效的部件并且可以安全删除。

结果如下:

    6B01C4B72008E70000A19171 /* ExistingFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B01C4B62008E70000A19171 /* ExistingFile.swift */; };
    3F01C4B72008E70000889299 /* NewFileA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F01C4B72008E70000889299 /* NewFileA.swift */; };
    4DF01C4B72008E70000882ED /* NewFileB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DF01C4B72008E70000882ED /* NewFileB.swift */; };

注意:我不建议将*.pbxproj merge=union添加到.gitattribues文件中,以忽略合并冲突,因为除非有一个复杂的脚本帮你检查,否则冲突的合并应始终手动检查。


1
问题已被作者删除。我认为UUID出现两次的可能性非常小。请参考UUID中的“唯一”一词。 - Manuel

4

到目前为止,我使用过的最好的pbx文件可视化合并工具是Visual Studio Code的合并工具。我在Code应用程序中打开pbx文件并解决冲突,然后再次打开XCode。


3
当我遇到这个问题时,我在寻找一个简单的解决方案时发现了另一个问题/答案:https://dev59.com/VG865IYBdhLWcg3wCp9A#14180388。这个解决方案让我感到非常惊喜,我试图合并一个差异化的功能分支,与主干相差近200个版本,但XCode和Mercurial对此并不满意。之前我尝试手动合并pbxproj文件(有超过100个冲突)8次后才尝试了这个解决方案。基本上,这个解决方案是这样的(假设你使用 Mercurial,因为它很棒):
  1. Attempt your merge in mercurial:

    hg update FEATURE_BRANCH
    hg merge default
    *mercurial gives you a ton of crap about the pbxproj file having merge conflicts*
    
  2. Open Xcode

  3. From the top toolbar, select Xcode->Open Developer Tool->FileMerge
  4. On the left, open your conflicted 'project.pbxproj' file (the one with merge conflict markup in it)
  5. On the right side, open your 'project.pbxproj.orig'
  6. Select File->Save Merge and save over the 'project.pbxproj' file
  7. Then back at the command line:

    hg resolve -m ProjectName.xcodeproj/project.pbxproj
    *merge any other broken files*
    hg commit -m "manually merged with trunk"
    
  8. Eat Cake Because You Are Done

1
结果发现 Xcode 5 的文件合并工具几乎无法正常运行,苹果公司真是干得好… - Engin Kurutepe
1
老实讲,与微软相比,虽然不太好用,但苹果通常不会发行很多漏洞。至少,它们发行的一些漏洞只影响到少数用户(即程序员),而且我们知道如何在谷歌上找到其他合并工具。 - G. Shearer
虽然我使用git,但是FileMerge也对我有帮助。 - Josh Paradroid

2
如上所述,处理冲突的最常见方式是:
  1. 接受“一切”
  2. 重新将文件导入项目中
我编写了一个Bash脚本来处理(1)。 请注意,这仅适用于解决大多数合并冲突的情况!
#!/bin/bash
#
#
#
if [ $# -eq 0 ]
 then
    echo "File must be provided as argument, darnit!"
    exit 1
fi

if [ $# -eq 2 ]
 then
    echo "only ONE File must be provided as argument, darnit!"
    exit 1
fi


echo "Will remove lines from file:" $1
grep -v "<<<<<" $1  | grep -v ">>>>>>" | grep -v "====" > out.tmp;mv out.tmp $1
echo "Done removing lines from file:" $1

我认为这个解决方案会产生与上面提供的.gitattributes解决方案相同的结果。 - Piotr Wittchen

2
有时候在不同的分支中会重新创建一个或多个文件(例如ManagedObjects),因此当你合并时,一个块中可能会有一个文件的两个声明。在这种情况下,您应该删除其中一个声明。

1

我遇到了一个棘手的问题。

不必手动处理这些冲突,你可以尝试这样做。
假设你在特性分支上。

  1. Git checkout master.
  2. Copy content in project.pbxproj
  3. Git checkout to your feature branch, and paste it.(Override the current content in project.pbxproj)
  4. Run

    react-native link
    

1
首先,这似乎只适用于使用RN的情况,其次,您将覆盖特性分支中所有新的文件链接。这毫无意义。 - David Seek

0

5
请注意,仅链接答案被强烈反对,Stack Overflow 上的答案应该是解决方案搜索的终点(而不是参考文献的另一个停留点,这些参考文献往往随着时间的推移变得过时)。请考虑在此处添加一个独立的概要,将链接作为参考。 - kleopatra
你能否提供更多关于这个工具如何解决所描述问题的细节? - Piotr Wittchen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接