Search code examples
gitgitignoresubdirectory

.gitignore revert a rule in nested subfolders


Problem

I have a folder structure like:

.gitignore
notebooks/
notebooks/nb1.ipynb
notebooks/nb1_outputs.something
notebooks/folderA/
notebooks/folderA/nb2.ipynb
notebooks/folderA/nb2_outputs.someothers
notebooks/folderA/folderAA/nb3.ipynb
notebooks/folderA/folderAA/nb3_outputs.someothers
...

I want to ignore all stuff in the notebooks/ folder except *.ipynb files.

What I have tried

I wrote in the .gitignore like this:

/notebooks/*
!**.ipynb

but this did not work for nb2.ipynb, probably because it is in a subfolder which has been ignored by /notebooks/*.

Though I can write manually:

/notebooks/*.*
!/notebooks/*.ipynb
/notebooks/*/*.*
!/notebooks/*/*.ipynb
/notebooks/*/*/*.*
!/notebooks/*/*/*.ipynb

Is there a way to do this more easily?

Supplementary info

(base) ➜  git-test git:(master) ✗ cat .gitignore
notebooks/**
!notebooks/**.ipynb
(base) ➜  git-test git:(master) ✗ tree          
.
└── notebooks
    ├── folderA
    │   ├── nb2.ipynb
    │   └── nb2.out
    ├── nb1.ipynb
    └── nb1.out

2 directories, 4 files
(base) ➜  git-test git:(master) ✗ git status    
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .gitignore

nothing added to commit but untracked files present (use "git add" to track)
(base) ➜  git-test git:(master) ✗ git --version
git version 2.7.4

Solution

  • Well I just figured this out. Just write:

    # ignore all files in subfolders
    /notebooks/**/*.*
    # revert for notebooks
    !/notebooks/**/*.ipynb
    

    This works for me, though it is still prone to files without extensions.

    Alternatively, a more general solution from @torek:

    # add this to the end of .gitignore:
    !*/
    

    This disables the directory optimization, because !*/ inverts the ignoring of any directory or subdirectory.