@
1、克隆現有倉庫:git clone
還是以之前做好的為例:
git clone git@github.com:2021AY/testfirst.git
現在我們的機器上有了一個 真實項目 的 Git 倉庫,並從這個倉庫中檢出了所有文件的 工作副本。通常,你會對這些文件做些修改,每當完成了一個階段的目標,想要將記錄下它時,就將它提交到到倉庫。
工作目錄下的每一個文件都不外乎這兩種狀態:已跟蹤 或 未跟蹤。已跟蹤的文件是指那些被納入了版本控制的文件,在上一次快照中有它們的記錄,在工作一段時間后,它們的狀態可能是未修改,已修改或已放入暫存區。簡而言之,已跟蹤的文件就是 Git 已經知道的文件。
工作目錄中除已跟蹤文件外的其它所有文件都屬於未跟蹤文件,它們既不存在於上次快照的記錄中,也沒有被放入暫存區。初次克隆某個倉庫的時候,工作目錄中的所有文件都屬於已跟蹤文件,並處於未修改狀態,因為 Git 剛剛檢出了它們, 而你尚未編輯過它們。
編輯過某些文件之后,由於自上次提交后你對它們做了修改,Git 將它們標記為已修改文件。工作時,你可以選擇性地將這些修改過的文件放入暫存區,然后提交所有已暫存的修改,如此反復。
2、檢查當前文件狀態 :git status
可以用 git status 命令查看哪些文件處於什么狀態。 如果在克隆倉庫后立即使用此命令,會看到類似這樣的輸出:
這說明你現在的工作目錄相當干凈。換句話說,所有已跟蹤文件在上次提交后都未被更改過。 此外,上面的信息還表明,當前目錄下沒有出現任何處於未跟蹤狀態的新文件,否則 Git 會在這里列出來。 最后,該命令還顯示了當前所在分支,並告訴你這個分支同遠程服務器上對應的分支沒有偏離。 現在,分支名是“main
”,這是默認的分支名。
在項目下創建一個新的 Excel.xlsx 文件
。 如果之前並不存在這個文件,使用 git status
命令,你將看到一個新的未跟蹤文件:
在狀態報告中可以看到新建的 Excel.xlsx
文件出現在 Untracked files
下面。 未跟蹤的文件意味着 Git 在之前的快照(提交)中沒有這些文件;Git 不會自動將之納入跟蹤范圍,除非你明明白白地告訴它“我需要跟蹤該文件”。 這樣的處理讓你不必擔心將生成的二進制文件或其它不想被跟蹤的文件包含進來。
3、跟蹤新文件:git add
使用命令 git add
開始跟蹤一個文件。 所以,要跟蹤 Excel.xlsx
文件,運行:git add Excel.xlsx
此時再運行 git status
命令,會看到 Excel.xlsx
文件已被跟蹤,並處於暫存狀態:
只要在 Changes to be committed
這行下面的,就說明是已暫存狀態。 如果此時提交,那么該文件在你運行 git add
時的版本將被留存在后續的歷史記錄中。 git add
命令使用文件或目錄的路徑作為參數;如果參數是目錄的路徑,該命令將遞歸地跟蹤該目錄下的所有文件。
4、暫存已修改的文件:git add
現在我們來修改一個已被跟蹤的文件。 如果你修改了一個名為 README.md
的已被跟蹤的文件,然后運行 git status
命令,會看到下面內容:
文件 README.md
出現在 Changes not staged for commit
這行下面,說明已跟蹤文件的內容發生了變化,但還沒有放到暫存區。 要暫存這次更新,需要運行 git add
命令。 這是個多功能命令:可以用它開始跟蹤新文件,或者把已跟蹤的文件放到暫存區,還能用於合並時把有沖突的文件標記為已解決狀態等。 將這個命令理解為“精確地將內容添加到下一次提交中”而不是“將一個文件添加到項目中”要更加合適。 現在讓我們運行 git add
將“README.md
”放到暫存區,然后再看看 git status
的輸出:
現在兩個文件都已暫存,下次提交時就會一並記錄到倉庫。 假設此時,你想要在 README.md
里再加條注釋。 重新編輯存盤后,准備好提交。 不過且慢,再運行 git status
看看:
怎么回事? 現在 README.md
文件同時出現在暫存區和非暫存區。 這怎么可能呢? 好吧,實際上 Git 只不過暫存了你運行 git add
命令時的版本。 如果你現在提交,README.md
的版本是你最后一次運行 git add
命令時的那個版本,而不是你運行 git commit
時,在工作目錄中的當前版本。 所以,運行了 git add
之后又作了修訂的文件,需要重新運行 git add
把最新版本重新暫存起來:
5、狀態簡覽: git status -s
git status
命令的輸出十分詳細,但其用語有些繁瑣。 Git 有一個選項可以幫你縮短狀態命令的輸出,這樣可以以簡潔的方式查看更改。 如果你使用 git status -s
命令或 git status --short
命令,你將得到一種格式更為緊湊的輸出。
新建newfile.txt文件,修改two.txt文件並保存后:
修改test.txt 並存盤后:
暫存test.txt后:
再次修改test.txt后:
新添加的未跟蹤文件前面有 ?? 標記,新添加到暫存區中的文件前面有 A 標記,修改過的文件前面有 M 標記。 輸出中有兩欄,左欄指明了暫存區的狀態,右欄指明了工作區的狀態。
例如,上面的狀態報告顯示: two.txt 文件在工作區已修改但尚未暫存,而 Excel.xlsx 文件已修改且已暫存。 test.txt 文件已修,暫存后又作了修改,因此該文件的修改中既有已暫存的部分,又有未暫存的部分。
6、忽略文件:.gitignore
一般我們總會有些文件無需納入 Git 的管理,也不希望它們總出現在未跟蹤文件列表。 通常都是些自動生成的文件,比如日志文件,或者編譯過程中創建的臨時文件等。 在這種情況下,我們可以創建一個名為 .gitignore
的文件,列出要忽略的文件的模式。 來看一個實際的 .gitignore
例子:
$ cat .gitignore
*.[oa]
*~
第一行告訴 Git 忽略所有以 .o
或 .a
結尾的文件。一般這類對象文件和存檔文件都是編譯過程中出現的。
第二行告訴 Git 忽略所有名字以波浪符(~
)結尾的文件,許多文本編輯軟件(比如 Emacs
)都用這樣的文件名保存副本。 此外,你可能還需要忽略 log
,tmp
或者 pid
目錄,以及自動生成的文檔等等。
要養成一開始就為你的新倉庫設置好 .gitignore
文件的習慣,以免將來誤提交這類無用的文件。
文件 .gitignore
的格式規范如下:
- 所有空行或者以 # 開頭的行都會被 Git 忽略。
- 可以使用標准的
glob
模式匹配,它會遞歸地應用在整個工作區中。 - 匹配模式可以以(/)開頭防止遞歸。
- 匹配模式可以以(/)結尾指定目錄。
- 要忽略指定模式以外的文件或目錄,可以在模式前加上嘆號(!)取反。
所謂的 glob
模式是指 shell
所使用的簡化了的正則表達式。 星號(*
)匹配零個或多個任意字符;[abc]
匹配任何一個列在方括號中的字符 (這個例子要么匹配一個 a,要么匹配一個 b,要么匹配一個 c); 問號(?
)只匹配一個任意字符;如果在方括號中使用短划線分隔兩個字符, 表示所有在這兩個字符范圍內的都可以匹配(比如 [0-9]
表示匹配所有 0 到 9 的數字)。 使用兩個星號(**
)表示匹配任意中間目錄,比如 a/**/z
可以匹配 a/z
、 a/b/z
或 a/b/c/z
等。
我們再看一個 .gitignore 文件的例子:
# 忽略所有的 .a 文件
*.a
# 跟蹤所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略當前目錄下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目錄下名為 build 的文件夾
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目錄及其所有子目錄下的 .pdf 文件
doc/**/*.pdf
GitHub
有一個十分詳細的針對數十種項目及語言的 .gitignore
文件列表:https://github.com/github/gitignore
7、查看已暫存和未暫存的修改:git diff
如果 git status
命令的輸出對於你來說過於簡略,而你想知道具體修改了什么地方,可以用 git diff
命令。 稍后我們會詳細介紹 git diff
,你通常可能會用它來回答這兩個問題:當前做的哪些更新尚未暫存? 有哪些更新已暫存並准備好下次提交? 雖然 git status
已經通過在相應欄下列出文件名的方式回答了這個問題,但 git diff
能通過文件補丁的格式更加具體地顯示哪些行發生了改變。
假如再次修改 README.md
文件后暫存,然后編輯 test.txt
文件后先不暫存, 運行 status
命令將會看到:
要查看尚未暫存的文件更新了哪些部分,不加參數直接輸入 git diff
,此命令比較的是工作目錄中當前文件和暫存區域快照之間的差異。 也就是修改之后還沒有暫存起來的變化內容。
若要查看已暫存的將要添加到下次提交里的內容,可以用 git diff --staged
命令。 這條命令將比對已暫存文件與最后一次提交的文件差異:
請注意,git diff
本身只顯示尚未暫存的改動,而不是自上次提交以來所做的所有改動。 所以有時候你一下子暫存了所有更新過的文件,運行 git diff 后卻什么也沒有,就是這個原因。
像之前說的,暫存 README.md
后再編輯,可以使用 git status
查看已被暫存的修改或未被暫存的修改。
修改README.md
:
暫存README.md
:
暫存README.md
后再修改:
此時我們的環境(終端輸出)看起來如下:
現在運行 git diff
看暫存前后的變化:(綠色為尚未暫存的)
然后用 git diff --cached
查看已經暫存起來的變化( --staged
和 --cached
是同義詞):(綠色是已經暫存的)
Git Diff 的插件版本: 使用
git diff
來分析文件差異,也可以使用圖形化的工具或外部 diff 工具來比較差異。 可以使用git difftool
命令來調用emerge
或vimdiff
等軟件(包括商業軟件)輸出 diff 的分析結果。 使用git difftool --tool-help
命令來看你的系統支持哪些 Git Diff 插件。
8、提交更新:git commit
現在的暫存區已經准備就緒,可以提交了。 在此之前,請務必確認還有什么已修改或新建的文件還沒有 git add
過, 否則提交的時候不會記錄這些尚未暫存的變化。 這些已修改但未暫存的文件只會保留在本地磁盤。 所以,每次准備提交前,先用 git status
看下,你所需要的文件是不是都已暫存起來了, 然后再運行提交命令 git commit
:
$ git commit
這樣會啟動你選擇的文本編輯器來輸入提交說明:
可以看到,默認的提交消息包含最后一次運行 git status 的輸出,放在注釋行里,另外開頭還有一個空行,供你輸入提交說明。 你完全可以去掉這些注釋行,不過留着也沒關系,多少能幫你回想起這次更新的內容有哪些。
Git(4)-- 如何退出 git log 和 git commit 狀態
退出編輯器時,Git 會丟棄注釋行,用你輸入的提交說明生成一次提交。
另外,你也可以在 commit
命令后添加 -m
選項,將提交信息與命令放在同一行,如下所示:git commit -m "FIRST time commit"
好,現在你已經創建了第一個提交! 可以看到,提交后它會告訴你,當前是在哪個分支(main
)提交的,本次提交的完整 SHA-1
校驗和是什么(7fa71a1
),以及在本次提交中,有多少文件修訂過,多少行添加和刪改過。
請記住,提交時記錄的是放在暫存區域的快照。 任何還未暫存文件的仍然保持已修改狀態,可以在下次提交時納入版本管理。 每一次運行提交操作,都是對你項目作一次快照,以后可以回到這個狀態,或者進行比較。
9、跳過使用暫存區域:git commit -a
盡管使用暫存區域的方式可以精心准備要提交的細節,但有時候這么做略顯繁瑣。 Git 提供了一個跳過使用暫存區域的方式, 只要在提交的時候,給 git commit
加上 -a
選項,Git 就會自動把所有已經跟蹤過的文件暫存起來一並提交,從而跳過 git add
步驟:
git commit -a -m "skip add commit"
看到了嗎?提交之前不再需要 git add
文件“testdiff.txt
”了。 這是因為 -a
選項使本次提交包含了所有修改過的文件。 這很方便,但是要小心,有時這個選項會將不需要的文件添加到提交中。
10、移除文件:git rm
要從 Git 中移除某個文件,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區域移除),然后提交。 可以用 git rm
命令完成此項工作,並連帶從工作目錄中刪除指定的文件,這樣以后就不會出現在未跟蹤文件清單中了。
如果只是簡單地從工作目錄中手工刪除文件,運行 git status
時就會在 “Changes not staged for commit
” 部分(也就是 未暫存清單)看到:
然后再運行 git rm
記錄此次移除文件的操作:
下一次提交時,該文件就不再納入版本管理了。 如果要刪除之前修改過或已
經放到暫存區的文件,則必須使用強制刪除選項 -f
(即 force
的首字母)。 這是一種安全特性,用於防止誤刪尚未添加到快照的數據,這樣的數據不能被 Git 恢復。
另外一種情況是,我們想把文件從 Git 倉庫中刪除(亦即從暫存區域移除),但仍然希望保留在當前工作目錄中。 換句話說,你想讓文件保留在磁盤,但是並不想讓 Git 繼續跟蹤。 當你忘記添加 .gitignore
文件,不小心把一個很大的日志文件或一堆 .a
這樣的編譯生成文件添加到暫存區時,這一做法尤其有用。 為達到這一目的,使用 --cached
選項:
git rm --cached testdiff.txt
git rm
命令后面可以列出文件或者目錄的名字,也可以使用 glob
模式。比如:
$ git rm log/\*.log
注意到星號 *
之前的反斜杠 \
, 因為 Git 有它自己的文件模式擴展匹配方式,所以我們不用 shell
來幫忙展開。 此命令刪除 log/
目錄下擴展名為 .log
的所有文件。 類似的比如:
$ git rm \*~
該命令會刪除所有名字以 ~
結尾的文件。
11、移動(重命名)文件:git mv file_from file_to
git mv
命令用於移動或重命名一個文件、目錄或軟連接。
不像其它的 VCS 系統,Git 並不顯式跟蹤文件移動操作。 如果在 Git 中重命名了某個文件,倉庫中存儲的元數據並不會體現出這是一次改名操作。 不過 Git 非常聰明,它會推斷出究竟發生了什么。
要在 Git 中對文件改名,可以這么做:git mv file_from file_to
它會恰如預期般正常工作。 實際上,即便此時查看狀態信息,也會明白無誤地看到關於重命名操作的說明: git mv test.txt testnew.txt
其實,運行 git mv
就相當於運行了下面三條命令:
$ mv test.txt testnew.txt
$ git rm test.txt
$ git add testnew.txt
如此分開操作,Git 也會意識到這是一次重命名,所以不管何種方式結果都一樣。 兩者唯一的區別是,mv
是一條命令而非三條命令,直接用 git mv
方便得多。 不過有時候用其他工具批處理重命名的話,要記得在提交前刪除舊的文件名,再添加新的文件名。