痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)

痞子衡發表於2016-12-18

  今天是Git系列課程第五課,上一課我們做了Git本地提交前的準備工作,今天痞子衡要講的是Git本地提交操作。

  當我們在倉庫工作區下完成了檔案增刪改操作之後,並且使用git add將檔案改動記錄在暫存區之後,便可以開始將其提交到Git本地倉庫。

1.本地檔案改動提交git commit

  Git空間本地的改動完成之後可以直接提交,有如下三種提交命令選項:

1.1將暫存區內容提交git commit -m ["description"]

  暫存區裡目前只有app/app.c檔案,我們先將其提交至倉庫。

// 將暫存區裡所有改動提交到本地倉庫,提交標題為"Initial application"
jay@pc MINGW64 /d/my_project/gittest (master)
$ git commit -m "Initial application"

[master 0a0c0fc] Initial application
 1 file changed, 7 insertions(+)
 create mode 100644 app/app.c

// 檢視本地提交日誌,確認提交是否已記錄在倉庫中
jay@pc MINGW64 /d/my_project/gittest (master)
$ git log

commit 0a0c0fcec8a1ef56bfc6a24e68bbf1436b2ef2cf (HEAD -> master)
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sat Mar 10 21:58:36 2018 +0800

    Initial application

commit 867df08b4e13649e30926b483279dddce32750c2 (origin/master, origin/HEAD)
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sat Mar 10 20:11:04 2018 +0800

    second commit

1.2追加提交git commit --amend -m ["description"]

  工作區裡面還有app/test.c檔案處於Untracked狀態,我們想將其也加到1.1的提交裡合併成一個提交。

// 將Untracked狀態的test.c檔案新增到暫存區,用於新提交
jay@pc MINGW64 /d/my_project/gittest (master)
$ git add app/test.c

// 將暫存區裡新改動追加提交到本地倉庫,與上一次提交進行合併,並修改提交標題為"Initial application and test"
jay@pc MINGW64 /d/my_project/gittest (master)
$ git commit --amend -m "Initial application and test"

[master 589f65b] Initial application and test
 Date: Sat Mar 10 21:58:36 2018 +0800
 2 files changed, 7 insertions(+)
 create mode 100644 app/app.c
 create mode 100644 app/test.c

// 檢視本地提交日誌,確實兩次提交被合併成了一個
jay@pc MINGW64 /d/my_project/gittest (master)
$ git log

commit 589f65b386dd4475bb884c40ea1441d8449fdcd1 (HEAD -> master)
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sat Mar 10 21:58:36 2018 +0800

    Initial application and test

commit 867df08b4e13649e30926b483279dddce32750c2 (origin/master, origin/HEAD)
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sat Mar 10 20:11:04 2018 +0800

    second commit

1.3非Untracked檔案的改動全部提交git commit -a -m ["description"]

  我們新增一個名叫platform.c空白檔案,並將其git add到暫存區;且對已提交的空白test.c檔案修改恢復其一開始的內容。此時我們工作區(test.c)和暫存區(platform.c)均存在檔案改動。有沒有可能一次性將test.c和platform.c改動提交上去,答案當然是有。

// 將platform.c改動新增到暫存區
jay@pc MINGW64 /d/my_project/gittest (master)
$ git add app/platform.c

// 檢視Git空間當前狀態,test.c改動在工作區,platform.c改動在暫存區
jay@pc MINGW64 /d/my_project/gittest (master)
$ git status

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   app/platform.c

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:   app/test.c

// 將Git空間內非Untracked改動之外的所有改動(無論是工作區/暫存區)一次性提交到本地倉庫,此處為test.c和platform.c
jay@pc MINGW64 /d/my_project/gittest (master)
$ git commit -a -m "Add initial platform and update test"

[master 610feaf] Add initial platform and update test
 2 files changed, 6 insertions(+)
 create mode 100644 app/platform.c

// 檢視Git空間當前狀態,沒有任何改動記錄,說明test.c和platform.c改動已被提交到倉庫
jay@pc MINGW64 /d/my_project/gittest (master)
$ git status

On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

// 檢視本地提交日誌,又多了一次名為"Add initial platform and update test"的新提交
jay@pc MINGW64 /d/my_project/gittest (master)
$ git log

commit 610feafbf5264b66dd0515f90cce79169aebd995 (HEAD -> master)
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sun Mar 11 07:46:16 2018 +0800

    Add initial platform and update test

commit 589f65b386dd4475bb884c40ea1441d8449fdcd1
Author: Jay Heng <hengjie1989@foxmail.com>
Date:   Sat Mar 10 21:58:36 2018 +0800

    Initial application and test

  需要注意的是git commit -a雖然是-all的簡寫,但其並不是將Git空間內所有改動全部提交,其不會提交工作區裡新建的檔案(Untracked狀態)。

2.補丁包方式提交

  Git是分散式版本控制系統,一個專案常常由多個人一起開發,有時候我們想把本地的改動交給別人去完成提交,傳統的做法是把你改動的所有檔案全部提取出來打包傳送給對方,但顯然這樣做比較繁瑣,而且你的提交描述也容易丟失。Git提供了一種很好方式解決這個需求,即生成一個patch,這個patch就是你本地的一次提交的所有資訊,你只需要把這個patch發給別人就可以了。

2.1生成補丁包git format-patch

  git format-patch命令是以本地提交為基礎的,讓我們先看看目前本地有多少提交:

// 圖形化方式檢視本地倉庫裡的歷史提交,共記錄4個提交
jay@pc MINGW64 /d/my_project/gittest (master)
$ gitk
痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)

  由上圖可知,倉庫裡一共有4次提交,其中兩次已推送到遠端,還有兩次在本地未推送:

2.1.1指定任意單個提交git format-patch -1 [commit]

  讓我們試著將"Initial application and test"這個提交生成patch:

// 將SHA-1號前7位為589f65b的提交生成一個patch
jay@pc MINGW64 /d/my_project/gittest (master)
$ git format-patch -1 589f65b
0001-Initial-application-and-test.patch

  此時在gittest倉庫目錄下便可以看到生成的.patch檔案,讓我們用文字編輯器開啟它看一看,確實包含了這個提交的所有改動。

From 589f65b386dd4475bb884c40ea1441d8449fdcd1 Mon Sep 17 00:00:00 2001
From: Jay Heng <hengjie1989@foxmail.com>
Date: Sat, 10 Mar 2018 21:58:36 +0800
Subject: [PATCH] Initial application and test

---
 app/app.c  | 7 +++++++
 app/test.c | 0
 2 files changed, 7 insertions(+)
 create mode 100644 app/app.c
 create mode 100644 app/test.c

diff --git a/app/app.c b/app/app.c
new file mode 100644
index 0000000..20fe868
--- /dev/null
+++ b/app/app.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdlib.h>
+int main(void)
+{
+    printf("hello world\n");
+    return 0;
+}
\ No newline at end of file
diff --git a/app/test.c b/app/test.c
new file mode 100644
index 0000000..e69de29
-- 
2.16.2.windows.1

2.1.2當前提交之前n個提交git format-patch -n

  如果一次想把本地未推送的提交全部生成patch,也可以試試-n引數,-1代表生成最近的一次提交的patch,-2代表生成最近兩次提交的patch,以此類推。這個引數也可以用HEAD替換,HEAD^ 等效於-1,HEAD^^等效於-2,HEAD~n等效於-n。

// 將最近3次提交全部生成patch
jay@pc MINGW64 /d/my_project/gittest (master)
$ git format-patch HEAD~3

0001-second-commit.patch
0002-Initial-application-and-test.patch
0003-Add-initial-platform-and-update-test.patch

// 依然是將最近3次提交全部生成patch
jay@pc MINGW64 /d/my_project/gittest (master)
$ git format-patch -3

0001-second-commit.patch
0002-Initial-application-and-test.patch
0003-Add-initial-platform-and-update-test.patch

2.1.3某個提交之後的所有提交git format-patch [commit]

  如果你覺得用-n引數顯得有點繁瑣,比如本地有很多個提交,你需要先往回數一共有多少個。還有一個方法是直接指定某個提交,以某個提交為基準往後的所有提交全部生成patch,比如我們以"second commit"為基準:

// 將SHA-1號前7位為867df08的提交之後的所有提交全部生成patch
jay@pc MINGW64 /d/my_project/gittest (master)
$ git format-patch 867df08

0001-Initial-application-and-test.patch
0002-Add-initial-platform-and-update-test.patch

2.2應用補丁包git am

  2.1.3節生成了2個補丁包,讓我們試著用一下這兩個補丁包,在用之前我們需要先把本地倉庫中這兩次提交撤銷並且也不保留在工作區(即完全刪除)。

// 將最近兩次提交在倉庫裡直接刪除,不留痕跡
jay@pc MINGW64 /d/my_project/gittest (master)
$ git reset --hard HEAD~2

HEAD is now at 867df08 second commit

// 檢視本地提交日誌,確實最近兩次提交已被刪除
jay@pc MINGW64 /d/my_project/gittest (master)
$ gitk
痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)

jay@pc MINGW64 /d/my_project/gittest (master)
$ git status

On branch master
Your branch is up to date with 'origin/master'.

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

        0001-Initial-application-and-test.patch
        0002-Add-initial-platform-and-update-test.patch

nothing added to commit but untracked files present (use "git add" to track)

2.2.1指定單個補丁包git am [patch path]

  讓我們試著將0001-Initial-application-and-test.patch打入我們的倉庫。

// 將名為0001-Initial-application-and-test的patch檔案打入倉庫
jay@pc MINGW64 /d/my_project/gittest (master)
$ git am 0001-Initial-application-and-test.patch

Applying: Initial application and test

// 檢視本地提交日誌,確實patch已經進入倉庫
jay@pc MINGW64 /d/my_project/gittest (master)
$ gitk
痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)

  細心的朋友可能會注意到,同一個patch在生成和打入的時候SHA-1號是不一樣的,是的,Git會保證任何時候任何人在任何本地倉庫生成的任何提交都是唯一的。

2.2.2指定目錄下所有補丁包git am [patch dir/*.patch]

  讓我們試著將gittest目錄下的所有patch全部打入我們的倉庫,需要注意的是由於2.2.1中已經將編號為0001 patch打入了倉庫,所有我們需要先將這個patch檔案刪除,否則在打入的時候會報錯。

// 將gittest目錄下的所有patch檔案全部打入倉庫
jay@pc MINGW64 /d/my_project/gittest (master)
$ git am *.patch

Applying: Add initial platform and update test

// 檢視本地提交日誌,確實patch已經都進入倉庫
jay@pc MINGW64 /d/my_project/gittest (master)
$ gitk
痞子衡嵌入式:第一本Git命令教程(5)- 提交(commit/format-patch/am)

相關文章