日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Git之深入解析本地仓库的基本操作·仓库的获取更新和提交历史的查看撤销以及标签别名的使用

發(fā)布時(shí)間:2024/5/21 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Git之深入解析本地仓库的基本操作·仓库的获取更新和提交历史的查看撤销以及标签别名的使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、獲取 Git 倉庫

  • 通常有兩種獲取 Git 項(xiàng)目倉庫的方式:
    • 將尚未進(jìn)行版本控制的本地目錄轉(zhuǎn)換為 Git 倉庫;
    • 從其它服務(wù)器克隆一個(gè)已存在的 Git 倉庫。
  • 兩種方式都會(huì)在本地機(jī)器上得到一個(gè)工作就緒的 Git 倉庫。

① 在已存在目錄中初始化倉庫

  • 如果有一個(gè)尚未進(jìn)行版本控制的項(xiàng)目目錄,想要用 Git 來控制它,那么首先需要進(jìn)入該項(xiàng)目目錄中。如果還沒這樣做過,那么不同系統(tǒng)上的做法有些不同:
    • 在 Linux 上:
$ cd /home/user/my_project
    • 在 macOS 上:
$ cd /Users/user/my_project
    • 在 Windows 上:
$ cd /c/user/my_project
  • 之后執(zhí)行:
$ git init
  • 該命令將創(chuàng)建一個(gè)名為 .git 的子目錄,這個(gè)子目錄含有初始化的 Git 倉庫中所有的必須文件,這些文件是 Git 倉庫的骨干。但是,在這個(gè)時(shí)候,僅僅是做了一個(gè)初始化的操作,項(xiàng)目里的文件還沒有被跟蹤。
  • 如果在一個(gè)已存在文件的文件夾(而非空文件夾)中進(jìn)行版本控制,應(yīng)該開始追蹤這些文件并進(jìn)行初始提交??梢酝ㄟ^ git add 命令來指定所需的文件來進(jìn)行追蹤,然后執(zhí)行 git commit :
$ git add *.c$ git add LICENSE$ git commit -m 'initial project version'
  • 現(xiàn)在,已經(jīng)得到了一個(gè)存在被追蹤文件與初始提交的 Git 倉庫。

② 克隆現(xiàn)有的倉庫

  • 如果想獲得一份已經(jīng)存在了的 Git 倉庫的拷貝,比如說,如果想為某個(gè)開源項(xiàng)目貢獻(xiàn)自己的一份力,這時(shí)就要用到 git clone 命令。如果對(duì)其它的 VCS 系統(tǒng)(比如說 Subversion)很熟悉,請(qǐng)留心一下所使用的命令是“clone”而不是“checkout”。這是 Git 區(qū)別于其它版本控制系統(tǒng)的一個(gè)重要特性,Git 克隆的是該 Git 倉庫服務(wù)器上的幾乎所有數(shù)據(jù),而不是僅僅復(fù)制完成工作所需要文件。
  • 當(dāng)執(zhí)行 git clone 命令的時(shí)候,默認(rèn)配置下遠(yuǎn)程 Git 倉庫中的每一個(gè)文件的每一個(gè)版本都將被拉取下來。事實(shí)上,如果服務(wù)器的磁盤壞掉了,通常可以使用任何一個(gè)克隆下來的用戶端來重建服務(wù)器上的倉庫 (雖然可能會(huì)丟失某些服務(wù)器端的鉤子(hook)設(shè)置,但是所有版本的數(shù)據(jù)仍在)。
  • 克隆倉庫的命令是 git clone 。比如,要克隆 Git 的鏈接庫 libgit2,可以用下面的命令:
$ git clone https://github.com/libgit2/libgit2
  • 這會(huì)在當(dāng)前目錄下創(chuàng)建一個(gè)名為 “l(fā)ibgit2” 的目錄,并在這個(gè)目錄下初始化一個(gè) .git 文件夾,從遠(yuǎn)程倉庫拉取下所有數(shù)據(jù)放入 .git 文件夾,然后從中讀取最新版本的文件的拷貝。如果進(jìn)入到這個(gè)新建的 libgit2 文件夾,會(huì)發(fā)現(xiàn)所有的項(xiàng)目文件已經(jīng)在里面了,準(zhǔn)備就緒等待后續(xù)的開發(fā)和使用。
  • 如果想在克隆遠(yuǎn)程倉庫的時(shí)候,自定義本地倉庫的名字,可以通過額外的參數(shù)指定新的目錄名:
$ git clone https://github.com/libgit2/libgit2 mylibgit
  • 這會(huì)執(zhí)行與上一條命令相同的操作,但目標(biāo)目錄名變?yōu)榱?mylibgit。Git 支持多種數(shù)據(jù)傳輸協(xié)議,上面的例子使用的是 https:// 協(xié)議,不過也可以使用 git:// 協(xié)議或者使用 SSH 傳輸協(xié)議,比如 user@server:path/to/repo.git。

二、記錄每次更新到倉庫

① 文件的狀態(tài)變化周期

  • 現(xiàn)在我們的機(jī)器上有了一個(gè)真實(shí)項(xiàng)目的 Git 倉庫,并從這個(gè)倉庫中檢出了所有文件的工作副本。通常,我們會(huì)對(duì)這些文件做些修改,每當(dāng)完成了一個(gè)階段的目標(biāo),想要將記錄下它時(shí),就將它提交到到倉庫。
  • 請(qǐng)記住,工作目錄下的每一個(gè)文件都不外乎這兩種狀態(tài):已跟蹤未跟蹤。已跟蹤的文件是指那些被納入了版本控制的文件,在上一次快照中有它們的記錄,在工作一段時(shí)間后,它們的狀態(tài)可能是未修改,已修改或已放入暫存區(qū)。簡(jiǎn)而言之,已跟蹤的文件就是 Git 已經(jīng)知道的文件。
  • 工作目錄中除已跟蹤文件外的其它所有文件都屬于未跟蹤文件,它們既不存在于上次快照的記錄中,也沒有被放入暫存區(qū)。初次克隆某個(gè)倉庫的時(shí)候,工作目錄中的所有文件都屬于已跟蹤文件,并處于未修改狀態(tài),因?yàn)?Git 剛剛檢出了它們,而你尚未編輯過它們。
  • 編輯過某些文件之后,由于自上次提交后我們對(duì)它們做了修改,Git 將它們標(biāo)記為已修改文件。在工作時(shí),可以選擇性地將這些修改過的文件放入暫存區(qū),然后提交所有已暫存的修改,如此反復(fù)。
  • 因此,文件的狀態(tài)變化周期如下所示:

② 檢查當(dāng)前文件狀態(tài)

  • 可以用 git status 命令查看哪些文件處于什么狀態(tài)。如果在克隆倉庫后立即使用此命令,會(huì)看到類似這樣的輸出:
$ git statusOn branch masterYour branch is up-to-date with 'origin/master'.nothing to commit, working directory clean
  • 這說明現(xiàn)在的工作目錄相當(dāng)干凈,換句話說,所有已跟蹤文件在上次提交后都未被更改過。 此外,上面的信息還表明,當(dāng)前目錄下沒有出現(xiàn)任何處于未跟蹤狀態(tài)的新文件,否則 Git 會(huì)在這里列出來。最后,該命令還顯示了當(dāng)前所在分支,并告訴你這個(gè)分支同遠(yuǎn)程服務(wù)器上對(duì)應(yīng)的分支沒有偏離?,F(xiàn)在,分支名是“master”,這是默認(rèn)的分支名。
  • 現(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)
  • 在狀態(tài)報(bào)告中可以看到新建的 README 文件出現(xiàn)在 Untracked files 下面,未跟蹤的文件意味著 Git 在之前的快照(提交)中沒有這些文件;Git 不會(huì)自動(dòng)將之納入跟蹤范圍,除非我們明明白白地告訴它“我需要跟蹤該文件”。 這樣的處理不必?fù)?dān)心將生成的二進(jìn)制文件或其它不想被跟蹤的文件包含進(jìn)來。不過現(xiàn)在的例子中,我們確實(shí)想要跟蹤管理 README 這個(gè)文件。

③ 跟蹤新文件

  • 使用命令 git add 開始跟蹤一個(gè)文件。所以,要跟蹤 README 文件,運(yùn)行:
$ git add README
  • 此時(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)new file: 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)new file: 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)new file: 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)new file: 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
  • 怎么回事? 現(xiàn)在 CONTRIBUTING.md 文件同時(shí)出現(xiàn)在暫存區(qū)和非暫存區(qū),這怎么可能呢? 實(shí)際上 Git 只不過暫存了運(yùn)行 git add 命令時(shí)的版本。如果現(xiàn)在提交,CONTRIBUTING.md 的版本是最后一次運(yùn)行 git add 命令時(shí)的那個(gè)版本,而不是運(yùn)行 git commit 時(shí),在工作目錄中的當(dāng)前版本。 所以,運(yùn)行了 git add 之后又作了修訂的文件,需要重新運(yùn)行 git add 把最新版本重新暫存起來:
$ 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)new file: 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 READMEMM RakefileA 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 文件已修,暫存后又作了修改,因此該文件的修改中既有已暫存的部分,又有未暫存的部分。

⑥ 忽略文件

  • 一般我們總會(huì)有些文件無需納入 Git 的管理,也不希望它們總出現(xiàn)在未跟蹤文件列表。通常都是些自動(dòng)生成的文件,比如日志文件,或者編譯過程中創(chuàng)建的臨時(shí)文件等。在這種情況下,可以創(chuàng)建一個(gè)名為 .gitignore 的文件,列出要忽略的文件的模式。來看一個(gè)實(shí)際的 .gitignore 例子:
$ cat .gitignore*.[oa]*~
  • 第一行告訴 Git 忽略所有以 .o 或 .a 結(jié)尾的文件,一般這類對(duì)象文件和存檔文件都是編譯過程中出現(xiàn)的,第二行告訴 Git 忽略所有名字以波浪符(~)結(jié)尾的文件,許多文本編輯軟件(比如 Emacs)都用這樣的文件名保存副本。此外,可能還需要忽略 log,tmp 或者 pid 目錄,以及自動(dòng)生成的文檔等等,要養(yǎng)成一開始就為新倉庫設(shè)置好 .gitignore 文件的習(xí)慣,以免將來誤提交這類無用的文件。
  • 文件 .gitignore 的格式規(guī)范如下:
    • 所有空行或者以 # 開頭的行都會(huì)被 Git 忽略;
    • 可以使用標(biāo)準(zhǔn)的 glob 模式匹配,它會(huì)遞歸地應(yīng)用在整個(gè)工作區(qū)中;
    • 匹配模式可以以(/)開頭防止遞歸;
    • 匹配模式可以以(/)結(jié)尾指定目錄;
    • 要忽略指定模式以外的文件或目錄,可以在模式前加上嘆號(hào)(!)取反。
  • 所謂的 glob 模式是指 shell 所使用的簡(jiǎn)化了的正則表達(dá)式,星號(hào)(*)匹配零個(gè)或多個(gè)任意字符;[abc] 匹配任何一個(gè)列在方括號(hào)中的字符 (這個(gè)例子要么匹配一個(gè) a,要么匹配一個(gè) b,要么匹配一個(gè) c); 問號(hào)(?)只匹配一個(gè)任意字符;如果在方括號(hào)中使用短劃線分隔兩個(gè)字符,表示所有在這兩個(gè)字符范圍內(nèi)的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的數(shù)字)。使用兩個(gè)星號(hào)表示匹配任意中間目錄,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。
  • 再看一個(gè) .gitignore 文件的例子:
# 忽略所有的 .a 文件*.a# 但跟蹤所有的 lib.a,即便前面忽略了 .a 文件!lib.a# 只忽略當(dāng)前目錄下的 TODO 文件,而不忽略 subdir/TODO/TODO# 忽略任何目錄下名為 build 的文件夾build/# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txtdoc/*.txt# 忽略 doc/ 目錄及其所有子目錄下的 .pdf 文件doc/**/*.pdf
  • 在最簡(jiǎn)單的情況下,一個(gè)倉庫可能只根目錄下有一個(gè) .gitignore 文件,它遞歸地應(yīng)用到整個(gè)倉庫中。然而,子目錄下也可以有額外的 .gitignore 文件,子目錄中的 .gitignore 文件中的規(guī)則只作用于它所在的目錄中(Linux 內(nèi)核的源碼庫擁有 206 個(gè) .gitignore 文件)。

⑦ 查看已暫存和未暫存的修改

  • 如果 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
  • 此命令比較的是工作目錄中當(dāng)前文件和暫存區(qū)域快照之間的差異,也就是修改之后還沒有暫存起來的變化內(nèi)容。
  • 若要查看已暫存的將要添加到下次提交里的內(nèi)容,可以用 git diff --staged 命令,這條命令將比對(duì)已暫存文件與最后一次提交的文件差異:
$ git diff --stageddiff --git a/README b/READMEnew file mode 100644index 0000000..03902a1--- /dev/null+++ b/README@@ -0,0 +1 @@+My Project
  • 不過要注意,git diff 本身只顯示尚未暫存的改動(dòng),而不是自上次提交以來所做的所有改動(dòng)。所以有時(shí)候一下子暫存了所有更新過的文件,運(yùn)行 git diff 后卻什么也沒有,就是這個(gè)原因。
  • 像之前說的,暫存 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## Starter ProjectsSee our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).+# test line
  • 然后用 git diff --cached 查看已經(jīng)暫存起來的變化( --staged 和 --cached 同義):
$ 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:# new file: README# modified: CONTRIBUTING.md#~~~".git/COMMIT_EDITMSG" 9L, 283C
  • 可以看到,默認(rèn)的提交消息包含最后一次運(yùn)行 git status 的輸出,放在注釋行里,另外開頭還有一個(gè)空行,供輸入提交說明,完全可以去掉這些注釋行,不過留著也沒關(guān)系,多少能幫你回想起這次更新的內(nèi)容有哪些。
  • 退出編輯器時(shí),Git 會(huì)丟棄注釋行,用輸入的提交說明生成一次提交。另外,也可以在 commit 命令后添加 -m 選項(xiàng),將提交信息與命令放在同一行,如下所示:
$ git commit -m "Story 182: Fix benchmarks for speed"[master 463dc4f] Story 182: Fix benchmarks for speed2 files changed, 2 insertions(+)create mode 100644 README
  • 現(xiàn)在已經(jīng)創(chuàng)建了第一個(gè)提交,可以看到,提交后它會(huì)提示當(dāng)前是在哪個(gè)分支(master)提交的,本次提交的完整 SHA-1 校驗(yàn)和是什么(463dc4f),以及在本次提交中,有多少文件修訂過,多少行添加和刪改過。
  • 請(qǐng)記住,提交時(shí)記錄的是放在暫存區(qū)域的快照,任何還未暫存文件的仍然保持已修改狀態(tài),可以在下次提交時(shí)納入版本管理。每一次運(yùn)行提交操作,都是對(duì)項(xiàng)目作一次快照,以后可以回到這個(gè)狀態(tài),或者進(jìn)行比較。

⑨ 跳過使用暫存區(qū)域

  • 盡管使用暫存區(qū)域的方式可以精心準(zhǔn)備要提交的細(xì)節(jié),但有時(shí)候這么做略顯繁瑣。Git 提供了一個(gè)跳過使用暫存區(qū)域的方式,只要在提交的時(shí)候,給 git commit 加上 -a 選項(xiàng),Git 就會(huì)自動(dòng)把所有已經(jīng)跟蹤過的文件暫存起來一并提交,從而跳過 git add 步驟:
$ 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 new benchmarks1 file changed, 5 insertions(+), 0 deletions(-)
  • 提交之前不再需要 git add 文件“CONTRIBUTING.md”,這是因?yàn)?-a 選項(xiàng)使本次提交包含了所有修改過的文件。這很方便,但是要注意,有時(shí)這個(gè)選項(xiàng)會(huì)將不需要的文件添加到提交中。

⑩ 移除文件

  • 要從 Git 中移除某個(gè)文件,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區(qū)域移除),然后提交。可以用 git rm 命令完成此項(xiàng)工作,并連帶從工作目錄中刪除指定的文件,這樣以后就不會(huì)出現(xiàn)在未跟蹤文件清單中。
  • 如果只是簡(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 倉庫中刪除(亦即從暫存區(qū)域移除),但仍然希望保留在當(dāng)前工作目錄中。換句話說,想讓文件保留在磁盤,但是并不想讓 Git 繼續(xù)跟蹤,當(dāng)忘記添加 .gitignore 文件,不小心把一個(gè)很大的日志文件或一堆 .a 這樣的編譯生成文件添加到暫存區(qū)時(shí),這一做法尤其有用。為達(dá)到這一目的,使用 --cached 選項(xiàng):
$ git rm --cached README
  • git rm 命令后面可以列出文件或者目錄的名字,也可以使用 glob 模式。比如:
$ git rm log/\*.log
  • 意到星號(hào) * 之前的反斜杠 \, 因?yàn)?Git 有它自己的文件模式擴(kuò)展匹配方式,所以不用 shell 來幫忙展開,此命令刪除 log/ 目錄下擴(kuò)展名為 .log 的所有文件。類似的比如:刪除所有名字以 ~ 結(jié)尾的文件的命令:
$ git rm \*~

? 移動(dòng)文件

  • 不像其它的 VCS 系統(tǒng),Git 并不顯式跟蹤文件移動(dòng)操作。如果在 Git 中重命名了某個(gè)文件,倉庫中存儲(chǔ)的元數(shù)據(jù)并不會(huì)體現(xiàn)出這是一次改名操作。不過 Git 非常聰明,它會(huì)推斷出究竟發(fā)生了什么,至于具體是如何做到的,我們稍后再談。
  • 既然如此,當(dāng)看到 Git 的 mv 命令時(shí)一定會(huì)困惑不已。要在 Git 中對(duì)文件改名,可以這么做:
$ git mv file_from file_to
  • 它會(huì)恰如預(yù)期般正常工作,實(shí)際上即便此時(shí)查看狀態(tài)信息,也會(huì)明白無誤地看到關(guān)于重命名操作的說明:
$ 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
  • 其實(shí),運(yùn)行 git mv 就相當(dāng)于運(yùn)行了下面三條命令:
$ mv README.md README$ git rm README.md$ git add README
  • 如此分開操作,Git 也會(huì)意識(shí)到這是一次重命名,所以不管何種方式結(jié)果都一樣。兩者唯一的區(qū)別是,mv 是一條命令而非三條命令,直接用 git mv 方便得多。不過有時(shí)候用其他工具批處理重命名的話,要記得在提交前刪除舊的文件名,再添加新的文件名。

三、查看提交歷史

  • 在提交了若干更新,又或者克隆了某個(gè)項(xiàng)目之后,我們也許想回顧下提交歷史,完成這個(gè)任務(wù)最簡(jiǎn)單而又有效的工具是 git log 命令。
  • 使用一個(gè)非常簡(jiǎn)單的 “simplegit” 項(xiàng)目作為示例,運(yùn)行下面的命令獲取該項(xiàng)目:
$ git clone https://github.com/kody/simplegit-progit
  • 當(dāng)在此項(xiàng)目中運(yùn)行 git log 命令時(shí),可以看到下面的輸出:
$ git logcommit ca82a6dff817ec66f44342007202690a93763949Author: Scott Chacon <kody@gee-mail.com>Date: Mon Mar 17 21:52:11 2021 -0700changed the version numbercommit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7Author: Scott Chacon <kody@gee-mail.com>Date: Sat Mar 15 16:40:33 2021 -0700removed unnecessary testcommit a11bef06a3f659402fe7563abf99ad00de2209e6Author: Scott Chacon <kody@gee-mail.com>Date: Sat Mar 15 10:31:28 2021 -0700first commit
  • 不傳入任何參數(shù)的默認(rèn)情況下,git log 會(huì)按時(shí)間先后順序列出所有的提交,最近的更新排在最上面。正如所看到的,這個(gè)命令會(huì)列出每個(gè)提交的 SHA-1 校驗(yàn)和、作者的名字和電子郵件地址、提交時(shí)間以及提交說明。
  • git log 有許多選項(xiàng)可以搜尋你所要找的提交,其中一個(gè)比較有用的選項(xiàng)是 -p 或 --patch,它會(huì)顯示每次提交所引入的差異(按補(bǔ)丁的格式輸出),也可以限制顯示的日志條目數(shù)量,例如使用 -2 選項(xiàng)來只顯示最近的兩次提交:
$ git log -p -2commit ca82a6dff817ec66f44342007202690a93763949Author: Scott Chacon <kody@gee-mail.com>Date: Mon Mar 17 21:52:11 2021 -0700changed the version numberdiff --git a/Rakefile b/Rakefileindex a874b73..8f94139 100644--- a/Rakefile+++ b/Rakefile@@ -5,7 +5,7 @@ require 'rake/gempackagetask'spec = Gem::Specification.new do |s|s.platform = Gem::Platform::RUBYs.name = "simplegit"- s.version = "0.1.0"+ s.version = "0.1.1"s.author = "Scott Chacon"s.email = "kody@gee-mail.com"s.summary = "A simple gem for using Git in Ruby code."commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7Author: Scott Chacon <kody@gee-mail.com>Date: Sat Mar 15 16:40:33 2021 -0700removed unnecessary testdiff --git a/lib/simplegit.rb b/lib/simplegit.rbindex a0a60ae..47c6340 100644--- a/lib/simplegit.rb+++ b/lib/simplegit.rb@@ -18,8 +18,3 @@ class SimpleGitendend--if $0 == __FILE__- git = SimpleGit.new- puts git.show-end
  • 該選項(xiàng)除了顯示基本信息之外,還附帶了每次提交的變化。當(dāng)進(jìn)行代碼審查,或者快速瀏覽某個(gè)搭檔的提交所帶來的變化的時(shí)候,這個(gè)參數(shù)就非常有用了,也可以為 git log 附帶一系列的總結(jié)性選項(xiàng)。比如想看到每次提交的簡(jiǎn)略統(tǒng)計(jì)信息,可以使用 --stat 選項(xiàng):
$ git log --statcommit ca82a6dff817ec66f44342007202690a93763949Author: Scott Chacon <kody@gee-mail.com>Date: Mon Mar 17 21:52:11 2021 -0700changed the version numberRakefile | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7Author: Scott Chacon <kody@gee-mail.com>Date: Sat Mar 15 16:40:33 2021 -0700removed unnecessary testlib/simplegit.rb | 5 -----1 file changed, 5 deletions(-)commit a11bef06a3f659402fe7563abf99ad00de2209e6Author: Scott Chacon <kody@gee-mail.com>Date: Sat Mar 15 10:31:28 2021 -0700first commitREADME | 6 ++++++Rakefile | 23 +++++++++++++++++++++++lib/simplegit.rb | 25 +++++++++++++++++++++++++3 files changed, 54 insertions(+)
  • 正如所看到的,–stat 選項(xiàng)在每次提交的下面列出所有被修改過的文件、有多少文件被修改了以及被修改過的文件的哪些行被移除或是添加了,在每次提交的最后還有一個(gè)總結(jié)。
  • 另一個(gè)非常有用的選項(xiàng)是 --pretty,這個(gè)選項(xiàng)可以使用不同于默認(rèn)格式的方式展示提交歷史,還有一些內(nèi)建的子選項(xiàng)供使用,比如 oneline 會(huì)將每個(gè)提交放在一行顯示,在瀏覽大量的提交時(shí)非常有用。另外還有 short,full 和 fuller 選項(xiàng),它們展示信息的格式基本一致,但是詳盡程度不一:
$ 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 - Scott Chacon, 6 years ago : changed the version number085bb3b - Scott Chacon, 6 years ago : removed unnecessary testa11bef0 - Scott Chacon, 6 years ago : first commit
  • 如下所示,列出了 format 接受的常用格式占位符的寫法及其代表的意義:
選項(xiàng)說明
%H提交的完整哈希值
%h提交的簡(jiǎn)寫哈希值
%T樹的完整哈希值
%t樹的簡(jiǎn)寫哈希值
%P父提交的完整哈希值
%p父提交的簡(jiǎn)寫哈希值
%an作者名字
%ae作者的電子郵件地址
%ad作者修訂日期(可以用 --date=選項(xiàng) 來定制格式)
%ar作者修訂日期,按多久以前的方式顯示
%cn提交者的名字
%ce提交者的電子郵件地址
%cd提交日期
%cr提交日期(距今多長(zhǎng)時(shí)間)
%s提交說明
  • 那么作者和提交者之間究竟有何差別?其實(shí)作者指的是實(shí)際作出修改的人,提交者指的是最后將此工作成果提交到倉庫的人。 所以,當(dāng)為某個(gè)項(xiàng)目發(fā)布補(bǔ)丁,然后某個(gè)核心成員將我們的補(bǔ)丁并入項(xiàng)目時(shí),我們就是作者,而那個(gè)核心成員就是提交者。
  • 當(dāng) oneline 或 format 與另一個(gè) log 選項(xiàng) --graph 結(jié)合使用時(shí)尤其有用,這個(gè)選項(xiàng)添加了一些 ASCII 字符串來形象地展示分支和合并歷史:
$ 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
  • git log 的常用選項(xiàng):
選項(xiàng)說明
-p按補(bǔ)丁格式顯示每個(gè)提交引入的差異
–stat顯示每次提交的文件修改統(tǒng)計(jì)信息
–shortstat只顯示 --stat 中最后的行數(shù)修改添加移除統(tǒng)計(jì)
–name-only僅在提交信息后顯示已修改的文件清單
–name-status顯示新增、修改、刪除的文件清單
–abbrev-commit僅顯示 SHA-1 校驗(yàn)和所有 40 個(gè)字符中的前幾個(gè)字符
–relative-date使用較短的相對(duì)時(shí)間而不是完整格式顯示日期(比如“2 weeks ago”)
–graph在日志旁以 ASCII 圖形顯示分支與合并歷史
–pretty使用其他格式顯示歷史提交信息,可用的選項(xiàng)包括 oneline、short、full、fuller 和 format(用來定義自己的格式)
–oneline–pretty=oneline --abbrev-commit 合用的簡(jiǎn)寫
  • 除了定制輸出格式的選項(xiàng)之外,git log 還有許多非常實(shí)用的限制輸出長(zhǎng)度的選項(xiàng),也就是只輸出一部分的提交。之前你已經(jīng)看到過 git log -p -2 選項(xiàng)了,它只會(huì)顯示最近的兩條提交,實(shí)際上可以使用類似 - 的選項(xiàng),其中的 n 可以是任何整數(shù),表示僅顯示最近的 n 條提交。不過,實(shí)踐中這個(gè)選項(xiàng)不是很常用,因?yàn)?Git 默認(rèn)會(huì)將所有的輸出傳送到分頁程序中,所以一次只會(huì)看到一頁的內(nèi)容。
  • 但是,類似 --since 和 --until 這種按照時(shí)間作限制的選項(xiàng)很有用。例如,下面的命令會(huì)列出最近兩周的所有提交:
$ git log --since=2.weeks
  • 該命令可用的格式十分豐富——可以是類似“2021-01-15”的具體的某一天,也可以是類似 “2 years 1 day 3 minutes ago” 的相對(duì)日期。
  • 還可以過濾出匹配指定條件的提交,用 --author 選項(xiàng)顯示指定作者的提交,用 --grep 選項(xiàng)搜索提交說明中的關(guān)鍵字,可以指定多個(gè) --author 和 --grep 搜索條件,這樣會(huì)只輸出任意匹配 --author 模式和 --grep 模式的提交;然而,如果添加了 --all-match 選項(xiàng),則只會(huì)輸出所有匹配 --grep 模式的提交。
  • 另一個(gè)非常有用的過濾器是 -S(俗稱“pickaxe”選項(xiàng)),它接受一個(gè)字符串參數(shù),并且只會(huì)顯示那些添加或刪除了該字符串的提交,假設(shè)想找出添加或刪除了對(duì)某一個(gè)特定函數(shù)的引用的提交,可以調(diào)用:
$ git log -S function_name
  • 最后一個(gè)很實(shí)用的 git log 選項(xiàng)是路徑(path), 如果只關(guān)心某些文件或者目錄的歷史提交,可以在 git log 選項(xiàng)的最后指定它們的路徑,因?yàn)槭欠旁谧詈笪恢蒙系倪x項(xiàng),所以用兩個(gè)短劃線(–)隔開之前的選項(xiàng)和后面限定的路徑名。
  • 限制 git log 輸出的選項(xiàng)如下表:
選項(xiàng)說明
-僅顯示最近的 n 條提交
–since, --after僅顯示指定時(shí)間之后的提交
–until, --before僅顯示指定時(shí)間之前的提交
–author僅顯示作者匹配指定字符串的提交
–committer僅顯示提交者匹配指定字符串的提交
–grep僅顯示提交說明中包含指定字符串的提交
-S僅顯示添加或刪除內(nèi)容匹配指定字符串的提交
  • 來看一個(gè)實(shí)際的例子,如果要在 Git 源碼庫中查看 Junio Hamano 在 2021 年 7 月其間,除了合并提交之外的哪一個(gè)提交修改了測(cè)試文件,可以使用下面的命令:
$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2021-07-01" \--before="2021-08-01" --no-merges -- t/5610e3b - Fix testcase failure when extended attributes are in useacd3b9e - Enhance hold_lock_file_for_{update,append}() APIf563754 - demonstrate breakage of detached checkout with symbolic link HEADd1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths51a94af - Fix "checkout --track -b newbranch" on detached HEADb0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch
  • 在近 40000 條提交中,上面的輸出僅列出了符合條件的 6 條記錄。
  • 隱藏合并提交:按照代碼倉庫的工作流程,記錄中可能有為數(shù)不少的合并提交,它們所包含的信息通常并不多,為了避免顯示的合并提交弄亂歷史記錄,可以為 log 加上 --no-merges 選項(xiàng)。

四、撤消操作

  • 有時(shí)候提交完了才發(fā)現(xiàn)漏掉了幾個(gè)文件沒有添加,或者提交信息寫錯(cuò)了,此時(shí)可以運(yùn)行帶有 --amend 選項(xiàng)的提交命令來重新提交:
$ git commit --amend
  • 這個(gè)命令會(huì)將暫存區(qū)中的文件提交,如果自上次提交以來還未做任何修改(例如,在上次提交后馬上執(zhí)行了此命令),那么快照會(huì)保持不變,而所修改的只是提交信息。
  • 文本編輯器啟動(dòng)后,可以看到之前的提交信息,編輯后保存會(huì)覆蓋原來的提交信息。例如,提交后發(fā)現(xiàn)忘記了暫存某些需要的修改,可以像下面這樣操作:
$ git commit -m 'initial commit'$ git add forgotten_file$ git commit --amend
  • 最終只會(huì)有一個(gè)提交——第二次提交將代替第一次提交的結(jié)果。

① 取消暫存的文件

  • 如何操作暫存區(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 HEAD CONTRIBUTING.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
  • 這個(gè)命令有點(diǎn)兒奇怪,但是起作用了,CONTRIBUTING.md 文件已經(jīng)是修改未暫存的狀態(tài)。git reset 確實(shí)是個(gè)危險(xiǎn)的命令,如果加上了 --hard 選項(xiàng)則更是如此。然而在上述場(chǎng)景中,工作目錄中的文件尚未修改,因此相對(duì)安全一些。

② 撤消對(duì)文件的修改

  • 如果并不想保留對(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
  • 它非常清楚地提示了如何撤消之前所做的修改,讓我們來按照提示執(zhí)行,可以看到那些修改已經(jīng)被撤消了:
$ git checkout -- CONTRIBUTING.md$ git statusOn branch masterChanges to be committed:(use "git reset HEAD <file>..." to unstage)renamed: README.md -> README
  • 請(qǐng)注意: git checkout – 是一個(gè)危險(xiǎn)的命令,對(duì)那個(gè)文件在本地的任何修改都會(huì)消失——Git 會(huì)用最近提交的版本覆蓋掉它,除非確實(shí)清楚不想要對(duì)那個(gè)文件的本地修改了,否則請(qǐng)不要使用這個(gè)命令。
  • 如果仍然想保留對(duì)那個(gè)文件做出的修改,但是現(xiàn)在仍然需要撤消,將會(huì)利用 Git 分支來保存進(jìn)度與分支,這通常是更好的做法。
  • 在 Git 中任何已提交的東西幾乎總是可以恢復(fù)的,甚至那些被刪除的分支中的提交或使用 --amend 選項(xiàng)覆蓋的提交也可以恢復(fù) (閱讀數(shù)據(jù)恢復(fù)了解數(shù)據(jù)恢復(fù))。 然而,任何未提交的東西丟失后很可能再也找不到了。

五、遠(yuǎn)程倉庫的使用

  • 為了能在任意 Git 項(xiàng)目上協(xié)作,需要知道如何管理自己的遠(yuǎn)程倉庫。遠(yuǎn)程倉庫是指托管在因特網(wǎng)或其他網(wǎng)絡(luò)中的項(xiàng)目的版本庫,可以有好幾個(gè)遠(yuǎn)程倉庫,通常有些倉庫只讀,有些則可以讀寫。與他人協(xié)作涉及管理遠(yuǎn)程倉庫以及根據(jù)需要推送或拉取數(shù)據(jù),管理遠(yuǎn)程倉庫包括了解如何添加遠(yuǎn)程倉庫、移除無效的遠(yuǎn)程倉庫、管理不同的遠(yuǎn)程分支并定義它們是否被跟蹤等。
  • 我們完全可以在一個(gè)“遠(yuǎn)程”倉庫上工作,而實(shí)際上它在我們本地的主機(jī)上。“遠(yuǎn)程”未必表示倉庫在網(wǎng)絡(luò)或互聯(lián)網(wǎng)上的其它位置,而只是表示它在別處,在這樣的遠(yuǎn)程倉庫上工作,仍然需要和其它遠(yuǎn)程倉庫上一樣的標(biāo)準(zhǔn)推送、拉取和抓取操作。

① 查看遠(yuǎn)程倉庫

  • 如果想查看已經(jīng)配置的遠(yuǎn)程倉庫服務(wù)器,可以運(yùn)行 git remote 命令,它會(huì)列出指定的每一個(gè)遠(yuǎn)程服務(wù)器的簡(jiǎn)寫,如果已經(jīng)克隆了自己的倉庫,那么至少應(yīng)該能看到 origin ——這是 Git 給克隆的倉庫服務(wù)器的默認(rèn)名字:
$ git clone https://github.com/kody/ticgitCloning into 'ticgit'...remote: Reusing existing pack: 1857, done.remote: Total 1857 (delta 0), reused 0 (delta 0)Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.Resolving deltas: 100% (772/772), done.Checking connectivity... done.$ cd ticgit$ git remoteorigin
  • 也可以指定選項(xiàng) -v,會(huì)顯示需要讀寫遠(yuǎn)程倉庫使用的 Git 保存的簡(jiǎn)寫與其對(duì)應(yīng)的 URL:
$ git remote -vorigin https://github.com/kody/ticgit (fetch)origin https://github.com/kody/ticgit (push)
  • 如果遠(yuǎn)程倉庫不止一個(gè),該命令會(huì)將它們?nèi)苛谐觥@?#xff0c;與幾個(gè)協(xié)作者合作的,擁有多個(gè)遠(yuǎn)程倉庫的倉庫看起來像下面這樣:
$ cd grit$ git remote -vbakkdoor https://github.com/bakkdoor/grit (fetch)bakkdoor https://github.com/bakkdoor/grit (push)cho45 https://github.com/cho45/grit (fetch)cho45 https://github.com/cho45/grit (push)defunkt https://github.com/defunkt/grit (fetch)defunkt https://github.com/defunkt/grit (push)koke git://github.com/koke/grit.git (fetch)koke git://github.com/koke/grit.git (push)origin git@github.com:mojombo/grit.git (fetch)origin git@github.com:mojombo/grit.git (push)
  • 這表示我們能非常方便地拉取其它用戶的貢獻(xiàn),還可以擁有向他們推送的權(quán)限(注意:這些遠(yuǎn)程倉庫使用了不同的協(xié)議)。

② 添加遠(yuǎn)程倉庫

  • 在上文中,提到并展示了 git clone 命令是如何自行添加遠(yuǎn)程倉庫的,不過這里將告訴我們?nèi)绾巫约簛硖砑铀?#xff0c;運(yùn)行 git remote add 添加一個(gè)新的遠(yuǎn)程 Git 倉庫,同時(shí)指定一個(gè)方便使用的簡(jiǎn)寫:
$ git remoteorigin$ git remote add pb https://github.com/paulboone/ticgit$ git remote -vorigin https://github.com/kody/ticgit (fetch)origin https://github.com/kody/ticgit (push)pb https://github.com/paulboone/ticgit (fetch)pb https://github.com/paulboone/ticgit (push)
  • 現(xiàn)在可以在命令行中使用字符串 pb 來代替整個(gè) URL。 例如,如果你想拉取 Paul 的倉庫中有但你沒有的信息,可以運(yùn)行 git fetch pb:
$ git fetch pbremote: Counting objects: 43, done.remote: Compressing objects: 100% (36/36), done.remote: Total 43 (delta 10), reused 31 (delta 5)Unpacking objects: 100% (43/43), done.From https://github.com/paulboone/ticgit* [new branch] master -> pb/master* [new branch] ticgit -> pb/ticgit
  • 現(xiàn)在 Paul 的 master 分支可以在本地通過 pb/master 訪問到——我們可以將它合并到自己的某個(gè)分支中,或者如果想要查看它的話,可以檢出一個(gè)指向該點(diǎn)的本地分支。

③ 從遠(yuǎn)程倉庫中抓取與拉取

  • 從遠(yuǎn)程倉庫中獲得數(shù)據(jù),可以執(zhí)行:
$ git fetch <remote>
  • 這個(gè)命令會(huì)訪問遠(yuǎn)程倉庫,從中拉取所有你還沒有的數(shù)據(jù)。執(zhí)行完成后,將會(huì)擁有那個(gè)遠(yuǎn)程倉庫中所有分支的引用,可以隨時(shí)合并或查看。
  • 如果使用 clone 命令克隆了一個(gè)倉庫,命令會(huì)自動(dòng)將其添加為遠(yuǎn)程倉庫并默認(rèn)以 “origin” 為簡(jiǎn)寫。 所以,git fetch origin 會(huì)抓取克隆(或上一次抓取)后新推送的所有工作,必須注意 git fetch 命令只會(huì)將數(shù)據(jù)下載到本地倉庫,它并不會(huì)自動(dòng)合并或修改當(dāng)前的工作,當(dāng)準(zhǔn)備好時(shí)必須手動(dòng)將其合并入工作。
  • 如果當(dāng)前分支設(shè)置了跟蹤遠(yuǎn)程分支,那么可以用 git pull 命令來自動(dòng)抓取后合并該遠(yuǎn)程分支到當(dāng)前分支,這或許是個(gè)更加簡(jiǎn)單舒服的工作流程。默認(rèn)情況下,git clone 命令會(huì)自動(dòng)設(shè)置本地 master 分支跟蹤克隆的遠(yuǎn)程倉庫的 master 分支(或其它名字的默認(rèn)分支),運(yùn)行 git pull 通常會(huì)從最初克隆的服務(wù)器上抓取數(shù)據(jù)并自動(dòng)嘗試合并到當(dāng)前所在的分支。

④ 推送到遠(yuǎn)程倉庫

  • 當(dāng)想分享項(xiàng)目時(shí),必須將其推送到上游,這個(gè)命令很簡(jiǎn)單:git push 。當(dāng)想要將 master 分支推送到 origin 服務(wù)器時(shí)(再次說明,克隆時(shí)通常會(huì)自動(dòng)設(shè)置好那兩個(gè)名字), 那么運(yùn)行這個(gè)命令就可以將所做的備份到服務(wù)器:
$ git push origin master
  • 只有當(dāng)我們有所克隆服務(wù)器的寫入權(quán)限,并且之前沒有人推送過時(shí),這條命令才能生效。當(dāng)我們和其他人在同一時(shí)間克隆,他們先推送到上游然后我們?cè)偻扑偷缴嫌?#xff0c;我們的推送就會(huì)毫無疑問地被拒絕,我們必須先抓取他們的工作并將其合并進(jìn)我們的工作后才能推送。

⑤ 查看某個(gè)遠(yuǎn)程倉庫

  • 如果想要查看某一個(gè)遠(yuǎn)程倉庫的更多信息,可以使用 git remote show 命令,如果想以一個(gè)特定的縮寫名運(yùn)行這個(gè)命令,例如 origin,會(huì)得到像下面類似的信息:
$ git remote show origin* remote originFetch URL: https://github.com/kody/ticgitPush URL: https://github.com/kody/ticgitHEAD branch: masterRemote branches:master trackeddev-branch trackedLocal branch configured for 'git pull':master merges with remote masterLocal ref configured for 'git push':master pushes to master (up to date)
  • 它同樣會(huì)列出遠(yuǎn)程倉庫的 URL 與跟蹤分支的信息,這些信息非常有用,它告訴我們正處于 master 分支,并且如果運(yùn)行 git pull, 就會(huì)抓取所有的遠(yuǎn)程引用,然后將遠(yuǎn)程 master 分支合并到本地 master 分支,它也會(huì)列出拉取到的所有遠(yuǎn)程引用。
  • 如果是 Git 的重度使用者,那么還可以通過 git remote show 看到更多的信息:
$ git remote show origin* remote originURL: https://github.com/my-org/complex-projectFetch URL: https://github.com/my-org/complex-projectPush URL: https://github.com/my-org/complex-projectHEAD branch: masterRemote branches:master trackeddev-branch trackedmarkdown-strip trackedissue-43 new (next fetch will store in remotes/origin)issue-45 new (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)
  • 這個(gè)命令列出了當(dāng)在特定的分支上執(zhí)行 git push 會(huì)自動(dòng)地推送到哪一個(gè)遠(yuǎn)程分支,它也同樣地列出了哪些遠(yuǎn)程分支不在本地,哪些遠(yuǎn)程分支已經(jīng)從服務(wù)器上移除了,還有當(dāng)執(zhí)行 git pull 時(shí)哪些本地分支可以與它跟蹤的遠(yuǎn)程分支自動(dòng)合并。

⑥ 遠(yuǎn)程倉庫的重命名與移除

  • 可以運(yùn)行 git remote rename 來修改一個(gè)遠(yuǎn)程倉庫的簡(jiǎn)寫名。例如,想要將 pb 重命名為 paul,可以用 git remote rename 這樣做:
$ git remote rename pb paul$ git remoteoriginpaul
  • 這同樣也會(huì)修改所有遠(yuǎn)程跟蹤的分支名字,那些過去引用 pb/master 的現(xiàn)在會(huì)引用 paul/master,如果因?yàn)橐恍┰蛳胍瞥粋€(gè)遠(yuǎn)程倉庫,我們已經(jīng)從服務(wù)器上搬走了或不再想使用某一個(gè)特定的鏡像了,又或者某一個(gè)貢獻(xiàn)者不再貢獻(xiàn)了,可以使用 git remote remove 或 git remote rm :
$ git remote remove paul$ git remoteorigin
  • 一旦使用這種方式刪除了一個(gè)遠(yuǎn)程倉庫,那么所有和這個(gè)遠(yuǎn)程倉庫相關(guān)的遠(yuǎn)程跟蹤分支以及配置信息也會(huì)一起被刪除。

六、打標(biāo)簽

① 列出標(biāo)簽

  • 在 Git 中列出已有的標(biāo)簽非常簡(jiǎn)單,只需要輸入 git tag (可帶上可選的 -l 選項(xiàng) --list):
$ git tagv1.0v2.0
  • 這個(gè)命令以字母順序列出標(biāo)簽,但是它們顯示的順序并不重要。
  • 也可以按照特定的模式查找標(biāo)簽。例如,Git 自身的源代碼倉庫包含標(biāo)簽的數(shù)量超過 500 個(gè),如果只對(duì) 1.8.5 系列感興趣,可以運(yùn)行:
$ git tag -l "v1.8.5*"v1.8.5v1.8.5-rc0v1.8.5-rc1v1.8.5-rc2v1.8.5-rc3v1.8.5.1v1.8.5.2v1.8.5.3v1.8.5.4v1.8.5.5
  • 如果只想要完整的標(biāo)簽列表,那么運(yùn)行 git tag 就會(huì)默認(rèn)假定想要一個(gè)列表,它會(huì)直接給你列出來,此時(shí)的 -l 或 --list 是可選的。然而,如果提供了一個(gè)匹配標(biāo)簽名的通配模式,那么 -l 或 --list 就是強(qiáng)制使用的。

② 創(chuàng)建標(biāo)簽

  • Git 支持兩種標(biāo)簽:輕量標(biāo)簽(lightweight)與附注標(biāo)簽(annotated)。
  • 輕量標(biāo)簽很像一個(gè)不會(huì)改變的分支,它只是某個(gè)特定提交的引用。而附注標(biāo)簽是存儲(chǔ)在 Git 數(shù)據(jù)庫中的一個(gè)完整對(duì)象,它們是可以被校驗(yàn)的,其中包含打標(biāo)簽者的名字、電子郵件地址、日期時(shí)間, 此外還有一個(gè)標(biāo)簽信息,并且可以使用 GNU Privacy Guard (GPG)簽名并驗(yàn)證。
  • 通常會(huì)建議創(chuàng)建附注標(biāo)簽,這樣可以擁有以上所有信息。但是如果你只是想用一個(gè)臨時(shí)的標(biāo)簽, 或者因?yàn)槟承┰虿幌胍4孢@些信息,那么也可以用輕量標(biāo)簽。
  • 在 Git 中創(chuàng)建附注標(biāo)簽十分簡(jiǎn)單,最簡(jiǎn)單的方式是當(dāng)在運(yùn)行 tag 命令時(shí)指定 -a 選項(xiàng):
$ git tag -a v1.4 -m "my version 1.4"$ git tagv0.1v1.3v1.4
  • -m 選項(xiàng)指定了一條將會(huì)存儲(chǔ)在標(biāo)簽中的信息,如果沒有為附注標(biāo)簽指定一條信息,Git 會(huì)啟動(dòng)編輯器要求輸入信息。
  • 通過使用 git show 命令可以看到標(biāo)簽信息和與之對(duì)應(yīng)的提交信息,輸出顯示了打標(biāo)簽者的信息、打標(biāo)簽的日期時(shí)間、附注信息,然后顯示具體的提交信息:
$ git show v1.4tag v1.4Tagger: Ben Straub <ben@straub.cc>Date: Sat May 3 20:19:12 2014 -0700my version 1.4commit ca82a6dff817ec66f44342007202690a93763949Author: Scott Chacon <kody@gee-mail.com>Date: Mon Mar 17 21:52:11 2008 -0700changed the version number
  • 另一種給提交打標(biāo)簽的方式是使用輕量標(biāo)簽。輕量標(biāo)簽本質(zhì)上是將提交校驗(yàn)和存儲(chǔ)到一個(gè)文件中,沒有保存任何其他信息,創(chuàng)建輕量標(biāo)簽,不需要使用 -a、-s 或 -m 選項(xiàng),只需要提供標(biāo)簽名字:
$ git tag v1.4-lw$ git tagv0.1v1.3v1.4v1.4-lwv1.5
  • 這時(shí),如果在標(biāo)簽上運(yùn)行 git show,不會(huì)看到額外的標(biāo)簽信息。命令只會(huì)顯示出提交信息:
$ git show v1.4-lwcommit ca82a6dff817ec66f44342007202690a93763949Author: Scott Chacon <kody@gee-mail.com>Date: Mon Mar 17 21:52:11 2008 -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
  • 現(xiàn)在,假設(shè)在 v1.2 時(shí)忘記給項(xiàng)目打標(biāo)簽,也就是在 “updated rakefile” 提交,可以在之后補(bǔ)上標(biāo)簽,要在那個(gè)提交上打標(biāo)簽,需要在命令的末尾指定提交的校驗(yàn)和(或部分校驗(yàn)和):
$ git tag -a v1.2 9fceb02
  • 可以看到已經(jīng)在那次提交上打上標(biāo)簽了:
$ git tagv0.1v1.2v1.3v1.4v1.4-lwv1.5$ git show v1.2tag v1.2Tagger: Scott Chacon <kody@gee-mail.com>Date: Mon Feb 9 15:32:16 2009 -0800version 1.2commit 9fceb02d0ae598e95dc970b74767f19372d61af8Author: Magnus Chacon <mchacon@gee-mail.com>Date: Sun Apr 27 20:43:35 2008 -0700updated rakefile...

④ 共享標(biāo)簽

  • 默認(rèn)情況下,git push 命令并不會(huì)傳送標(biāo)簽到遠(yuǎn)程倉庫服務(wù)器上,在創(chuàng)建完標(biāo)簽后必須顯式地推送標(biāo)簽到共享服務(wù)器上,這個(gè)過程就像共享遠(yuǎn)程分支一樣,可以運(yùn)行 git push origin :
$ git push origin v1.5Counting objects: 14, done.Delta compression using up to 8 threads.Compressing objects: 100% (12/12), done.Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.Total 14 (delta 3), reused 0 (delta 0)To git@github.com:schacon/simplegit.git* [new tag] v1.5 -> v1.5
  • 如果想要一次性推送很多標(biāo)簽,也可以使用帶有 --tags 選項(xiàng)的 git push 命令,這將會(huì)把所有不在遠(yuǎn)程倉庫服務(wù)器上的標(biāo)簽全部傳送到那里:
$ git push origin --tagsCounting objects: 1, done.Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.Total 1 (delta 0), reused 0 (delta 0)To git@github.com:schacon/simplegit.git* [new tag] v1.4 -> v1.4* [new tag] v1.4-lw -> v1.4-lw
  • 現(xiàn)在,當(dāng)其他人從倉庫中克隆或拉取,他們也能得到那些標(biāo)簽。
  • 使用 git push --tags 推送標(biāo)簽并不會(huì)區(qū)分輕量標(biāo)簽和附注標(biāo)簽,沒有簡(jiǎn)單的選項(xiàng)能夠只選擇推送一種標(biāo)簽。

⑤ 刪除標(biāo)簽

  • 要?jiǎng)h除掉本地倉庫上的標(biāo)簽,可以使用命令 git tag -d 。 例如,可以使用以下命令刪除一個(gè)輕量標(biāo)簽:
$ git tag -d v1.4-lwDeleted tag 'v1.4-lw' (was e7d5add)
  • 注意上述命令并不會(huì)從任何遠(yuǎn)程倉庫中移除這個(gè)標(biāo)簽,必須用 git push :refs/tags/ 來更新遠(yuǎn)程倉庫:
    • 第一種變體是 git push :refs/tags/,這種操作的含義是,將冒號(hào)前面的空值推送到遠(yuǎn)程標(biāo)簽名,從而高效地刪除它:
$ git push origin :refs/tags/v1.4-lwTo /git@github.com:schacon/simplegit.git- [deleted] v1.4-lw
    • 第二種更直觀的刪除遠(yuǎn)程標(biāo)簽的方式是:
$ git push origin --delete <tagname>

⑥ 檢出標(biāo)簽

  • 如果想查看某個(gè)標(biāo)簽所指向的文件版本,可以使用 git checkout 命令,雖然這會(huì)使我們的倉庫處于“分離頭指針(detached HEAD)”的狀態(tài),這個(gè)狀態(tài)有些不好的副作用:
$ 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 new branch 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>HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final$ git checkout 2.0-beta-0.1Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-finalHEAD is now at df3f601... add atlas.json and cover image
  • 在“分離頭指針”狀態(tài)下,如果做了某些更改然后提交它們,標(biāo)簽不會(huì)發(fā)生變化,但新提交將不屬于任何分支,并且將無法訪問,除非通過確切的提交哈希才能訪問。 因此,如果需要進(jìn)行更改,比如要修復(fù)舊版本中的錯(cuò)誤,那么通常需要?jiǎng)?chuàng)建一個(gè)新分支:
$ git checkout -b version2 v2.0.0Switched to a new branch 'version2'
  • 如果在這之后又進(jìn)行了一次提交,version2 分支就會(huì)因?yàn)檫@個(gè)改動(dòng)向前移動(dòng),此時(shí)它就會(huì)和 v2.0.0 標(biāo)簽稍微有些不同,這時(shí)就要當(dāng)心。

七、Git 別名

  • Git 并不會(huì)在輸入部分命令時(shí)自動(dòng)推斷出想要的命令,如果不想每次都輸入完整的 Git 命令,可以通過 git config 文件來輕松地為每一個(gè)命令設(shè)置一個(gè)別名。 這里有一些例子:
$ git config --global alias.co checkout$ git config --global alias.br branch$ git config --global alias.ci commit$ git config --global alias.st status
  • 這意味著,當(dāng)要輸入 git commit 時(shí),只需要輸入 git ci。隨著繼續(xù)不斷地使用 Git,可能也會(huì)經(jīng)常使用其他命令,所以創(chuàng)建別名時(shí)不要猶豫。
  • 在創(chuàng)建認(rèn)為應(yīng)該存在的命令時(shí)這個(gè)技術(shù)會(huì)很有用。例如,為了解決取消暫存文件的易用性問題,可以向 Git 中添加自己的取消暫存別名:
$ 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: Josh Goebel <dreamer3@example.com>Date: Tue Aug 26 19:48:51 2008 +0800test for current headSigned-off-by: Scott Chacon <kody@example.com>
  • 可以看出,Git 只是簡(jiǎn)單地將別名替換為對(duì)應(yīng)的命令。然而,可能想要執(zhí)行外部命令,而不是一個(gè) Git 子命令,如果是那樣的話,可以在命令前面加入 ! 符號(hào);如果自己要寫一些與 Git 倉庫協(xié)作的工具的話,那會(huì)很有用。現(xiàn)在演示將 git visual 定義為 gitk 的別名:
$ git config --global alias.visual '!gitk'

總結(jié)

以上是生活随笔為你收集整理的Git之深入解析本地仓库的基本操作·仓库的获取更新和提交历史的查看撤销以及标签别名的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。