現(xiàn)在,讓我們?cè)陧?xiàng)目下創(chuàng)建一個(gè)新的 README 文件。如果之前并不存在這個(gè)文件,使用 git status 命令,將看到一個(gè)新的未跟蹤文件:
$ echo 'My Project'>README$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Untracked files:(use "git add <file>..." to include in what will be committed)READMEnothing added to commit but untracked files present (use "git add" to track)
此時(shí)再運(yùn)行 git status 命令,會(huì)看到 README 文件已被跟蹤,并處于暫存狀態(tài):
$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git restore --staged <file>..." to unstage)newfile:README
只要在 Changes to be committed 這行下面的,就說明是已暫存狀態(tài)。如果此時(shí)提交,那么該文件在運(yùn)行 git add 時(shí)的版本將被留存在后續(xù)的歷史記錄中,可能會(huì)想起之前我們使用 git init 后就運(yùn)行了 git add 命令,開始跟蹤當(dāng)前目錄下的文件。git add 命令使用文件或目錄的路徑作為參數(shù);如果參數(shù)是目錄的路徑,該命令將遞歸地跟蹤該目錄下的所有文件。
④ 暫存已修改的文件
現(xiàn)在來修改一個(gè)已被跟蹤的文件,如果修改了一個(gè)名為 CONTRIBUTING.md 的已被跟蹤的文件,然后運(yùn)行 git status 命令,會(huì)看到下面內(nèi)容:
$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)newfile:READMEChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
文件 CONTRIBUTING.md 出現(xiàn)在 Changes not staged for commit 這行下面,說明已跟蹤文件的內(nèi)容發(fā)生了變化,但還沒有放到暫存區(qū)。要暫存這次更新,需要運(yùn)行 git add 命令,這是個(gè)多功能命令:可以用它開始跟蹤新文件,或者把已跟蹤的文件放到暫存區(qū),還能用于合并時(shí)把有沖突的文件標(biāo)記為已解決狀態(tài)等。將這個(gè)命令理解為“精確地將內(nèi)容添加到下一次提交中”而不是“將一個(gè)文件添加到項(xiàng)目中”要更加合適?,F(xiàn)在來運(yùn)行 git add 將“CONTRIBUTING.md”放到暫存區(qū),然后再看看 git status 的輸出:
$ git add CONTRIBUTING.md$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)newfile:READMEmodified:CONTRIBUTING.md
現(xiàn)在兩個(gè)文件都已暫存,下次提交時(shí)就會(huì)一并記錄到倉庫。假設(shè)此時(shí),想要在 CONTRIBUTING.md 里再加條注釋,重新編輯存盤后,準(zhǔn)備好提交。不過且慢,再運(yùn)行 git status 看看:
$ vim CONTRIBUTING.md$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)newfile:READMEmodified:CONTRIBUTING.mdChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
$ git add CONTRIBUTING.md$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)newfile:READMEmodified:CONTRIBUTING.md
⑤ 狀態(tài)簡(jiǎn)覽
git status 命令的輸出十分詳細(xì),但其用語有些繁瑣。Git 有一個(gè)選項(xiàng)可以幫你縮短狀態(tài)命令的輸出,這樣可以以簡(jiǎn)潔的方式查看更改。如果使用 git status -s 命令或 git status --short 命令,將得到一種格式更為緊湊的輸出:
$ git status -sM READMEMMRakefileA lib/git.rbM lib/simplegit.rb??LICENSE.txt
新添加的未跟蹤文件前面有 ?? 標(biāo)記,新添加到暫存區(qū)中的文件前面有 A 標(biāo)記,修改過的文件前面有 M 標(biāo)記。輸出中有兩欄,左欄指明了暫存區(qū)的狀態(tài),右欄指明了工作區(qū)的狀態(tài)。例如,上面的狀態(tài)報(bào)告顯示: README 文件在工作區(qū)已修改但尚未暫存,而 lib/simplegit.rb 文件已修改且已暫存,Rakefile 文件已修,暫存后又作了修改,因此該文件的修改中既有已暫存的部分,又有未暫存的部分。
如果 git status 命令的輸出過于簡(jiǎn)略,而我們想知道具體修改了什么地方,可以用 git diff 命令。通常可能會(huì)用它來回答這兩個(gè)問題:當(dāng)前做的哪些更新尚未暫存? 有哪些更新已暫存并準(zhǔn)備好下次提交? 雖然 git status 已經(jīng)通過在相應(yīng)欄下列出文件名的方式回答了這個(gè)問題,但 git diff 能通過文件補(bǔ)丁的格式更加具體地顯示哪些行發(fā)生了改變。
假如再次修改 README 文件后暫存,然后編輯 CONTRIBUTING.md 文件后先不暫存, 運(yùn)行 status 命令將會(huì)看到:
$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:READMEChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
要查看尚未暫存的文件更新了哪些部分,不加參數(shù)直接輸入 git diff:
$ git diffdiff --git a/CONTRIBUTING.md b/CONTRIBUTING.mdindex 8ebb991..643e24f 100644--- a/CONTRIBUTING.md+++ b/CONTRIBUTING.md@@ -65,7+65,8 @@ branch directly, things can get messy.Please include a nice description of your changes when you submit your PR;if we have to read the whole diff to figure out why you're contributingin the first place, you're less likely to get feedback and have your change-merged in.+merged in.Also,split your changes into comprehensive chunks if your patch is+longer than a dozen lines.If you are starting to work on a particular area, feel free to submit a PRthat highlights your work in progress (and note in the PR title that it's
像之前說的,暫存 CONTRIBUTING.md 后再編輯,可以使用 git status 查看已被暫存的修改或未被暫存的修改。如果我們的環(huán)境(終端輸出)看起來如下:
$ git add CONTRIBUTING.md$ echo '# test line'>>CONTRIBUTING.md$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:CONTRIBUTING.mdChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
現(xiàn)在運(yùn)行 git diff 看暫存前后的變化:
$ git diffdiff --git a/CONTRIBUTING.md b/CONTRIBUTING.mdindex 643e24f..87f08c8 100644--- a/CONTRIBUTING.md+++ b/CONTRIBUTING.md@@ -119,3+119,4 @@ at the## StarterProjectsSee our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).+# test line
$ git diff --cacheddiff --git a/CONTRIBUTING.md b/CONTRIBUTING.mdindex 8ebb991..643e24f 100644--- a/CONTRIBUTING.md+++ b/CONTRIBUTING.md@@ -65,7+65,8 @@ branch directly, things can get messy.Please include a nice description of your changes when you submit your PR;if we have to read the whole diff to figure out why you're contributingin the first place, you're less likely to get feedback and have your change-merged in.+merged in.Also,split your changes into comprehensive chunks if your patch is+longer than a dozen lines.If you are starting to work on a particular area, feel free to submit a PRthat highlights your work in progress (and note in the PR title that it's
⑧ 提交更新
現(xiàn)在的暫存區(qū)已經(jīng)準(zhǔn)備就緒,可以提交了,在此之前,請(qǐng)務(wù)必確認(rèn)還有什么已修改或新建的文件還沒有 git add 過,否則提交的時(shí)候不會(huì)記錄這些尚未暫存的變化。這些已修改但未暫存的文件只會(huì)保留在本地磁盤。因此,每次準(zhǔn)備提交前,先用 git status 看下,所需要的文件是不是都已暫存起來了, 然后再運(yùn)行提交命令 git commit,這樣會(huì)啟動(dòng)選擇的文本編輯器來輸入提交說明:
$ git commit
編輯器會(huì)顯示類似下面的文本信息(本例選用 Vim 的屏顯方式展示):
# Please enter the commit message for your changes.Lines starting# with '#' will be ignored, and an empty message aborts the commit.# On branch master# Your branch is up-to-date with 'origin/master'.## Changes to be committed:# newfile:README# modified:CONTRIBUTING.md#~~~".git/COMMIT_EDITMSG" 9L, 283C
可以看到,默認(rèn)的提交消息包含最后一次運(yùn)行 git status 的輸出,放在注釋行里,另外開頭還有一個(gè)空行,供輸入提交說明,完全可以去掉這些注釋行,不過留著也沒關(guān)系,多少能幫你回想起這次更新的內(nèi)容有哪些。
$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.mdno changes added to commit (use "git add" and/or "git commit -a")$ git commit -a -m 'added new benchmarks'[master 83e38c7] added newbenchmarks1 file changed,5insertions(+),0deletions(-)
如果只是簡(jiǎn)單地從工作目錄中手工刪除文件,運(yùn)行 git status 時(shí)就會(huì)在 “Changes not staged for commit” 部分(也就是未暫存清單)看到:
$ rm PROJECTS.md$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes not staged for commit:(use "git add/rm <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)deleted:PROJECTS.mdno changes added to commit (use "git add" and/or "git commit -a")
然后再運(yùn)行 git rm 記錄此次移除文件的操作:
$ git rm PROJECTS.mdrm 'PROJECTS.md'$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)deleted:PROJECTS.md
下一次提交時(shí),該文件就不再納入版本管理。如果要?jiǎng)h除之前修改過或已經(jīng)放到暫存區(qū)的文件,則必須使用強(qiáng)制刪除選項(xiàng) -f(譯注:即 force 的首字母),這是一種安全特性,用于防止誤刪尚未添加到快照的數(shù)據(jù),這樣的數(shù)據(jù)不能被 Git 恢復(fù)。
$ git mv README.md README$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.Changes to be committed:(use "git reset HEAD <file>..." to unstage)renamed:README.md ->README
$ git log --pretty=onelineca82a6dff817ec66f44342007202690a93763949 changed the version number085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary testa11bef06a3f659402fe7563abf99ad00de2209e6 first commit
最有意思的是 format ,可以定制記錄的顯示格式,這樣的輸出對(duì)后期提取分析格外有用——因?yàn)橹垒敵龅母袷讲粫?huì)隨著 Git 的更新而發(fā)生改變:
$ git log --pretty=format:"%h - %an, %ar : %s"ca82a6d -ScottChacon,6 years ago : changed the version number085bb3b -ScottChacon,6 years ago : removed unnecessary testa11bef0 -ScottChacon,6 years ago :first commit
$ git log --pretty=format:"%h %s"--graph* 2d3acf9 ignore errors from SIGCHLD on trap* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit|\|* 420eac9 Added a method for getting the current branch.*| 30e367c timeout code and tests*| 5a09431 add timeout protection to grit*| e1193f8 support for heads with slashes in them|/* d6016bc require time for xmlschema* 11d191e Merge branch 'defunkt' into local
如何操作暫存區(qū)和工作目錄中已修改的文件,這些命令在修改文件狀態(tài)的同時(shí),也會(huì)提示如何撤消操作。例如,已經(jīng)修改了兩個(gè)文件并且想要將它們作為兩次獨(dú)立的修改提交,但是卻意外地輸入 git add * 暫存了它們兩個(gè),如何只取消暫存兩個(gè)中的一個(gè)呢? git status 命令提示:
$ git add *$ git statusOn branch masterChanges to be committed:(use "git reset HEAD <file>..." to unstage)renamed:README.md ->READMEmodified:CONTRIBUTING.md
在 “Changes to be committed” 文字正下方,提示使用 git reset HEAD … 來取消暫存,所以,可以這樣來取消暫存 CONTRIBUTING.md 文件:
$ git reset HEADCONTRIBUTING.mdUnstaged changes after reset:M CONTRIBUTING.md$ git statusOn branch masterChanges to be committed:(use "git reset HEAD <file>..." to unstage)renamed:README.md ->READMEChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
如果并不想保留對(duì) CONTRIBUTING.md 文件的修改該怎么辦呢? 該如何方便地撤消修改,將它還原成上次提交時(shí)的樣子(或者剛克隆完的樣子,或者剛把它放入工作目錄時(shí)的樣子)? 幸運(yùn)的是,git status 也告訴了我們應(yīng)該如何做,在例子中,未暫存區(qū)域是這樣:
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:CONTRIBUTING.md
$ git checkout --CONTRIBUTING.md$ git statusOn branch masterChanges to be committed:(use "git reset HEAD <file>..." to unstage)renamed:README.md ->README
$ git remote show origin* remote originURL: https://github.com/my-org/complex-projectFetchURL: https://github.com/my-org/complex-projectPushURL: https://github.com/my-org/complex-projectHEAD branch: masterRemote branches:master trackeddev-branch trackedmarkdown-strip trackedissue-43new(next fetch will store in remotes/origin)issue-45new(next fetch will store in remotes/origin)refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove)Local branches configured for'git pull':dev-branch merges with remote dev-branchmaster merges with remote masterLocal refs configured for'git push':dev-branch pushes to dev-branch (up to date)markdown-strip pushes to markdown-strip (up to date)master pushes to master (up to date)
通過使用 git show 命令可以看到標(biāo)簽信息和與之對(duì)應(yīng)的提交信息,輸出顯示了打標(biāo)簽者的信息、打標(biāo)簽的日期時(shí)間、附注信息,然后顯示具體的提交信息:
$ git show v1.4tag v1.4Tagger:BenStraub<ben@straub.cc>Date:SatMay320:19:122014-0700my version 1.4commit ca82a6dff817ec66f44342007202690a93763949Author:ScottChacon<kody@gee-mail.com>Date:MonMar1721:52:112008-0700changed the version number
$ git show v1.4-lwcommit ca82a6dff817ec66f44342007202690a93763949Author:ScottChacon<kody@gee-mail.com>Date:MonMar1721:52:112008-0700changed the version number
③ 后期打標(biāo)簽
也可以對(duì)過去的提交打標(biāo)簽,假設(shè)提交歷史是這樣的:
$ git log --pretty=oneline15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support0d52aaab4479697da7686c15f77a3d64d9165190 one more thing6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function4682c3261057305bdd616e23b64b0857d832627b added a todo file166ae0c4d3f420721acbb115cc33848dfcc2121a started write support9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
$ git checkout 2.0.0Note: checking out '2.0.0'.You are in'detached HEAD' state.You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.If you want to create a newbranch to retain commits you create, you maydo so (now or later) by using -b with the checkout command again.Example:git checkout -b <new-branch>HEADis now at 99ada87...Merge pull request #89 from schacon/appendix-final$ git checkout 2.0-beta-0.1PreviousHEAD position was 99ada87...Merge pull request #89 from schacon/appendix-finalHEADis now at df3f601... add atlas.json and cover image
$ git config --global alias.unstage 'reset HEAD --'
這會(huì)使下面的兩個(gè)命令等價(jià):
$ git unstage fileA$ git reset HEAD-- fileA
這樣看起來更清楚一些。通常也會(huì)添加一個(gè) last 命令,像這樣:
$ git config --global alias.last'log -1 HEAD'
這樣,可以輕松地看到最后一次提交:
$ git lastcommit 66938dae3329c7aebe598c2246a8e6af90d04646Author:JoshGoebel<dreamer3@example.com>Date:TueAug2619:48:512008+0800test for current headSigned-off-by:ScottChacon<kody@example.com>