Best practices for Xcode + Git for multi-developer

2020-05-19 00:49发布

问题:

I can create a repo and use GitHub / BitBucket fine for my own projects. I have had problems when collaborating with other developers or trying to fork a project on GitHub.

I am aware of other answers like Best practices for git repositories on open source projects but there are OSX / Xcode specific problems I want to know how to solve.

  1. .DS_Store files can be a pain. You can use .gitignore to prevent, but what happens if they have already been included, or another developer adds them back in through a clumsy git command?

  2. The .xcodeproj will have changes to the directory names and developer profiles for the other person. What's the best way to do merges or to avoid conflicts?

  3. If I have forked or pulled from a github project, how can I clean up these issues and also minimise merge conflicts for the maintainer?

If people have an example .gitignore created for Xcode, or scripts they use to initialise their repos then that would be great!

回答1:

I'll try one by one:

I. You need to use git filter-branch only if you need to remove the files from your history completely. If those files do not contain any credit card information, then i think the following should be enough:

git rm --cached .DS_Store
git commit -m "{Your message}" 

then add this file to .gitignore and commit it.

This will commit the removal of the file from the repository but will keep the file in working directory. If you push it though and then somebody else will pull this commit, they might have their file removed, so you MUST communicate this. By committing .gitignore you will prevent other developers from adding this file again. If you're not a maintainer, then i don't think you should do anything, but address this issue to the maintainer.

II. I'm a strong believer that hidden files of any nature are most of the time not supposed to be put into the repository exactly for that reason. Therefore i think that you should do the same thing with .xcodeproj as with .DS_Store and put it into .gitignore and commit it. .gitignore is the exception for the rule above.

III. If those files are properly ignored , then there will be no issues in future with them. If they are already in the repo and somebody wants do such cleanup it should be done by maintainer and communicated inside the team.

Hope that helps!



回答2:

  1. Put .DS_Store in .gitignore. Then, if you haven't already, add .gitignore to the repo. (You should not ignore .gitignore.) Now all developers will ignore .DS_Store files. If any were added to the repo erroneously before you put .DS_Store in .gitignore, you can now remove them (in a commit) and they should stay out.

  2. The xcodeproj is a directory. The only file in this directory that must be in the repository is the project.pbxproj file. I generally ignore all of the others by putting these lines in my .gitignore:

    *.xcuserstate
    project.xcworkspace/
    xcuserdata/
    

    You should avoid putting absolute paths in your build settings. Use relative paths.

    Your Debug and Release builds should use iPhone Developer as the code signing identity, so that Xcode will automatically select the local developer's profile. When you want to create an IPA (for distribution), Xcode will offer to re-sign it with a different identity, at which point you can choose your distribution profile if you need to.

  3. If you're trying to use a project from github that has made these mistakes, you can try to get the maintainer to fix them, or you can make sure you don't touch the .DS_Store files and the code signing identities in the same commits that you want to send upstream.



回答3:

git filter-branch might help you to remove unwanted files (.DS_Store files) from your repository -- see e.g. https://help.github.com/articles/remove-sensitive-data

If a clumsy git commit has added files you should be able to replay the corrected changesets onto a clean repository.



回答4:

For the 2nd issue regarding the .xcodeproj and merge conflicts.

Using a .gitattributes file to specify that merge conflicts for all .pbxproj files should be handled using the merge=union strategy, which should mean that Git knows to merge in the changes from both sides of the conflict, taking the upstream changes first.

This article explains it in a bit more depth



回答5:

You're right in the sense that if a .DS_Store is already added the .gitignore won't be of much help however I think this is still a good resource for you and others.

When I start a project, I normally look at this list to see if there is a good .gitignore already existing. More specifically for you, this one is the Objective-C .gitignore.

Hopefully those resources are of some use.



回答6:

As a Mac user you should download a tool like SourceTree which supports Git Flow. Git Flow will help you establish some best practices around how your collaborators will commit code to the repo and at the very least make merge conflicts less frequent and more manageable. For a set of gitignore files for various project types you can go to GitHub and download one that is ready to go. For Xcode they have it listed as Objective-C.gitignore. That is a good starting place and it even covers Cocoapods. If you're using external libraries, your project should use CocoaPods so that you can isolate that code and keep it outside of your repo and avoid git submodules.

Now when you find a file has made it into your repo like .DS_Store just remove it, and move on. Make sure you add it to the .gitignore file that is checked into the project.

As for xcodeproj... there shouldn't be that much customization within the file that is user specific since the above mentioned gitignore filters that out. If a scheme is to be shared make sure you check shared under Manage Schemes and you will check in files in that subdirectory. You should be using automatic selection of certificates so the only real choice is Developer or Distribution. You should also take advantage of variables provided within Xcode that avoid hardcoding complete paths. When trying to think of an example Plists came to mind, in this case, you might have written /Users/me/MyProject/Resources/MyProject.plist, but instead should use $(SRCROOT)/resources/MyProject.plist.