手把手帶你玩git之gitignore

內容提要

  • 忽略文件
  • 忽略目錄的四種不同方式
  • /mytmp
  • /mytmp/*
  • **/mytmp
  • **/mytmp/*
  • 例外
  • ! 表示例外;
  • 作用于/mytmp/*,不能作用于/mytmp
  • ignore 生效的前提
  • 通配符語法
  • 一個星表示任意字符;
  • 兩個星表示任意路徑
  • 兩種形式:共享式和獨享式
  • 官方模板

語法

當我們進行代碼開發時,把代碼存到遠程代碼庫上。但是總有一些代碼是不需要上傳的,比如編譯的中間文件,單元測試自動生成的測試報告等。這個時候我們需要告訴git,哪些文件應該忽略,git提供了這種機制,它通過.gitignore 配置文件來實現。通常該文件放在項目的根目錄下,我們可以手動創建它,然后編輯內容。

忽略文件

.gitignore文件中編輯:

#.gitignore for java
*.class

第一行以#開頭的是注釋,*.class 表示忽略“所有”以.class為后綴的文件(其中*號表示glob模式匹配的通配符)。這里的“所有”無論它在哪個目錄下。

實驗驗證下,創建多級子目錄,每個目錄創建一個.class文件,結構如下:

?  demo-gitignore git:(master) tree
.
├── L1.class
└── child1
    ├── L2.class
    └── child2
        ├── L3.class
        └── child3
            └── L4.class

3 directories, 4 files

執行git status,看看有沒有被忽略?

?  demo-gitignore git:(master) git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)

當然也可以不用通配符,例如

# project specified gitignore
Hello.xml

表示忽略“所有”名字叫Hello.xml的文件。

忽略目錄

語法上,以/開頭的表示忽略目錄。比如/mytmp表示忽略“根目錄下”名叫mytmp的目錄,并非表示“所有”。

在上述3個childX目錄下,各自創建一個mytmp子目錄(實驗時請勿用tmp,以免用戶目錄下的~/.gitignore已經配置過忽略tmp),并在每個mytmp目錄下創建Hello.xml文件(因為如果沒有文件,git不會理會空目錄的)。

形如:

demo-gitignore
├── child1
│   ├── child2
│   │   ├── child3
│   │   │   └── mytmp
│   │   │       └── Hello.xml
│   │   └── mytmp
│   │       └── Hello.xml
│   └── mytmp
│       └── Hello.xml
└── mytmp
    └── Hello.xml

?  demo-gitignore git:(master) ? git status -s
?? child1/
?? mytmp/

.gitignore中添加/mytmp忽略后,再看status:

?  demo-gitignore git:(master) ? git status -s
 M .gitignore
?? child1/

首先發現?? mytmp/已經不見了(被忽略了)。第一行.gitignore的變化是因為剛添加/mytmp,尚未提交;第二行?? child1/為什么還在?因為我們只是忽略了/mytmp目錄,并沒有忽略其下的文件Hello.xml?其實是只忽略根目錄下的/mytmp,子目錄下的/mytmp并不被忽略。

?  demo-gitignore git:(master) ? git add child1
?  demo-gitignore git:(master) ? git status -s
 M .gitignore
A  child1/child2/child3/mytmp/Hello.xml
A  child1/child2/mytmp/Hello.xml
A  child1/mytmp/Hello.xml

上述唯獨沒有提到根目錄demo-gitignore下的mytmp目錄。如果要讓所有目錄下的mytmp目錄都被忽略呢? 前綴加兩個*號(即:**)。

# project specified gitignore
**/mytmp

此時mytmp,都不再顯示,無論是哪級子目錄:

?  demo-gitignore git:(master) ? git status -s
 M .gitignore

如果我們要“排除(不忽略)” /child1/child2/mytmp 目錄呢?
!/child1/child2/mytmp排除。

# project specified gitignore
**/mytmp
!/child1/child2/mytmp

結果驗證如下:

?  demo-gitignore git:(master) ? git status -s
 M .gitignore
A  child1/child2/mytmp/Hello.xml

總結備忘

/開頭忽略目錄,表示當前。例如/mytmp表示忽略根目錄下的mytmp。
**/開頭,忽略所有目錄。例如**/mytmp表示忽略所有層級下的mytmp目錄。
!開頭表示例外。例如!/child1/child2/mytmp表示單獨強調“不忽略”/child1/child2/mytmp的 mytmp 目錄。

忽略的例外

如前文所說,例外用!表示。這里補充下關于“文件”的例外。在上述的實驗環境中,新創建文件 demo-gitignore/mytmp/HelloExpectional.xml,并配置.gitignore如下:

# project specified gitignore
/mytmp/*
!/mytmp/HelloExpectional.xml

它表示忽略根目錄/下的mytmp子目錄下的所有文件(星號表示),但是/mytmp/HelloExpectional.xml文件例外(不忽略)。

?  demo-gitignore git:(master) ? git add .
?  demo-gitignore git:(master) ? git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   .gitignore
    new file:   child1/child2/child3/mytmp/Hello.xml
    new file:   child1/child2/mytmp/Hello.xml
    new file:   child1/mytmp/Hello.xml
    new file:   mytmp/HelloExpectional.xml

如上結果,只有mytmp/Hello.xml被忽略。如預期。如果要所有mytmp呢?用**/tmp呀。

為什么ignore 沒生效?

緊接著上面,把.gitignore內容修改為:

# project specified gitignore
**/mytmp/*
!/mytmp/HelloExpectional.xml

查看status,發現并沒有變化?

?  demo-gitignore git:(master) ? git status -s
MM .gitignore
A  child1/child2/child3/mytmp/Hello.xml
A  child1/child2/mytmp/Hello.xml
A  child1/mytmp/Hello.xml
A  mytmp/HelloExpectional.xml

預期應該是只有mytmp/HelloExceptional.xml不被忽略,其他均被忽略。新配置為什么沒生效?因為前文git add .的時候,已經加入git索引了,gitignore只能對untracked狀態的資源起作用。

先把他們從tracked (to be committed) 中撤掉:

?  demo-gitignore git:(master) ? git rm --cached -r child1
rm 'child1/child2/child3/mytmp/Hello.xml'
rm 'child1/child2/mytmp/Hello.xml'
rm 'child1/mytmp/Hello.xml'
?  demo-gitignore git:(master) ? git rm --cached -r mytmp
rm 'mytmp/HelloExpectional.xml'
?  demo-gitignore git:(master) ?

命令解釋如下:

git rm --cached 表示直接刪除“索引區”的內容(不是導出到Working dir,也不是提交到版本庫)。后面接文件,表示操作對象;-r是當操作對象為目錄時,表示遞歸。

接著實驗看看新的ignore規則:

?  demo-gitignore git:(master) ? git add .
?  demo-gitignore git:(master) ? git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   .gitignore
    new file:   mytmp/HelloExpectional.xml

目錄忽略,它的子目錄和文件呢?

當我們忽略一個目錄時,它下面的子目錄和文件也一起被忽略嗎?

demo-gitignore/mytmp創建一級子目錄son-of-mytmp和二級子目錄grandson-of-mytmp,并各自放一個文件,如下結構:

?  demo-gitignore git:(master) ? tree mytmp
mytmp
├── Hello.xml
├── HelloExpectional.xml
└── son-of-mytmp
    ├── grandson-of-mytmp
    │   └── grandson.xml
    └── son.xml

2 directories, 4 files

ignore配置:

# project specified gitignore
/mytmp
!/mytmp/HelloExpectional.xml

查看狀態:

?  demo-gitignore git:(master) ? git status -s
 M .gitignore
?? child1/

的的確確 根目錄下的mytmp目錄及其子目錄,都被忽略了。但與此同時奇怪的是!/mytmp/HelloExpectional.xml“例外設置”并沒有生效?

如果調整 ignore 設置:

# project specified gitignore
/mytmp/*
!/mytmp/HelloExpectional.xml

/mytmp調整為/mytmp/*,結果例外生效了。

?  demo-gitignore git:(master) ? git add .
?  demo-gitignore git:(master) ? git status -s
M  .gitignore
A  child1/child2/child3/mytmp/Hello.xml
A  child1/child2/mytmp/Hello.xml
A  child1/mytmp/Hello.xml
A  mytmp/HelloExpectional.xml

總結備忘

忽略目錄/mytmp/mytmp/*,都會遞歸影響其子目錄和文件的忽略。
只有/mytmp/*忽略,才能添加形如!/mytmp/HelloExpectional.xml的例外。

glob模式語法

所謂“glob模式”就是我們常見的bash下簡化的正則表達式。就4招:

  • 星號 *,通配多個字符;
  • 兩個星號**,表示任意中間層目錄。例如a/**/z 可以匹配目錄a/z, a/b/za/b/c/z等。
  • 問號?,通配單個字符;
  • 方號[],枚舉單個字符。例如[abc]表示要么a,要么b,要么c,但是ab兩個字符是不能匹配的,只能是1個。
  • 范圍[0-9][a-z] 表示任意一個數字或字母。
  • 嘆號!,表示“取反”,表示“不忽略”的語義。

使用習慣

基本概念

  • .gitignore 文件是項目根目錄下的一個隱藏文件,不是.git子目錄下的。
  • .gitignore 文件對其所在的目錄及其全部子目錄均有效。當然用戶級HOME目錄下~/.gitignore文件全局有效,項目的ignore繼承覆蓋用戶級的。
  • 配置文件.gitignore本身需要加入版本庫,以便其他組員能共享同一套資源忽略管理規則。
?  demo-gitignore git:(master) ? touch .gitignore
?  demo-gitignore git:(master) ? git status -s
?? .gitignore
?  demo-gitignore git:(master) ? git add .gitignore
?  demo-gitignore git:(master) ? git commit .gitignore -m 'create project specified gitignore conf'

共享式 與 獨享式

ignore 規則既可以選擇“共享式”讓全組員使用同樣的規則(文件位置是項目根目錄下的.gitignore文件),好處是大家的配置一樣,不好是.gitignore內容太多,維護太累。也可以選擇“獨享式”,只對自己生效,其他組員看不到(因為都不上傳到版本庫)。“獨享式”有兩種形式:

  • 用戶級的 位置在~/.gitignore 用戶HOME目錄下;
  • 項目級的 位置在.git/info/exclude,它也是一個ignore文件,語法規則是一樣的。注意:盡管.git目錄一定是要上傳到版本庫的(它就是版本庫本身),但是卻留下了exclue是不上傳的。感覺.git的設計者很有用心。

那我們什么時候共享式,什么時候獨享式呢?個人覺得,更多的是團隊的一個約定。我們可以先對需要ignore的東西,做個大致分類:

  • 操作系統層面的 比如Mac OS的 .DS_Store, windows的Thumbs.db
  • IDE層面的 比如Eclipse的.project, .settings/.classpath。 IDE層面還包括“樸素IDE”,比如臨時用VIM應急修改了個東西,意外的閃崩生成了一個.swap文件或有些編輯器會生成.bak備份文件。
  • 中間結果類 比如程序運行一下,就打些日志到文件。再比如嵌入式數據庫生成的臨時文件。
  • 語言相關的 剛說的“中間結果”日志類的是通用的,無論哪種語言開發的程序都會輸出日志,除此外,還有喝多跟語言編譯相關的,比如JAVA的.class字節碼,比如Web項目構建時生成的.war包。

了解這些后,或許我們可以把前面兩類作為“獨享式”只作用于自己本地,比如你用Mac那你配Mac的ignore,用Eclipse配Eclipse的;別人用Window,他自己配置Windows的。然后把中間結果和語言相關的,弄成“共享式”的,在全組員中共享。

這么多配置需要我們自己寫嗎? 當然不用,這些問題很多開發者都是要遇到同樣的問題的,把各種環境窮舉下? 事實上有人給我們做了。

官方ignore模板

官方提供ignore模板 https://github.com/github/gitignore

它的組織形式就是按上文說的“分層組織”。比如:

  • 系統層
  • IDE層
  • 語言層

附錄1:如何刪除已經提交,但不需要提交的資源?

盡管提倡項目開始的時候,就需要對資源ignore 規則進行設置。但是現實常常沒有那么理想,往往提交后才發現提交了一些不應該提交的東西。怎么刪除它們?

首先要區分兩類刪除:

  • 真的不需要的,比如每次編譯產生的 .class,這些文件真的不需要。

  • 需要,但不想提交到版本庫的。比如某些臨時的document,你打算提交到wiki,而不是版本庫。

  • 找出“已經提交,但不需要提交的”資源

從遠程拷貝一份。之所以這么做,不用當前本地的,是因為ignore規則的存在,本地一定與遠程不是完全一致的(從文件系統的角度說的完全一致,不是git diff角度)。

git clone  http://10.77.144.192:11824/blueocean/passport.git

然后,比如假設我們之前誤提交了.class文件,那么需要找出:

find . -name "*.class"

發現./WebRoot/WEB-INF/classes/ 下面居然有,刪除它們。同時在新拷貝的和本地現有的都刪除。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,776評論 18 139
  • 本文為 Git教程的學習筆記,教程源自廖雪峰的博客。這是一個由淺入深,學完后能立刻上手的Git教程。另,附上另一本...
    七弦桐語閱讀 6,262評論 5 47
  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,688評論 9 163
  • November012013-11-01 20:47:02|分類:大學日記|字號訂閱 今天院里迎新晚會,剛開始...
    獨行向日葵閱讀 286評論 0 1
  • 不做人, 來到人世干什么。 不做自己, 做人又是為什么。 不投入, 不能成功。 不遁出, 一切沒用。 不做自己, ...
    再湊熱鬧閱讀 143評論 0 0