1. 程式人生 > >Git忽略提交規則

Git忽略提交規則

開發十年,就只剩下這套架構體系了! >>>   

在使用Git的過程中,我們喜歡有的檔案比如日誌,臨時檔案,編譯的中間檔案等不要提交到程式碼倉庫,這時就要設定相應的忽略規則,來忽略這些檔案的提交。簡單來說一個場景:在你使用git add .的時候,遇到了把你不想提交的檔案也新增到了快取中去的情況,比如專案的本地配置資訊,如果你上傳到Git中去其他人pull下來的時候就會和他本地的配置有衝突,所以這樣的個性化配置檔案我們一般不把它推送到git伺服器中,但是又為了偷懶每次新增快取的時候都想用git add .而不是手動一個一個檔案新增,該怎麼辦呢?很簡單,git為我們提供了一個.gitignore檔案只要在這個檔案中申明那些檔案你不希望新增到git中去,這樣當你使用git add .的時候這些檔案就會被自動忽略掉。

有三種方法可以實現忽略Git中不想提交的檔案
1)在Git專案中定義.gitignore檔案
對於經常使用Git的朋友來說,.gitignore配置一定不會陌生。這種方式通過在專案的某個資料夾下定義.gitignore檔案,在該檔案中定義相應的忽略規則,來管理當前資料夾下的檔案的Git提交行為。.gitignore 檔案是可以提交到公有倉庫中,這就為該專案下的所有開發者都共享一套定義好的忽略規則。在.gitingore 檔案中,遵循相應的語法,在每一行指定一個忽略規則。如:

1

2

3

*.log

*.temp

/vendor

2)在Git專案的設定中指定排除檔案
這種方式只是臨時指定該專案的行為,需要編輯當前專案下的 .git/info/exclude檔案,然後將需要忽略提交的檔案寫入其中。需要注意的是,這種方式指定的忽略檔案的根目錄是專案根目錄。

3)定義Git全域性的 .gitignore 檔案
除了可以在專案中定義 .gitignore 檔案外,還可以設定全域性的git .gitignore檔案來管理所有Git專案的行為。這種方式在不同的專案開發者之間是不共享的,是屬於專案之上Git應用級別的行為。這種方式也需要建立相應的 .gitignore 檔案,可以放在任意位置。然後在使用以下命令配置Git:

1

# git config --global core.excludesfile ~/.gitignore

首先要強調一點,這個檔案的完整檔名就是".gitignore",注意最前面有個“.”。一般來說每個Git專案中都需要一個“.gitignore”檔案,這個檔案的作用就是告訴Git哪些檔案不需要新增到版本管理中。實際專案中,很多檔案都是不需要版本管理的,比如Python的.pyc檔案和一些包含密碼的配置檔案等等。這個檔案的內容是一些規則,Git會根據這些規則來判斷是否將檔案新增到版本控制中。

Git忽略檔案的原則
-  忽略作業系統自動生成的檔案,比如縮圖等;
-  忽略編譯生成的中間檔案、可執行檔案等,也就是如果一個檔案是通過另一個檔案自動生成的,那自動生成的檔案就沒必要放進版本庫,比如Java編譯產生的.class檔案;
-  忽略你自己的帶有敏感資訊的配置檔案,比如存放口令的配置檔案。

.gitignore檔案的使用方法
首先,在你的工作區新建一個名稱為.gitignore的檔案。
然後,把要忽略的檔名填進去,Git就會自動忽略這些檔案。
不需要從頭寫.gitignore檔案,GitHub已經為我們準備了各種配置檔案,只需要組合一下就可以使用了。

有時對於git專案下的某些檔案,我們不需要納入版本控制,比如日誌檔案或者IDE的配置檔案,此時可以在專案的根目錄下建立一個隱藏檔案 .gitignore(linux下以.開頭的檔案都是隱藏檔案),然後在.gitignore中寫入需要忽略的檔案。

1

2

3

4

[root@kevin ~]# cat .gitignore

*.xml

*.log

*.apk

.gitignore註釋用'#', *表示匹配0個或多個任意字元,所以上面的模式就是要忽略所有的xml檔案,log檔案和apk檔案。

.gitignore配置檔案用於配置不需要加入版本管理的檔案,配置好該檔案可以為版本管理帶來很大的便利。

.gitignore忽略規則的優先順序
在 .gitingore 檔案中,每一行指定一個忽略規則,Git檢查忽略規則的時候有多個來源,它的優先順序如下(由高到低):
1)從命令列中讀取可用的忽略規則
2)當前目錄定義的規則
3)父級目錄定義的規則,依次遞推
4)$GIT_DIR/info/exclude 檔案中定義的規則
5)core.excludesfile中定義的全域性規則

.gitignore忽略規則的匹配語法
在 .gitignore 檔案中,每一行的忽略規則的語法如下:
1)空格不匹配任意檔案,可作為分隔符,可用反斜槓轉義
2)以“”開頭的行都會被 Git 忽略。即#開頭的檔案標識註釋,可以使用反斜槓進行轉義。
3)可以使用標準的glob模式匹配。所謂的glob模式是指shell所使用的簡化了的正則表示式。
4)以斜槓"/"開頭表示目錄;"/"結束的模式只匹配資料夾以及在該資料夾路徑下的內容,但是不匹配該檔案;"/"開始的模式匹配專案跟目錄;如果一個模式不包含斜槓,則它匹配相對於當前 .gitignore 檔案路徑的內容,如果該模式不在 .gitignore 檔案中,則相對於專案根目錄。
5)以星號"*"通配多個字元,即匹配多個任意字元;使用兩個星號"**" 表示匹配任意中間目錄,比如`a/**/z`可以匹配 a/z, a/b/z 或 a/b/c/z等。
6)以問號"?"通配單個字元,即匹配一個任意字元;
7)以方括號"[]"包含單個字元的匹配列表,即匹配任何一個列在方括號中的字元。比如[abc]表示要麼匹配一個a,要麼匹配一個b,要麼匹配一個c;如果在方括號中使用短劃線分隔兩個字元,表示所有在這兩個字元範圍內的都可以匹配。比如[0-9]表示匹配所有0到9的數字,[a-z]表示匹配任意的小寫字母)。
8)以歎號"!"表示不忽略(跟蹤)匹配到的檔案或目錄,即要忽略指定模式以外的檔案或目錄,可以在模式前加上驚歎號(!)取反。需要特別注意的是:如果檔案的父目錄已經被前面的規則排除掉了,那麼對這個檔案用"!"規則是不起作用的。也就是說"!"開頭的模式表示否定,該檔案將會再次被包含,如果排除了該檔案的父級目錄,則使用"!"也不會再次被包含。可以使用反斜槓進行轉義。

需要謹記:git對於.ignore配置檔案是按行從上到下進行規則匹配的,意味著如果前面的規則匹配的範圍更大,則後面的規則將不會生效;

.gitignore忽略規則簡單說明

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

#               表示此為註釋,將被Git忽略

*.a             表示忽略所有 .a 結尾的檔案

!lib.a          表示但lib.a除外

/TODO           表示僅僅忽略專案根目錄下的 TODO 檔案,不包括 subdir/TODO

build/          表示忽略 build/目錄下的所有檔案,過濾整個build資料夾;

doc/*.txt       表示會忽略doc/notes.txt但不包括 doc/server/arch.txt

 

bin/:           表示忽略當前路徑下的bin資料夾,該資料夾下的所有內容都會被忽略,不忽略 bin 檔案

/bin:           表示忽略根目錄下的bin檔案

/*.c:           表示忽略cat.c,不忽略 build/cat.c

debug/*.obj:    表示忽略debug/io.obj,不忽略 debug/common/io.obj和tools/debug/io.obj

**/foo:         表示忽略/foo,a/foo,a/b/foo

a/**/b:         表示忽略a/b, a/x/b,a/x/y/b

!/bin/run.sh    表示不忽略bin目錄下的run.sh檔案

*.log:          表示忽略所有 .log 檔案

config.php:     表示忽略當前路徑的 config.php 檔案

 

/mtk/           表示過濾整個資料夾

*.zip           表示過濾所有.zip檔案

/mtk/do.c       表示過濾某個具體檔案

 

被過濾掉的檔案就不會出現在git倉庫中(gitlab或github)了,當然本地庫中還有,只是push的時候不會上傳。

 

需要注意的是,gitignore還可以指定要將哪些檔案新增到版本管理中,如下:

!*.zip

!/mtk/one.txt

 

唯一的區別就是規則開頭多了一個感嘆號,Git會將滿足這類規則的檔案新增到版本管理中。為什麼要有兩種規則呢?

想象一個場景:假如我們只需要管理/mtk/目錄中的one.txt檔案,這個目錄中的其他檔案都不需要管理,那麼.gitignore規則應寫為::

/mtk/*

!/mtk/one.txt

 

假設我們只有過濾規則,而沒有新增規則,那麼我們就需要把/mtk/目錄下除了one.txt以外的所有檔案都寫出來!

注意上面的/mtk/*不能寫為/mtk/,否則父目錄被前面的規則排除掉了,one.txt檔案雖然加了!過濾規則,也不會生效!

 

----------------------------------------------------------------------------------

還有一些規則如下:

fd1/*

說明:忽略目錄 fd1 下的全部內容;注意,不管是根目錄下的 /fd1/ 目錄,還是某個子目錄 /child/fd1/ 目錄,都會被忽略;

 

/fd1/*

說明:忽略根目錄下的 /fd1/ 目錄的全部內容;

 

/*

!.gitignore

!/fw/ 

/fw/*

!/fw/bin/

!/fw/sf/

說明:忽略全部內容,但是不忽略 .gitignore 檔案、根目錄下的 /fw/bin/ 和 /fw/sf/ 目錄;注意要先對bin/的父目錄使用!規則,使其不被排除。

溫馨提示:
如果你不慎在建立.gitignore檔案之前就push了專案,那麼即使你在.gitignore檔案中寫入新的過濾規則,這些規則也不會起作用,Git仍然會對所有檔案進行版本管理。簡單來說出現這種問題的原因就是Git已經開始管理這些檔案了,所以你無法再通過過濾規則過濾它們。所以大家一定要養成在專案開始就建立.gitignore檔案的習慣,否則一單push,處理起來會非常麻煩。

.gitignore忽略規則常用示例

1)示例

比如你的專案是java專案,.java檔案編譯後會生成.class檔案,這些檔案多數情況下是不想被傳到倉庫中的檔案。這時候你可以直接適用github的.gitignore檔案模板。https://github.com/github/gitignore/blob/master/Java.gitignore 將這些忽略檔案資訊複製到你的.gitignore檔案中去:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# Compiled class file

*.class

 

# Log file

*.log

 

# BlueJ files

*.ctxt

 

# Mobile Tools for Java (J2ME)

.mtj.tmp/

 

# Package Files #

*.jar

*.war

*.nar

*.ear

*.zip

*.tar.gz

*.rar

 

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml

hs_err_pid*

可以看到github為我們提供了最流行的.gitignore檔案配置。儲存.ignore檔案後我們檢視下git status,檢查下是否還有我們不需要的檔案會被新增到git中去:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

$ git status

On branch master

 

Initial commit

 

Changes to be committed:

  (use "git rm --cached <file>..." to unstage)

 

        new file:   .gitignore

        new file:   HelloWorld.java

 

Untracked files:

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

 

        Config.ini

比如我的專案目錄下有一個Config.ini檔案,這個是個本地配置檔案我不希望上傳到git中去,我們可以在gitignore檔案中新增這樣的配置:

1

Config.ini

或者你想忽略所有的.ini檔案你可以這樣寫:

1

*.ini

如果有些檔案已經被你忽略了,當你使用git add時是無法新增的,比如我忽略了*.class,現在我想把HelloWorld.class新增到git中去:

1

2

3

4

$ git add HelloWorld.class

The following paths are ignored by one of your .gitignore files:

HelloWorld.class

Use -f if you really want to add them.

git會提示我們這個檔案已經被我們忽略了,需要加上-f引數才能強制新增到git中去:

1

2

3

4

5

6

7

8

9

10

11

$ git status

On branch master

 

Initial commit

 

Changes to be committed:

  (use "git rm --cached <file>..." to unstage)

 

        new file:   .gitignore

        new file:   HelloWorld.class

        new file:   HelloWorld.java

這樣就能強制新增到快取中去了。如果我們意外的將想要忽略的檔案新增到快取中去了,我們可以使用rm命令將其從中移除:

1

2

$ git rm HelloWorld.class --cached

rm 'HelloWorld.class'

如果你已經把不想上傳的檔案上傳到了git倉庫,那麼你必須先從遠端倉庫刪了它,我們可以從遠端倉庫直接刪除然後pull程式碼到本地倉庫這些檔案就會本刪除,或者從本地刪除這些檔案並且在.gitignore檔案中新增這些你想忽略的檔案,然後再push到遠端倉庫。

2)示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

下面是曾經線上使用過的一個gerrit裡專案程式碼的.gitignore的配置(在專案中新增.gitignore過濾檔案,在git push到gerrit裡即可)

[wangshibo@gerrit-server hq_ios]$ cat .gitignore

#Built application files

*.apk

*.ap_

  

# Files for the Dalvik VM

*.dex

  

# Java class files

*.class

  

# Generated files

*/bin/

*/gen/

*/out/

  

# Gradle files

.gradle/

build/

*/build/

gradlew

gradlew.bat

  

# Local configuration file (sdk path, etc)

local.properties

  

# Proguard folder generated by Eclipse

proguard/

  

# Log Files

*.log

  

# Android Studio Navigation editor temp files

.navigation/

  

# Android Studio captures folder

captures/

  

# Intellij

*.iml

*/*.iml

  

# Keystore files

#*.jks

#gradle wrapper

gradle/

  

#some local files

*/.settings/

*/.DS_Store

.DS_Store

*/.idea/

.idea/

gradlew

gradlew.bat

unused.txt

3)示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

[wangshibo@gerrit-server hq_ios$ cat .gitignore

# Lines that start with '#' are comments.

# IntelliJ IDEA Project files

.idea

*.iml

*.ipr

*.iws

out

  

# Eclipse Project files

.classpath

.project

.settings/

  

bin/

gen/

local.properties

  

.DS_Store

Thumbs.db

  

*.bak

*.tem

*.temp

#.swp

*.*~

~*.*

.gitignor忽略規則檢視
如果你發下.gitignore寫得有問題,需要找出來到底哪個規則寫錯了,可以用git check-ignore命令檢查:

1

2

$ git check-ignore -v HelloWorld.class

.gitignore:1:*.class    HelloWorld.class

可以看到HelloWorld.class匹配到了我們的第一條*.class的忽略規則所以檔案被忽略了。

簡單來說,要實現過濾掉Git裡不想上傳的檔案,如上介紹三種方法能達到這種目的,只不過適用情景不一樣:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

============第一種方法===========

針對單一工程排除檔案,這種方式會讓這個工程的所有修改者在克隆程式碼的同時,也能克隆到過濾規則,而不用自己再寫一份,

這就能保證所有修改者應用的都是同一份規則,而不是張三自己有一套過濾規則,李四又使用另一套過濾規則,個人比較喜歡這個。

 

配置步驟如下:

在工程根目錄下建立.gitignore檔案,將要排除的檔案或目錄 寫到.gitignore這個檔案中,其中有兩種寫入方法:

 

a)使用命令列增加排除檔案

排除以.class結尾的檔案 echo "*.class" >.gitignore (>> 是在檔案尾增加,> 是刪除已經存在的內容再增加),之後會在當前目錄下

生成一個.gitignore的檔案。排除bin目錄下的檔案 echo "bin/" >.gitignore

 

b)最方便的辦法是,用記事本開啟,增加需要排除的檔案或目錄,一行增加一個,例如:

*.class

*.apk

bin/

gen/

.settings/

proguard/

 

 

===========第二種方法===========

全域性設定排除檔案,這會在全域性起作用,只要是Git管理的工程,在提交時都會自動排除不在控制範圍內的檔案或目錄。這種方法對開發者來說,

比較省事,只要一次全域性配置,不用每次建立工程都要配置一遍過濾規則。但是這不保證其他的開發者在克隆你的程式碼後,他們那邊的規則跟你

的是一樣的,這就帶來了程式碼提交過程中的各種衝突問題。

配置步驟如下:

a)像方法(1)一樣,也需要建立一個.gitignore檔案,把要排除的檔案寫進去。

b)但在這裡,我們不規定一定要把.gitnore檔案放到某個工程下面,而是任何地方,比如我們這裡放到了Git預設的Home路徑下,比如:/home/wangshibo/hqsb_ios

c)使用命令方式可以配置全域性排除檔案:

   # git config --global core.excludesfile ~/.gitignore

   你會發現在~/.gitconfig檔案中會出現excludesfile = /home/wangshibo/hqsb_ios/.gitignore。

   說明Git把檔案過濾規則應用到了Global的規則中。

 

 

===========第三種方法===========

單個工程設定排除檔案,在工程目錄下找到.git/info/exclude,把要排除的檔案寫進去:

*.class

*.apk

bin/

gen/

.settings/

proguard/

 

這種方法就不提倡了,只能針對單一工程配置,而且還不能將過濾規則同步到其他開發者,跟方法一和方法二比較起來沒有一點優勢。

Git忽略規則(.gitignore配置)不生效原因和解決

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

第一種方法:

.gitignore中已經標明忽略的檔案目錄下的檔案,git push的時候還會出現在push的目錄中,或者用git status檢視狀態,想要忽略的檔案還是顯示被追蹤狀態。

原因是因為在git忽略目錄中,新建的檔案在git中會有快取,如果某些檔案已經被納入了版本管理中,就算是在.gitignore中已經聲明瞭忽略路徑也是不起作用的,

這時候我們就應該先把本地快取刪除,然後再進行git的提交,這樣就不會出現忽略的檔案了。

  

解決方法: git清除本地快取(改變成未track狀態),然後再提交:

[root@kevin ~]# git rm -r --cached .

[root@kevin ~]# git add .

[root@kevin ~]# git commit -m 'update .gitignore'

[root@kevin ~]# git push -u origin master

 

需要特別注意的是:

1).gitignore只能忽略那些原來沒有被track的檔案,如果某些檔案已經被納入了版本管理中,則修改.gitignore是無效的。

2)想要.gitignore起作用,必須要在這些檔案不在暫存區中才可以,.gitignore檔案只是忽略沒有被staged(cached)檔案,

   對於已經被staged檔案,加入ignore檔案時一定要先從staged移除,才可以忽略。

 

第二種方法:(推薦)

在每個clone下來的倉庫中手動設定不要檢查特定檔案的更改情況。

[root@kevin ~]# git update-index --assume-unchanged PATH                  //在PATH處輸入要忽略的檔案

在使用.gitignore檔案後如何刪除遠端倉庫中以前上傳的此類檔案而保留本地檔案
在使用git和github的時候,之前沒有寫.gitignore檔案,就上傳了一些沒有必要的檔案,在添加了.gitignore檔案後,就想刪除遠端倉庫中的檔案卻想儲存本地的檔案。這時候不可以直接使用"git rm directory",這樣會刪除本地倉庫的檔案。可以使用"git rm -r –cached directory"來刪除緩衝,然後進行"commit"和"push",這樣會發現遠端倉庫中的不必要檔案就被刪除了,以後可以直接使用"git add -A"來新增修改的內容,上傳的檔案就會受到.gitignore檔案的內容約束。

額外說明:git庫所在的資料夾中的檔案大致有4種狀態

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

Untracked:

未跟蹤, 此檔案在資料夾中, 但並沒有加入到git庫, 不參與版本控制. 通過git add 狀態變為Staged.

 

Unmodify:

檔案已經入庫, 未修改, 即版本庫中的檔案快照內容與資料夾中完全一致. 這種型別的檔案有兩種去處, 如果它被修改,

而變為Modified. 如果使用git rm移出版本庫, 則成為Untracked檔案

 

Modified:

檔案已修改, 僅僅是修改, 並沒有進行其他的操作. 這個檔案也有兩個去處, 通過git add可進入暫存staged狀態,

使用git checkout 則丟棄修改過, 返回到unmodify狀態, 這個git checkout即從庫中取出檔案, 覆蓋當前修改

 

Staged:

暫存狀態. 執行git commit則將修改同步到庫中, 這時庫中的檔案和本地檔案又變為一致, 檔案為Unmodify狀態.

執行git reset HEAD filename取消暫存, 檔案狀態為Modified

 

Git 狀態 untracked 和 not staged的區別

1)untrack     表示是新檔案,沒有被add過,是為跟蹤的意思。

2)not staged  表示add過的檔案,即跟蹤檔案,再次修改沒有add,就是沒有暫存的意思

***************當你發現自己的才華撐不起野心時,就請安靜下來學