Search code examples
gitterminalgitignore

gitignore everything except repeated sub-directory


I have the following directory structure:

./
├── proj-1
│   ├── README.md
│   ├── src/
│   └── test/
└── proj-2
    ├── README.md
    ├── src/
    └── test/

How can I ignore everything except for the src/ directories using just one .gitignore file in the root directory?

I've tried:

*
!.gitignore
!/*/src/
!/*/src/*

But that doesn't seem to pick up the directories I want after running git status.

Any tips?


Solution

  • You have to recursively un-ignore all parent directories of the src directory tree, then ignore their content:

    # Ignore everything
    *
    
    # Unignore .gitignore
    !.gitignore
    
    # Unignore all directories
    !*/
    
    # Ignore contents of all directories
    */*
    
    # Unignore all src subdirectories
    !*/src/
    
    # Unignore directory tree under src subdirectories
    !*/src/**
    

    So, for a tree that looks like

    .
    ├── proj-1
    │   ├── README.md
    │   ├── src
    │   │   ├── srcfile1
    │   │   ├── srcfile2
    │   │   ├── srcfile3
    │   │   └── subsrc
    │   │       ├── subsrcfile1
    │   │       ├── subsrcfile2
    │   │       └── subsrcfile3
    │   └── test
    │       ├── testfile1
    │       ├── testfile2
    │       └── testfile3
    ├── proj-2
    │   ├── README.md
    │   ├── src
    │   │   ├── srcfile1
    │   │   ├── srcfile2
    │   │   └── srcfile3
    │   └── test
    │       ├── testfile1
    │       ├── testfile2
    │       └── testfile3
    └── proj-3
        └── file
    

    you get this status

    On branch master
    
    No commits yet
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
        .gitignore
        proj-1/
        proj-2/
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    and after adding everything, you get

    $ git add * .gitignore 
    
    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
            new file:   .gitignore
            new file:   proj-1/src/srcfile1
            new file:   proj-1/src/srcfile2
            new file:   proj-1/src/srcfile3
            new file:   proj-1/src/subsrc/subsrcfile1
            new file:   proj-1/src/subsrc/subsrcfile2
            new file:   proj-1/src/subsrc/subsrcfile3
            new file:   proj-2/src/srcfile1
            new file:   proj-2/src/srcfile2
            new file:   proj-2/src/srcfile3
    

    .gitignore has to be added explicitly because the shell doesn't expand * to include hidden files.