10.8 文件忽略

Git提供了文件忽略功能。当对工作区某个目录或某些文件设置了忽略后,再执行git status查看状态时,被忽略的文件即使存在也不会显示为未跟踪状态,甚至根本感觉不到这些文件的存在。现在就针对Hello world程序目录试验一下。


$cd/path/to/my/workspace/demo/src

$git status-s

?? hello

?? main.o

?? version.h


可以看到src目录下编译的目标文件等显示为未跟踪,每一行开头的两个问号好像在向我们请求:“快把我们添加到版本库里吧”。

执行下面的命令可以在这个目录下创建一个名为.gitignore的文件(注意文件的前面有个点),把这些要忽略的文件写在其中,文件名可以使用通配符。注意:第2行到第5行开头的右尖括号是cat命令的提示符,不是用户的输入。


$cat>.gitignore<<EOF

>hello

>*.o

>*.h

>EOF


看看写好的.gitignore文件。每个要忽略的文件显示在一行。


$cat.gitignore

hello

*.o

*.h


再来看看当前工作区的状态。


$git status-s

?? .gitignore


把.gitignore文件添加到版本库中吧。(如果不希望添加到库里,也不希望.gitignore文件带来干扰,可以在忽略文件中忽略自己。)


$git add.gitignore

$git commit-m "ignore object files."

[master b3af728]ignore object files.

1 files changed,3 insertions(+),0 deletions(-)

create mode 100644 src/.gitignore


1.文件.gitignore可以放在任何目录中

文件.gitignore的作用范围是其所处的目录及其子目录,因此如果把刚刚创建的.gitignore移动到上一层目录(仍位于工作区内)也应该有效,移动操作如下:


$git mv.gitignore..

$git status

On branch master

Changes to be committed:

(use "git reset HEAD<file>…"to unstage)

#

renamed:.gitignore->../.gitignore

#


果然移动.gitignore文件到上层目录,Hello world程序目录下的目标文件依然被忽略着。执行提交:


$git commit-m "move.gitignore outside also works."

[master 3488f2c]move.gitignore outside also works.

1 files changed,0 insertions(+),0 deletions(-)

rename src/.gitignore=>.gitignore(100%)


2.忽略文件有错误,后果很严重

实际上,上面写的忽略文件不是非常好,为了忽略version.h,结果使用了通配符*.h会把源码目录下的有用的头文件也给忽略掉,导致应该添加到版本库的文件忘记添加。

在当前目录下创建一个新的头文件hello.h。


$echo "/test/">hello.h


在工作区状态显示中看不到hello.h文件。


$git status

On branch master

nothing to commit(working directory clean)


只有使用了—ignored参数,才会在状态显示中看到被忽略的文件。


$git status—ignored-s

!! hello

!! hello.h

!! main.o

!! version.h


要添加hello.h文件,使用git add-A和git add.都失效。无法用这两个命令将hello.h添加到暂存区中。


$git add-A

$git add.

$git status-s


只有在添加操作的命令行中明确地写入文件名,并且提供-f参数才能真正添加。


$git add-f hello.h

$git commit-m "add hello.h"

[master 48456ab]add hello.h

1 files changed,1 insertions(+),0 deletions(-)

create mode 100644 src/hello.h


3.忽略只对未跟踪文件有效,对于已加入版本库的文件无效

文件hello.h添加到版本库后,就不再受到.gitignore设置的文件忽略所影响了,对hello.h的修改都会立刻被跟踪到。这是因为Git的文件忽略只是对未入库的文件起作用。


$echo "/end/">>hello.h

$git status

On branch master

Changed but not updated:

(use "git add<file>…" to update what will be committed)

(use "git checkout—<file>…" to discard changes in working directory)

#

modified:hello.h

#

no changes added to commit(use "git add" and/or "git commit-a")


偷懒式提交。(使用了-a参数提交,不用预先执行git add命令。)


$git commit-a-m" 偷懒了,直接用-a参数直接提交。"

[master 613486c]偷懒了,直接用-a参数直接提交。

1 files changed,1 insertions(+),0 deletions(-)


4.本地独享式忽略文件

文件.gitignore设置的文件忽略是共享式的。之所以称其为“共享式”,是因为.gitignore被添加到版本库后成为了版本库的一部分,当版本库共享给他人(克隆),或者把版本库推送(PUSH)到集中式的服务器(或他人的版本库)时,这个忽略文件就会出现在他人的工作区中,文件忽略在他人的工作区中同样生效。

与“共享式”忽略对应的是“独享式”忽略。独享式忽略就是不会因为版本库共享,或者版本库之间的推送传递给他人的文件忽略。独享式忽略有两种方式:

一种是针对具体版本库的“独享式”忽略。即在版本库.git目录下的一个文件.git/info/exclude来设置文件忽略。

另外一种是全局的“独享式”忽略。即通过Git的配置变量core.excludesfile指定的一个忽略文件,其设置的忽略对所有本地版本库均有效。

至于哪些情况需要通过向版本库中提交.gitignore文件设置共享式的文件忽略,哪些情况通过.git/info/exclude设置只对本地有效的独享式文件忽略,这取决于要设置的文件忽略是否具有普遍意义。如果文件忽略对于所有使用此版本库工作的人都有益,就通过在版本库相应的目录下创建一个.gitignore文件建立忽略;否则,如果是需要忽略工作区中创建的一个试验目录或试验性的文件,则使用本地忽略。

例如,我的本地就设置着一个全局的独享的文件忽略列表(这个文件名可以随意设置):


$git config—global core.excludesfile/home/jiangxin/.gitignore

$git config core.excludesfile

/home/jiangxin/.gitignore

$cat/home/jiangxin/.gitignore

*~#vim临时文件

*.pyc#python的编译文件

.*.mmx#不是正则表达式哦,因为FreeMind-MMX的辅助文件以点开头


5.Git忽略语法

关于Git的忽略文件的语法规则再多说几句:

忽略文件中的空行或以井号(#)开始的行会被忽略。

可以使用通配符,参见Linux手册:glob(7)。例如:星号(*)代表任意多字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围等。

如果名称的最前面是一个路径分隔符(/),表明要忽略的文件在此目录下,而非子目录的文件。

如果名称的最后面是一个路径分隔符(/),表明要忽略的是整个目录,同名文件不忽略,否则同名的文件和目录都忽略。

通过在名称的最前面添加一个感叹号(!),代表不忽略。

下面的文件忽略示例,包含了上述要点:


这是注释行—被忽略

*.a # 忽略所有以.a为扩展名的文件。

!lib.a # 但是lib.a文件或目录不要忽略,即使前面设置了对*.a的忽略。

/TODO # 只忽略此目录下的TODO文件,子目录的TODO文件不忽略。

build/ # 忽略所有build/目录下的文件。

doc/*.txt # 忽略文件如doc/notes.txt,但是文件如doc/server/arch.txt不被忽略。