-->

Whitelist directories with .gitignore

2019-07-06 17:11发布

问题:

I want to have two directories in one git repository. My method of choice is to create a git repository in a top-level directory and then use .gitignore to whitelist the two directories of interest. Requirements are within the comments of my attempted .gitignore file:

# Blacklist everything
*
# Whitelist directories of interest and their contents
# stage files in directory A/ recursively
!A/
!A/*
# stage files in directory B/B1/ recursively (without staging files in B/)
!B/B1/
!B/B1/**
# Whitelist files of interest
# stage only the .md files (not .txt files)
!*.md

How to write a .gitignore file that whitelists two directories?

The above gitignore file is based on .gitignore ignoring whitelisted folder

Here is the directory I tested .gitignore on:

$ find A B C
A
A/a.md
A/a.txt
A/A1
A/A1/a1.md
A/A1/a1.txt
B
B/b.md
B/b.txt
B/B1
B/B1/b1.md
B/B1/b1.txt
C
C/c.md

Here is how I tested the .gitignore file:

$ find A B C            #list all paths
$ git init
                        #test .gitignore:
$ git add . --dry-run   #show what would be staged
                        #edit gitignore and test again

Expected output:

$ git add . --dry-run
add 'A/A1/a1.md
add 'A/a.md
add 'B/B1/b1.md

回答1:

This .gitignore file whiteslists the directories A and B/B1, and excludes .txt files:

#exclude files and directories in top directory
/*

#include the A directory
!/A

#include the B directory
!/B
#exclude files and directories in B
/B/*
#include the B/B1 directory
!/B/B1

#ignore .txt files
*.txt

It is based on last example in http://git-scm.com/docs/gitignore



回答2:

You can solve your problem with several .gitignore files:

# .gitignore
*
!.gitignore
!A/
!A/*
!B/
!B/*
!*.md

# A/.gitignore
!*

# B/.gitignore
!*


回答3:

This is what I did, based on the information in the cross-referenced question and the directory setup in this question:

$ mkdir junk
$ cd junk
$ git init
Initialized empty Git repository in /Users/jleffler/soq/junk/.git/
$ mkdir -p A/A1 B/B1 C
$ > A.md
$ > A/a.md
$ > A/a.txt
$ > A/A1/a1.md
$ > A/A1/a1.txt
$ > B/b.md
$ > B/b.txt
$ > B/B1/b1.md
$ > B/B1/b1.txt
$ > C/c.md
$ cat > .gitignore
*
!A/
!A/**
!B/
!B/**
!*.md
$ git status
On branch master

Initial commit

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

    A.md
    A/
    B/

nothing added to commit but untracked files present (use "git add" to track)   
$ git add A.md A B
$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   A.md
    new file:   A/A1/a1.md
    new file:   A/A1/a1.txt
    new file:   A/a.md
    new file:   A/a.txt
    new file:   B/B1/b1.md
    new file:   B/B1/b1.txt
    new file:   B/b.md
    new file:   B/b.txt

$

After adding A and B, all the files within are waiting to be added. Note that the .gitignore file contains the directories (the trailing slash is not mandatory, AFAICT), and then the names !A/**. The double star is key to the recursive search.


I used git reset (having never actually made a commit), and jiggered with .gitignore. I'm not clear that the goals are self-consistent at the moment. However, this modified .gitignore file:

*
!A/
#!A/**.md
!B
!B/B1
#!B/B1/**.md
!*.md
B/b.md

plus git add A.md A B yields:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   A.md
    new file:   A/a.md
    new file:   B/B1/b1.md

$

You should be able to play with variations on the themes shown to get the result you desire. The !*.md line tracks all .md files. The B/b.md line ignores B/b.md, of course. The .md file in C is ignored because C is blacklisted (via the *).