gitignore negations ignored by git for osx xcode project

This question arises from reading and commenting on another question: Git ignore file for Xcode projects

While Adam’s answer (and accompanying gist) appears definitive, I cannot actually get it to work. My understanding of the gitignore syntax seems incomplete.

  • Git push from a previous commit
  • How to rebase my feature branch to development branch in git with least possible conflicts?
  • How do I update git to its latest version on Linux?
  • Why do large files still exist in my packfile, after scrubbing them with filter-branch?
  • How can I stop Git from trying to push non-existent file?
  • Create a copy of each version of a file in a git repository
  • My setup: OSX 10.8.2, git version 1.7.9.6 (Apple Git-31.1). There are no global gitignore files.

    I am testing on a new project created with the OSX Application template in Xcode 4.5.

    This is the test project file layout:

    ./.gitignore
    ./MyApp
    ./MyApp/AppDelegate.h
    ./MyApp/AppDelegate.m
    ./MyApp/en.lproj
    ./MyApp/en.lproj/Credits.rtf
    ./MyApp/en.lproj/InfoPlist.strings
    ./MyApp/en.lproj/MainMenu.xib
    ./MyApp/main.m
    ./MyApp/MyApp-Info.plist
    ./MyApp/MyApp-Prefix.pch
    ./MyApp.xcodeproj
    ./MyApp.xcodeproj/project.pbxproj
    ./MyApp.xcodeproj/project.xcworkspace
    ./MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
    ./MyApp.xcodeproj/project.xcworkspace/xcuserdata
    ./MyApp.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad
    ./MyApp.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate
    ./MyApp.xcodeproj/xcuserdata
    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad
    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes
    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/MyApp.xcscheme
    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist
    

    I set up the test project with source control disabled, then initialise the git repo manually in Terminal. The working directory is the project directory:

    git init
    git add .
    git commit -m "first commit"
    

    which returns a list of committed files:

    13 files changed, 5204 insertions(+)
    create mode 100644 MyApp.xcodeproj/project.pbxproj
    create mode 100644 MyApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
    create mode 100644 MyApp.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate
    create mode 100644 MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/MyApp.xcscheme
    create mode 100644 MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist
    create mode 100644 MyApp/AppDelegate.h
    create mode 100644 MyApp/AppDelegate.m
    create mode 100644 MyApp/MyApp-Info.plist
    create mode 100644 MyApp/MyApp-Prefix.pch
    create mode 100644 MyApp/en.lproj/Credits.rtf
    create mode 100644 MyApp/en.lproj/InfoPlist.strings
    create mode 100644 MyApp/en.lproj/MainMenu.xib
    create mode 100644 MyApp/main.m
    

    After each .gitignore test I reset by deleting the .git folder and reinitialising.

    If .gitignore is this

    AppDelegate.h
    

    then
    ./MyApp/AppDelegate.h
    is excluded

    If I change .gitignore to

    AppDelegate*
    

    Both of these are excluded
    ./MyApp/AppDelegate.h
    ./MyApp/AppDelegate.m
    as expected

    If my .gitignore is this:

    AppDelegate*  
    !AppDelegate.m  
    

    Again, only AppDelegate.h is excluded

    This is all as expected

    However I can’t get reincludes to work when the exclusion rule is a containing folder

    For example if my .gitignore is this

    xcuserdata  
    

    then these files are excluded

    ./MyApp.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate

    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/MyApp.xcscheme
    ./MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist

    Now if I want to re-include the contents of xcschemes

    xcuserdata  
    !xcschemes
    

    the result is the same – !xcschemes appears to be ignored.

    similarly if .gitignore is

    en.lproj
    

    these files are excluded

    ./MyApp/en.lproj/Credits.rtf
    ./MyApp/en.lproj/InfoPlist.strings
    ./MyApp/en.lproj/MainMenu.xib

    If I wanted to reinclude one of them

    en.lproj  
    !Credits.rtf  
    

    the same files are excluded: !Credits.rtf is ignored.

    the manpage for gitignore just says this:

    An optional prefix ! which negates the pattern; any matching file
    excluded by a previous pattern will become included again. If a
    negated pattern matches, this will override lower precedence
    patterns sources.

    but I am not sure what “lower precedence patterns sources” means, or whether it is relevant here.

    What am I missing?

    update
    Adam has updated his gitignore gist to take account of these issues. I have wrapped his changes into my fork, and also added some notes on how to add or change such a .gitignore when an XCode project is already under git control.

  • Expand variables on config.xml PhoneGap
  • How to maintain a Github fork of a popular project with submodules
  • git commit directory
  • How can I add another repository in git?
  • How can I repair my git configuration?
  • How do I update my local branch of forked repo
  • One Solution collect form web for “gitignore negations ignored by git for osx xcode project”

    Git traverses your file system tree and tries to match your ignore rules.
    If the rules match a directory that directory is, well, ignored.
    That means that git will not even look at any contents of it, that’s why any exception inside of it will be ignored.

    Getting around this is a bit tricky and not always possible.

    /MyApp.xcodeproj/xcuserdata/*
    !/MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/
    /MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/*
    !/MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/
    /MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/*
    !/MyApp.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/MyApp.xcscheme
    

    The above .gitignore will ignore all files in /MyApp.xcodeproj/xcuserdata/ except for MyApp.xcscheme.

    Often it is also possible to pretty much ignore those exceptions and only specify what you actually want to ignore.

    Git Baby is a git and github fan, let's start git clone.