git簡明使用手冊

git作為時下最流行的代碼管理工具,Git權(quán)威指南總結(jié)了十條喜歡Git的理由

  • 異地協(xié)同工作;
  • 現(xiàn)場版本控制;
  • 重寫提交說明;
  • 無盡的后悔藥;
  • 更好用的提交列表;
  • 更好的差異比較;
  • 工作進(jìn)度保存;
  • 作為SVN前端實(shí)現(xiàn)移動辦公;
  • 無處不在的分頁器;
  • 快。

其中:

1. 概述

1.1 git客戶端安裝

1.2 git客戶端配置

遠(yuǎn)程倉庫可以通過網(wǎng)頁方式訪問,但通常情況下仍然需要創(chuàng)建本地倉庫:

  1. 創(chuàng)建本地 SSH key:

    • Windows下打開Git Bash,Linux下打開終端;
    • 執(zhí)行ssh-keygen,所有提示均回車確認(rèn),生成私鑰和公鑰:

      <當(dāng)前用戶根目錄>/.ssh/id_rsa
      <當(dāng)前用戶根目錄>/.ssh/id_rsa.pub

    • 查看公鑰文件內(nèi)容并復(fù)制,注意不要復(fù)制命令本身

      cat <當(dāng)前用戶根目錄>/.ssh/id_rsa.pub

  2. 添加遠(yuǎn)程倉庫訪問權(quán)限,不同的服務(wù)器會有不同的配置方法:

    • GitHub需要從右上角頭像右側(cè)的向下箭頭進(jìn)入settings->SSH and GPG keys來添加或者直接通過GitHub客戶端自動添加;
    • gitolite需要將SSH公鑰拷貝到gitolite-admin目錄下的keydir目錄中,并需要gitolite.conf已配置合適的訪問權(quán)限。

    注意:

    • 本機(jī)SSH 私鑰id_rsa不能刪除。
    • 本機(jī)SSH key只需要創(chuàng)建一對,不需要為每個服務(wù)器都創(chuàng)建一對。
  3. 創(chuàng)建本地倉庫并配置

    • 回到Git Bash/終端;
    • 執(zhí)行

      git clone ssh://xxx.git

    • 執(zhí)行本地配置(更多配置參見自定義-Git-配置-Git

      git config --global user.name “姓名”
      git config --global user.email “郵箱”
      git config --global color.ui auto
      git config --global core.ignorecase false

      git config --global core.filemode false
      git config --global core.autocrlf input
      git config --global core.safecrlf true
      git config --global push.default simple
      git config --global rerere.enabled true
    • 配置完成后可顯示本地配置信息

      git config -l --global

    注意

    • 自動補(bǔ)齊: Windows客戶端默認(rèn)支持命令補(bǔ)齊,服務(wù)器上Linux已經(jīng)配置自動補(bǔ)齊,自行安裝的Linux需要參考Git基礎(chǔ)-技巧和竅門進(jìn)行配置;
    • 命令別名:git允許為常用操作設(shè)置別名,以簡化操作(參見Git-基礎(chǔ)-Git-別名):

    git config --global alias.ci commit
    git config --global alias.unstage 'reset HEAD --'

2. git基礎(chǔ)

2.1 基本工作流程

2.2 獲取幫助信息

2.3 合并比較結(jié)果閱讀

git支持外部比較/合并工具(參見外部的合并與比較工具配置說明),但通常使用更為直接的命令行方式:

  • diff結(jié)果閱讀
--- a/src/test.txt  :原始文件(以---開頭) 
+++ b/src/test.txt  :目標(biāo)文件(以+++開頭) 
@@ -1,3 +1,3 @@     :當(dāng)前差異塊的比較對象為原始文件的第1行開始的3行與目標(biāo)文件的地1行開始的3行
-orign              :只存在于原始文件(以-開頭) 
+modified           :只存在于目標(biāo)文件(以+開頭)  
以空格開頭           : 同時存在于原始文件和目標(biāo)文件
  • merge結(jié)果閱讀
<<<<<<<
當(dāng)前分支代碼
=======_
其他分支合并進(jìn)來的代碼
>>>>>>>

2.4 提交(commit)消息格式

git提交消息是日志回溯/代碼審查/二分法問題查找的基礎(chǔ),建議參考thoughtbot規(guī)范

50-character subject line

1. Why was this change necessary?

2. How does it address the problem?

3. Are there any side effects?

建議將模板保存在根目錄下,使用如下命令配置為模板,這樣在提交時就會自動顯示:

git config --global commit.template <模板文件>

3. git倉庫構(gòu)成及訪問路徑

Paste_Image.png

3.1 遠(yuǎn)程倉庫

遠(yuǎn)程倉庫是服務(wù)器上的git倉庫,支持如下常用操作(更多操作參見Git-基礎(chǔ)-遠(yuǎn)程倉庫的使用):

3.1.1 基本操作

  • 查看本地倉庫遠(yuǎn)程倉庫列表

    git remote -v

    如下所示:

    $ git remote -v
    origin  ssh://xxx.git (fetch)
    origin  ssh://xxx.git (push)
    

    注意:每個本地倉庫可以從多個遠(yuǎn)程倉庫獲取代碼,當(dāng)前僅包含一個遠(yuǎn)程倉庫origin。

  • 查看遠(yuǎn)程倉庫概況

    git remote show <遠(yuǎn)程倉庫名稱>

    如下所示:

Paste_Image.png

該操作可用于查看遠(yuǎn)程倉庫的地址,分支情況,與本地分支的差別等等。

3.1.2 從遠(yuǎn)程倉庫到本地倉庫

  • 創(chuàng)建新的本地倉庫

    git clone <遠(yuǎn)程倉庫路徑> <可選的本地倉庫目錄名稱>

  • 從遠(yuǎn)程倉庫獲取最新內(nèi)容,包括新的分支以及原有分支上的改動

    git fetch

  • 從遠(yuǎn)程倉庫獲取最新內(nèi)容,并合并到當(dāng)前分支

    git pull

    注意:

    • 該操作相當(dāng)于git fetch + git merge origin/<當(dāng)前分支名稱>,因此出現(xiàn)沖突時可以使用git merge --abort來終止;
    • 如果發(fā)生沖突,應(yīng)當(dāng)順序執(zhí)行如下操作:
      • 使用git merge --abort終止本次操作;
      • 使用git checkout -b temp創(chuàng)建并切換到1個臨時分支;
      • 使用git branch -D <當(dāng)前分支名稱>刪除當(dāng)前分支;
      • 使用git checkout <當(dāng)前分支名稱>重新從遠(yuǎn)程分支創(chuàng)建本地分支;
      • 使用git branch -D temp刪除臨時分支。
    • ?。?!請勿使用--rebase選項(xiàng),除非你知道你在干什么?。?!。

3.1.3 從本地倉庫到遠(yuǎn)程倉庫

  • 本地倉庫更新到遠(yuǎn)程倉庫

    git push

    注意

    • 若本地分支在遠(yuǎn)程倉庫中沒有對應(yīng)的分支,則本操作會在遠(yuǎn)程倉庫中創(chuàng)建同名分支并自動關(guān)聯(lián);
    • 若與遠(yuǎn)程倉庫代碼沖突且確認(rèn)本地倉庫沒有問題,例如使用git rebase與master分支同步后,則可以使用git push --force來強(qiáng)制推送到服務(wù)器,從而使用本地倉庫覆蓋遠(yuǎn)程倉庫;此時,遠(yuǎn)程倉庫中的修改日志將會丟失。

3.2 本地倉庫

本地倉庫是當(dāng)前工作機(jī)器上的git倉庫,支持如下常用操作:

3.2.1 查看本地倉庫狀態(tài)

  • 查看總體狀態(tài)

    git status

Paste_Image.png

命令結(jié)果中注釋如下:

  • 注1: 本地倉庫當(dāng)前分支名稱;
  • 注2: 本地倉庫當(dāng)前分支與遠(yuǎn)程倉庫同名分支之間的差異;
  • 注3: 推薦執(zhí)行的操作;
  • 注4: 暫存區(qū)(stage)內(nèi)容;
  • 注5: 工作區(qū)內(nèi)容,對倉庫中文件的修改;
  • 注6: 工作區(qū)內(nèi)容,未加入到倉庫中的文件。

3.2.2 查看本地倉庫日志(參見Git-工具-選擇修訂版本

  • 查看所有或某個文件的修改記錄

    git log <可選文件路徑>

  • 查看所有或某個文件的修改記錄的概要(修改文件列別行數(shù)等)

    git log --stat <可選文件路徑>

  • 圖形化簡略模式查看倉庫日志

    git log --oneline --graph

    注意:在提交pull request之前,建議使用該命令確認(rèn)需要合入主線的分支上沒有重疊區(qū)域,例如下圖中紅圈所示的重疊線條,否則出現(xiàn)問題時難以定位錯誤提交:

Paste_Image.png
  • 查看本地分支與遠(yuǎn)程倉庫master分支的差別,即本地分支對應(yīng)的pull request包含的內(nèi)容

    git log --oneline --left-right origin/master...<本地分支名稱>

    對于未與遠(yuǎn)程倉庫master分支同步即rebase的分支:

    $ git log --oneline --left-right origin/master...feature/KTOS-573-add-i2c-subsystem-2
    < deb713e Merge pull request #568 to master
    > be27660 XXXX
    ...
    < a674652 XXXX
    ...
    > c1a52d3 XXXX
    ...
    

    其中,<代表僅存在于遠(yuǎn)程分支上的提交,>代表僅存在于本地分支上的提交。而已經(jīng)與遠(yuǎn)程倉庫master分支同步即rebase的分支,則只包含>,即即僅存在于本地分支上的提交。

  • 查看某次提交中所有或某個文件的具體修改內(nèi)容

    git show <提交ID> <可選文件路徑>

  • 查看文件的歷史版本

    git show <提交ID>:<文件路徑>

  • 查看某個文件中所有或指定行的修改記錄

    git blame <文件路徑>
    git blame -L <起始行>,<結(jié)束行> <文件路徑>
    git blame -L <起始行>,<+行數(shù)> <文件路徑>

3.2.3 查看本地倉庫的git操作記錄并無限回退

  • 查看操作記錄

    git reflog

Paste_Image.png
  • 回退到某次操作后的狀態(tài)

    git reset HEAD@{序號}

    注意

    • 沒有提到到倉庫中的代碼無法恢復(fù);
    • 暫存區(qū)的代碼會受影響,如需要保留可先提交到本地倉庫進(jìn)行備份。

3.3 分支

分支是指向提交的的可變指針(參見Git-分支-分支簡介),每個git倉庫都有一個默認(rèn)創(chuàng)建的master分支和若干其他分支,支持如下常用操作:

3.3.1 查看分支信息

  • 查看本地分支信息

    git branch

    注意:當(dāng)前分支名稱之前會有*標(biāo)志。

  • 查看本地分支詳細(xì)信息

    git branch -v

Paste_Image.png
  • 查看包含分支標(biāo)簽的本地倉庫日志

    git log --oneline --decorate

Paste_Image.png
  • 查看遠(yuǎn)程倉庫分支信息

    git branch -r

Paste_Image.png
  • 查看所有分支(包含本地和遠(yuǎn)程倉庫)信息

    git branch -a

Paste_Image.png

3.3.2 從當(dāng)前分支到其他分支

  • 切換到本地倉庫或遠(yuǎn)程倉庫已有分支

    git checkout <分支名稱>

  • 從當(dāng)前分支創(chuàng)建一個新分支并切換到新分支

    git checkout -b <新分支名稱>

  • 從某個提交創(chuàng)建一個新分支并切換到新分支(用于查看內(nèi)容或者查找問題)

    git checkout <提交ID> -b <新分支名稱>

  • 刪除某個分支

    git branch -D <分支名稱>

3.3.3 從其他分支到當(dāng)前分支

  • 合并其他分支到當(dāng)前分支,

    git merge <其他分支名稱>

    注意

    • 該操作有可能造成提交交錯,影響問題定位,因此不建議使用,除非你知道自己在干什么!?。?/strong>;
    • 如果合并過程中有沖突,需要順序執(zhí)行如下操作:
      • 編輯沖突文件,或刪除不需要的文件;
      • 使用git add -u將修改添加到暫存區(qū);
      • 使用git commit提交修改。
  • 終止當(dāng)前合并操作

    git merge --abort

  • 將其他分支的某個提交合并到當(dāng)前分支

    git cherry-pick <提交ID>

3.4 工作區(qū)和暫存區(qū)

工作區(qū)是工作目錄的形象化稱呼,實(shí)際上就是當(dāng)前分支最新版本的本地副本;暫存區(qū)(stage)則是包含將要提交到本地倉庫中的文件的索引列表(參見Git權(quán)威指南-git暫存區(qū))。

3.4.1 查看工作區(qū)和暫存區(qū)內(nèi)容

  • 查看工作區(qū)中文件的修改內(nèi)容,即比較工作區(qū)與暫存區(qū)中的文件

    git diff <可選路徑或文件名>

  • 查看暫存區(qū)中文件的修改內(nèi)容,即比較暫存區(qū)與HEAD的文件

    git diff --cached <文件名>

  • 比較工作區(qū)與某個提交中的文件

    git diff <提交ID> <可選路徑或文件名>

  • 比較暫存區(qū)與某個提交中的文件

    git diff --cached <提交ID> <可選路徑或文件名>

  • 比較2個提交中的文件

    git diff <提交ID1> <提交ID2> <可選路徑或文件名>
    git diff --name-only <提交ID1> <提交ID2> <可選路徑或文件名>

    注意

    • 2個提交中必須包含對要比較的文件的修改,且提交ID1更舊;
    • --name-only用于只顯示文件名。

3.4.2 從工作區(qū)到暫存區(qū)

  • 將工作區(qū)中的所有或某個文件放到暫存區(qū)

    git add <文件或目錄路徑>

  • 將工作區(qū)中所有對倉庫中已有代碼的修改放到暫存區(qū)

    git add -u

  • 以交互方式暫存文件

    git add -i

    注意

    • 該操作可以每一個被修改的文件和被修改的文件中的每一處修改都作出是否提交到暫存區(qū)的選擇;
    • 詳細(xì)操作參見Git-工具-交互式暫存
  • 刪除文件和目錄

    git rm
    git rm -r

  • 移動文件和目錄

    git mv

3.4.3 從暫存區(qū)到工作區(qū)

  • 將暫存區(qū)中對倉庫中所有或某個文件的修改恢復(fù)到工作區(qū)

    git reset HEAD <可選的文件或目錄路徑>

3.4.4 從暫存區(qū)到本地倉庫

  • 將暫存區(qū)中的內(nèi)容提交到本地倉庫(簡單注釋)

    git commit -m "注釋信息"

  • 將暫存區(qū)中的內(nèi)容提交到本地倉庫(復(fù)雜注釋,將會進(jìn)入文本編輯界面,默認(rèn)使用vi)

    git commit

  • 修改上次提交的注釋信息

    git commit --amend -m "注釋信息"

3.4.5 從本地倉庫到暫存區(qū)即清除暫存區(qū)

  • 使用本地倉庫中某個提交的代碼覆蓋暫存區(qū)并更新HEAD指針

    git reset <提交ID>

    注意,工作區(qū)的內(nèi)容不受影響,但是暫存區(qū)中未提交到本地倉庫中的修改會被覆蓋。

3.4.6 從本地倉庫到工作區(qū)

  • 使用本地倉庫中的最新代碼覆蓋工作區(qū)中的內(nèi)容,即撤銷工作區(qū)內(nèi)的所有或某個文件的修改

    git checkout .
    git checkout -- <文件或者目錄名>

    注意:本操作實(shí)質(zhì)上是用本地倉庫中的數(shù)據(jù)覆蓋工作區(qū)中的內(nèi)容。

  • 使用本地倉庫中某個提交的內(nèi)容覆蓋工作區(qū)中的某個文件或所有內(nèi)容

    git checkout <提交ID> <可選的文件或者目錄名>

  • 使用本地倉庫中某個提交的內(nèi)容覆蓋工作區(qū)和暫存區(qū)并更新HEAD指針

    git reset --hard <提交ID>

3.4.7 從工作區(qū)到本地倉庫

  • 直接將文件提交到本地倉庫

    git commit -a -m "注釋信息"

    注意,該操作不經(jīng)過暫存區(qū),務(wù)必慎用!!!

3.4.8 清除工作區(qū)

  • 清除工作區(qū)

    git clean -fd

3.5 臨時緩沖區(qū)

臨時緩沖區(qū)(stash)是保存臨時修改內(nèi)容的各個分支共享的全局緩沖區(qū),支持如下常用操作(參見Git-工具-儲藏與清理):

3.5.1 查看臨時緩沖區(qū)

  • 顯示臨時緩沖區(qū)內(nèi)保存的工作進(jìn)度

    git stash list

    如下所示:

    $ git stash list
    stash@{0}: On bugfix/KTOS-499-pci-decouple: pci review
    

    其中,第1個:之前的部分是每個工作進(jìn)度的標(biāo)簽,2個:之間的部分是保存該工作進(jìn)度時所在的分支,第2個:之后的部分是該工作進(jìn)度的描述信息。

  • 顯示臨時緩沖區(qū)某個工作進(jìn)度的內(nèi)容

    git stash show stash@{序號}

3.5.2 從工作區(qū)和暫存區(qū)到臨時緩沖區(qū)

  • 將工作區(qū)和暫存區(qū)中對本地倉庫中已有代碼的修改備份到臨時緩沖區(qū)

    git stash save "緩沖區(qū)描述"

  • 將工作區(qū)和暫存區(qū)中的所有修改(包括不在本地倉庫中的文件)備份到臨時緩沖區(qū)

    git stash save -u "緩沖區(qū)描述"

3.5.3 從臨時緩沖區(qū)到工作區(qū)

  • 將臨時緩沖區(qū)中對倉庫中代碼的修改彈出到工作區(qū)

    git stash pop stash@{序號}

  • 將臨時緩沖區(qū)中對倉庫中代碼的修改應(yīng)用到工作區(qū)(保留緩存區(qū)中的工作進(jìn)度)

    git stash apply stash@{序號}

4. git進(jìn)階

4.1 變基(參見Git權(quán)威指南-改變歷史

  • 該操作的基本語法為:

    git rebase --onto <目的提交> <起始提交> <結(jié)束提交>

  • 變基操作會為切換到 <目的提交>,然后把<起始提交>和<結(jié)束提交>之間的提交逐條疊加到<目的提交>之后;如果--onto <目的提交>未指定,則使用<起始提交>;如果<結(jié)束提交>未指定,則使用當(dāng)前分支;

  • 變基操作通常用于當(dāng)前任務(wù)分支跟主線同步,例如git rebase master;

  • 變基操作中出現(xiàn)問題時,需要根據(jù)對沖突的文件提示進(jìn)行修改,完成后使用git add -u提交到暫存區(qū),并使用git rebase --continue繼續(xù)或git rebase --skip跳過當(dāng)前提交繼續(xù)同步;

  • 變基操作可以被git rebase --abort終止以恢復(fù)到操作前狀態(tài);

  • 變基操作結(jié)束以后,推送到服務(wù)器時,如果報(bào)錯,需要使用git push --force強(qiáng)制推送。

  • 如果修改內(nèi)容較多,且長時間未同步,可能會出現(xiàn)同一文件多次沖突,因此強(qiáng)烈建議打開Rerere功能:

    git config --global rerere.enabled true

    使能后,沖突解決方案會被記錄,并在再次遇到時自動應(yīng)用,不需要再吃手工編輯文件解決,只需要git add -u即可。

4.2 二分法查找錯誤版本(參考Git權(quán)威指南-二分查找

該方法用于快速定位問題,但是需要如下條件作為前提才能高效工作:

  • 提交線性排序,不存在下圖所示的重疊部分:
Paste_Image.png
  • 每個關(guān)鍵提交最好都能編譯通過或運(yùn)行。

該操作具體步驟如下(使用簡單實(shí)例,具體使用時根據(jù)需要調(diào)整):

  • 查看當(dāng)前日志

    $ git log --oneline**
    ebc659b second bad
    2fe7f29 first bad
    abfcfbc second good
    84ec8c3 first good
    
  • 啟動查找

    $ git bisect start
    
  • 標(biāo)志當(dāng)前版本為壞版本

    $ git bisect bad
    
  • 標(biāo)志某個好版本作為起點(diǎn)

    $  git bisect good 84ec8c3
    Bisecting: 0 revisions left to test after this (roughly 1 step)
    [2fe7f29987123abe3fa0cb3429c07b597f86594c] first bad
    

    此時會自動跳轉(zhuǎn)到中間版本:

    $ git log --oneline
    2fe7f29 first bad
    abfcfbc second good
    84ec8c3 first good
    
  • 如果當(dāng)前版本為壞版本,標(biāo)志他

    $ git bisect bad
    Bisecting: 0 revisions left to test after this (roughly 0 steps)
    [abfcfbc361beb42551b4219d6d70ccb1fe3ac103] second good
    

    此時會自動跳轉(zhuǎn)到中間版本:

    $ git log --oneline
    abfcfbc second good
    84ec8c3 first good
    
  • 如果當(dāng)前版本為好版本,標(biāo)志他

    $ git bisect good
    2fe7f29987123abe3fa0cb3429c07b597f86594c is the first bad commit
    commit 2fe7f29987123abe3fa0cb3429c07b597f86594c
    Author: Matt Zu<matt.zu@pc.com>
    Date:   Tue Dec 20 20:36:56 2016 +0800
        first bad
    :100644 100644 0cfbf08886fca9a91cb753ec8734c84fcbe52c9f c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 M      test.c
    

    找到第一個壞版本時,自動結(jié)束,不再跳轉(zhuǎn)到中間版本:

    $ git log --oneline
    abfcfbc second good
    84ec8c3 first good
    
  • 切換到第一個壞版本

    $ git checkout bisect/bad
    Previous HEAD position was abfcfbc... second good
    HEAD is now at 2fe7f29... first bad
    

    日志如下:

    $ git log --oneline
    2fe7f29 first bad
    abfcfbc second good
    84ec8c3 first good
    

4.3 壓縮提交(參見Git-工具-重置揭密#壓縮

每個pull request中應(yīng)當(dāng)包含盡可能少的提交,因此在推送到服務(wù)器之前,每個功能點(diǎn)或者修改點(diǎn)包含的所有提交都應(yīng)當(dāng)壓縮成一個提交,并編譯通過,最好能夠通過基本測試。

該操作具體步驟如下(使用簡單實(shí)例,具體使用時根據(jù)需要調(diào)整):

  • 查看當(dāng)前日志

    $ git log --oneline
    f0fd7c9 commit msg 2
    335067c commit msg 1
    abfcfbc second good
    84ec8c3 first good
    
  • 查看文件修改記錄

    $ git blame test.c
    abfcfbc3 (Matt Zu 2016-12-20 20:36:35 +0800 1) 2
    335067c5 (Matt Zu 2016-12-27 14:28:33 +0800 2) 3
    f0fd7c9b (Matt Zu 2016-12-27 14:28:48 +0800 3) 4
    
  • 將HEAD指針回退到需要合并的提交之前

    $ git reset --soft 335067c^
    

注意^用于回退到上一次提交,等價于~1;也可以疊加使用以回退到N次提交之前,等價于~N。

  • 查看日志

    $ git log --oneline
    abfcfbc second good
    84ec8c3 first good
    
  • 查看修改內(nèi)容

    $ git status
    On branch msg
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
            modified:   test.c
    $ git diff --cached
    diff --git a/test.c b/test.c
    index 0cfbf08..dcf37cd 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
     2
    +3
    +4
    
  • 再次提交代碼以合并提交

    git commit -m "combine commit msg"
    
  • 查看日志

    $ git log --oneline
    a1fadaf combine commit msg
    abfcfbc second good
    84ec8c3 first good
    
  • 查看修改內(nèi)容

    $ git log --oneline -p -1
    a1fadaf combine commit msg
    diff --git a/test.c b/test.c
    index 0cfbf08..dcf37cd 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
     2
    +3
    +4
    

4.4 拆分提交(參見Git-工具-重寫歷史#拆分提交

該操作用于對不合理的提交壓縮進(jìn)行拆分,以方便cherry-pick和二分法查找等后續(xù)操作。

注意:該操作也可以用于調(diào)整提交的順序,參見Git-工具-重寫歷史#重新排序提交。

該操作具體步驟如下(使用簡單實(shí)例,具體使用時根據(jù)需要調(diào)整):

  • 查看日志

    $ git log --oneline
    0b22507 add aditional number
    abc373f update number and insert lines
    abfcfbc second good
    84ec8c3 first good
    

    假定abc373f為需要拆分的提交。

  • 查看修改內(nèi)容

    $ git log --oneline -p -2
    0b22507 add aditional number
    diff --git a/test.c b/test.c
    index 2ff46c8..ab7998f 100644
    --- a/test.c
    +++ b/test.c
    @@ -1,3 +1,3 @@
    
    -3
    +3 4 5
    
    abc373f update number and insert lines
    diff --git a/test.c b/test.c
    index 0cfbf08..2ff46c8 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
    -2
    +
    +3
    +
    
  • 變基到需要拆分的提交(abc373f)之前

    $ git rebase -i abc373f^
    

    此時會進(jìn)入vim界面,顯示如下內(nèi)容:

    pick abc373f update number and insert lines
    pick 0b22507 add aditional number
    
    # Rebase abfcfbc..0b22507 onto abfcfbc (2 commands)
    #
    # Commands:
    # p, pick = use commit
    # r, reword = use commit, but edit the commit message
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    # f, fixup = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    # d, drop = remove commit
    #
    # These lines can be re-ordered; they are executed from top to bottom.
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    #
    # However, if you remove everything, the rebase will be aborted.
    #
    # Note that empty commits are commented out
    ~
    

    根據(jù)提示,將需要拆分的提交前面的pick修改為edit此處可以調(diào)整提交順序):

    edit abc373f update number and insert lines
    pick 0b22507 add aditional number
    

    然后保存并退出,顯示如下提示:

    $ git rebase -i abc373f^
    warning: Stopped at abc373f... update number and insert lines
    You can amend the commit now, with
    
      git commit --amend
    
    Once you are satisfied with your changes, run
    
      git rebase --continue
    
  • 查看日志

    $ git log --oneline
    abc373f update number and insert lines
    abfcfbc second good
    84ec8c3 first good
    
  • 回退HEAD指針到上一次提交

    $ git reset HEAD^
    Unstaged changes after reset:
    M       test.c
    
  • 查看修改內(nèi)容

    $ git diff
    diff --git a/test.c b/test.c
    index 0cfbf08..2ff46c8 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
    -2
    +
    +3
    +
    
  • 將修改內(nèi)容保存到臨時緩沖區(qū)

    $ git stash save "msg split"
    Saved working directory and index state On (no branch): msg split
    HEAD is now at abfcfbc second good
    
  • 將修改內(nèi)容應(yīng)用到工作區(qū)并保留緩沖區(qū)中的進(jìn)度

    $ git stash apply stash@{0}
    
  • 移除不需要的修改并提交(此處僅保留數(shù)字更新)

    $ git diff
    diff --git a/test.c b/test.c
    index 0cfbf08..00750ed 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1 @@
    -2
    +3
    $ git add -u
    $ git commit -m "update number"
    [detached HEAD c2b7f71] update number
     1 file changed, 1 insertion(+), 1 deletion(-)
    
  • 查看日志

    $ git log --oneline
    c2b7f71 update number
    abfcfbc second good
    84ec8c3 first good
    
  • 查看修改內(nèi)容

    $ git log --oneline -p -1
    c2b7f71 update number
    diff --git a/test.c b/test.c
    index 0cfbf08..00750ed 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1 @@
    -2
    +3
    
  • 將修改內(nèi)容彈出到工作區(qū),修改沖突后再次提交

    $ git stash pop stash@{0}
    Auto-merging test.c
    CONFLICT (content): Merge conflict in test.c
    Recorded preimage for 'test.c'
    $ vim test.c
    $ git commit -m "insert lines"
    Recorded resolution for 'test.c'.
    [detached HEAD 13a6963] insert lines
     1 file changed, 2 insertions(+)
    
  • 查看日志

    $ git log --oneline
    13a6963 insert lines
    c2b7f71 update number
    abfcfbc second good
    84ec8c3 first good
    
  • 查看修改內(nèi)容

    $ git log --oneline -p -2
    13a6963 insert lines
    diff --git a/test.c b/test.c
    index 00750ed..2ff46c8 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
    +
     3
    +
    c2b7f71 update number
    diff --git a/test.c b/test.c
    index 0cfbf08..00750ed 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1 @@
    -2
    +3
    
  • 繼續(xù)變基

    $ git rebase --continue
    Successfully rebased and updated refs/heads/msg_split.
    
  • 查看日志

    $ git log --oneline
    dc4e8fa add aditional number
    13a6963 insert lines
    c2b7f71 update number
    abfcfbc second good
    84ec8c3 first good
    
  • 查看修改內(nèi)容

    $ git log --oneline -p -3
    dc4e8fa add aditional number
    diff --git a/test.c b/test.c
    index 2ff46c8..ab7998f 100644
    --- a/test.c
    +++ b/test.c
    @@ -1,3 +1,3 @@
    
    -3
    +3 4 5
    
    13a6963 insert lines
    diff --git a/test.c b/test.c
    index 00750ed..2ff46c8 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1,3 @@
    +
     3
    +
    c2b7f71 update number
    diff --git a/test.c b/test.c
    index 0cfbf08..00750ed 100644
    --- a/test.c
    +++ b/test.c
    @@ -1 +1 @@
    -2
    +3
    

4.5 補(bǔ)丁操作(參見分布式-Git-向一個項(xiàng)目貢獻(xiàn)#r_project_over_email分布式 Git - 維護(hù)項(xiàng)目

該操作用于創(chuàng)建和應(yīng)用patch。

  1. 標(biāo)準(zhǔn)格式補(bǔ)丁創(chuàng)建

    每個標(biāo)準(zhǔn)格式補(bǔ)丁就是1個包含提交消息、修改文件概述和修改文件細(xì)節(jié)的mbox格式文件:

    $ cat 0001-test1.patch
    From 0d57e1ea1a27c54c7ec62cacfccb7d037923150a Mon Sep 17 00:00:00 2001
    From: matt <matt@pc.com>
    Date: Mon, 28 May 2018 16:29:57 +0800
    Subject: [PATCH 1/2] test1
    
    ---
     README | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    !!!此處可以增加自定義信息以方便閱讀,應(yīng)用補(bǔ)丁時會被忽略。!!!
    
    diff --git a/README b/README
    index df1d5d6..3409f8c 100644
    --- a/README
    +++ b/README
    @@ -5,7 +5,7 @@
    
     Summary:
     ========
    -
    +1111111111111111111111111111111
     This directory contains the source code for U-Boot, a boot loader for
     Embedded boards based on PowerPC, ARM, MIPS and several other
     processors, which can be installed in a boot ROM and used to
    --
    2.10.1.windows.1
    

    操作命令如下所示:

    • git format-patch -M master

      為主線上不存在的每個提交創(chuàng)建一個標(biāo)準(zhǔn)格式補(bǔ)丁文件,同時查找重命名操作。注意,該操作需要切換到當(dāng)前工作分支,并與主線同步后執(zhí)行,即git checkout <工作分支>git rebase master之后。

    • git format-patch <起始提交ID或者標(biāo)簽>...<結(jié)束提交ID或者標(biāo)簽>

      為當(dāng)前分支上起始提交ID或者標(biāo)簽與結(jié)束提交ID或者標(biāo)簽之間的每個提交創(chuàng)建一個標(biāo)準(zhǔn)格式補(bǔ)丁文件,不包括起始提交ID或者標(biāo)簽,但是包含結(jié)束提交ID或者標(biāo)簽。

      注意:

      • --cover-letter選項(xiàng)用于創(chuàng)建郵一個額外的mbox格式文件,包含所有提交的信息,而不只是某一個提交的信息。
        $ cat 0000-cover-letter.patch
        From 89d4c523ebf5bb6c700bcbf8e2c899c3f1d345fe Mon Sep 17 00:00:00 2001
        From: matt <matt@pc.com>
        Date: Tue, 29 May 2018 09:28:44 +0800
        Subject: [PATCH 0/2] *** SUBJECT HERE ***
        
        *** BLURB HERE ***
        
        matt (2):
          test1
          test2
        
         README | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        --
        2.10.1.windows.1
        
      • 結(jié)束提交ID或者標(biāo)簽可以省略,默認(rèn)為HEAD。
    • git am <標(biāo)準(zhǔn)格式補(bǔ)丁文件>

      從標(biāo)準(zhǔn)格式補(bǔ)丁文件中讀取補(bǔ)丁內(nèi)容并應(yīng)用到當(dāng)前分支。注意,補(bǔ)丁文件應(yīng)用沖突時,該操作會停下來,提示手工解決沖突,并在沖突解決后使用git am --resolved繼續(xù)應(yīng)用下一個補(bǔ)丁:

      $ vim README
      $ git add ticgit.gemspec
      $ git am --resolved
      Applying: test1
      

      當(dāng)然,也可以跳過(git am --skip)或者終止(git am --abort)本次操作。

  2. diff格式補(bǔ)丁

    diff格式補(bǔ)丁使用diff命令創(chuàng)建,就是一個包含修改內(nèi)容的文本文件,不包含提交消息和修改文件概述,但是可已經(jīng)將多個提交的修改合并到一個文件中,方便閱讀,但是應(yīng)用補(bǔ)丁時只有補(bǔ)丁內(nèi)容全部應(yīng)用和完全不應(yīng)用兩種可能

    $ cat patch.txt
    diff --git a/README b/README
    index df1d5d6..3409f8c 100644
    --- a/README
    +++ b/README
    @@ -5,7 +5,7 @@
    
     Summary:
     ========
    -
    +1111111111111111111111111111111
     This directory contains the source code for U-Boot, a boot loader for
     Embedded boards based on PowerPC, ARM, MIPS and several other
     processors, which can be installed in a boot ROM and used to
    
    • git diff -c -p <起始提交ID或者標(biāo)簽>...<結(jié)束提交ID或者標(biāo)簽> > <補(bǔ)丁文件名稱>

      將當(dāng)前分支上起始提交ID或者標(biāo)簽與結(jié)束提交ID或者標(biāo)簽之間的所有修改創(chuàng)建一個diff格式補(bǔ)丁,不包括起始提交ID或者標(biāo)簽,但是包含結(jié)束提交ID或者標(biāo)簽。注意,結(jié)束提交ID或者標(biāo)簽可以省略,默認(rèn)為HEAD,例如:

      git diff -c -p HEAD^ > patch.txt

    • git apply <補(bǔ)丁文件名稱>

      讀取補(bǔ)丁內(nèi)容并應(yīng)用到當(dāng)前分支。注意,本操作只修改當(dāng)前分支文件,不會自動創(chuàng)建提交。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容