1. 程式人生 > >git使用教程-一篇文章全搞定哦

git使用教程-一篇文章全搞定哦

Git使用教程

Git是什麼

文章轉載自 程式碼飛:https://code.bywind.cn/2018/07/14/170/

Git是一個開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的專案。 
Git是 Linus Torvalds 為了幫助管理 Linux 核心開發而開發的一個開放原始碼的版本控制軟體。 
Git與常用的版本控制工具 CVS, Subversion 等不同,它採用了分散式版本庫的方式,不必伺服器端軟體支援。

Git與SVN的區別

GIT不僅僅是個版本控制系統,它也是個內容管理系統(CMS),工作管理系統等。 
如果你是一個具有使用SVN背景的人,你需要做一定的思想轉換,來適應GIT提供的一些概念和特徵。 
Git 與 SVN 區別點:

  1. GIT是分散式的,SVN不是:這是GIT和其它非分散式的版本控制系統,例如SVN,CVS等,最核心的區別。
  2. GIT把內容按元資料方式儲存,而SVN是按檔案:所有的資源控制系統都是把檔案的元資訊隱藏在一個類似.svn,.cvs等的資料夾裡。
  3. GIT分支和SVN的分支不同:分支在SVN中一點不特別,就是版本庫中的另外的一個目錄。
  4. GIT沒有一個全域性的版本號,而SVN有:目前為止這是跟SVN相比GIT缺少的最大的一個特徵。
  5. GIT的內容完整性要優於SVN:GIT的內容儲存使用的是SHA-1雜湊演算法。這能確保程式碼內容的完整性,確保在遇到磁碟故障和網路問題時降低對版本庫的破壞。

Git配置 git config

Git 提供了一個叫做 git config 的工具,專門用來配置或讀取相應的工作環境變數。 
這些環境變數,決定了 Git 在各個環節的具體工作方式和行為。這些變數可以存放在以下三個不同的地方:

/etc/gitconfig 檔案:系統中對所有使用者都普遍適用的配置。若使用 git config 時用 –system 選項,讀寫的就是這個檔案。 
~/.gitconfig 檔案:使用者目錄下的配置檔案只適用於該使用者。若使用 git config 時用 –global 選項,讀寫的就是這個檔案。 
當前專案的 Git 目錄中的配置檔案(也就是工作目錄中的 .git/config 檔案):這裡的配置僅僅針對當前專案有效。每一個級別的配置都會覆蓋上層的相同配置,所以 .git/config 裡的配置會覆蓋 /etc/gitconfig 中的同名變數。

在 Windows 系統上,Git 會找尋使用者主目錄下的 .gitconfig 檔案。主目錄即 $HOME 變數指定的目錄,一般都是 C:\Documents and Settings\$USER。

此外,Git 還會嘗試找尋 /etc/gitconfig 檔案,只不過看當初 Git 裝在什麼目錄,就以此作為根目錄來定位。

1.使用者資訊 git config user

配置個人的使用者名稱稱和電子郵件地址:

$ git config --global user.name "wyndam"
$ git config --global user.email "[email protected]"

如果用了–global選項,那麼更改的配置檔案就是位於你使用者主目錄下的那個,以後你所有的專案都會預設使用這裡配置的使用者資訊。 
如果要在某個特定的專案中使用其他名字或者電郵,只要去掉–global選項重新配置即可,新的設定儲存在當前專案的 .git/config 檔案裡。

2.文字編輯器

設定Git預設使用的文字編輯器, 一般可能會是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的話,可以重新設定:

$ git config --global core.editor emacs

3.差異分析工具

還有一個比較常用的是,在解決合併衝突時使用哪種差異分析工具。比如要改用 vimdiff 的話:

$ git config --global merge.tool vimdiff

Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合併工具的輸出資訊。 
當然,你也可以指定使用自己開發的工具,具體怎麼做可以參閱後面的章節。

4.檢視配置資訊 git config –list

要檢查已有的配置資訊,可以使用 git config –list 命令:

$ git config --list

core.symlinks=false
core.autocrlf=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
pack.packsizelimit=2g
help.format=html
http.sslcainfo=E:/Platform/Git/mingw32/ssl/certs/ca-bundle.crt
diff.astextplain.textconv=astextplain
rebase.autosquash=true
filter.lfs.clean=git-lfs clean %f
filter.lfs.smudge=git-lfs smudge %f
filter.lfs.required=true
user.name=Wyndam
[email protected]
core.editor=subl

有時候會看到重複的變數名,那就說明它們來自不同的配置檔案(比如 /etc/gitconfig 和 ~/.gitconfig),不過最終 Git 實際採用的是最後一個。 
這些配置我們也可以在 ~/.gitconfig 或 /etc/gitconfig 看到,如下所示:

[filter "lfs"]
    clean = git-lfs clean %f
    smudge = git-lfs smudge %f
    required = true
[user]
    name = Wyndam
    email = [email protected]
[core]
    editor = subl

也可以直接查閱某個環境變數的設定,只要把特定的名字跟在後面即可,像這樣:

$ git config user.email

[email protected]

Git工作流程

本章節我們將為大家介紹 Git 的工作流程。 
一般工作流程如下: 
1. 克隆 Git 資源作為工作目錄。 
2. 在克隆的資源上新增或修改檔案。 
3. 如果其他人修改了,你可以更新資源。 
4. 在提交前檢視修改。 
5. 提交修改。 
6. 在修改完成後,如果發現錯誤,可以撤回提交併再次修改並提交。 
下圖展示了 Git 的工作流程: 
git流程圖

Git 工作區、暫存區和版本庫

基本概念

我們先來理解下Git 工作區、暫存區和版本庫概念

  • 工作區:就是你專案的目錄(可見目錄)。
  • 快取區:英文叫stage, 或index。一般存放在”git目錄”下的index檔案(.git/index)中,所以我們把暫存區有時也叫作索引(index)。
  • 版本庫:工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。

下面這個圖展示了工作區、版本庫中的暫存區和版本庫之間的關係: 
工作區間

Git 建立倉庫

本章節我們將為大家介紹如何建立一個 Git 倉庫。 
你可以使用一個已經存在的目錄作為Git倉庫。

新建本地倉庫 git init

Git 使用 git init 命令來初始化一個 Git 倉庫,Git 的很多命令都需要在 Git 的倉庫中執行,所以 git init 是使用 Git 的第一個命令。 
在執行完成 git init 命令後,Git 倉庫會生成一個 .git 目錄,該目錄包含了資源的所有元資料,其他的專案目錄保持不變(不像 SVN 會在每個子目錄生成 .svn 目錄,Git 只在倉庫的根目錄生成 .git 目錄)。

使用方法

使用當前目錄作為Git倉庫,我們只需使它初始化。

$ git init

該命令執行完後會在當前目錄生成一個 .git 目錄。 
使用我們指定目錄作為Git倉庫。

$ git init newrepo

初始化後,會在 newrepo 目錄下會出現一個名為 .git 的目錄,所有 Git 需要的資料和資源都存放在這個目錄中。 
如果當前目錄下有幾個檔案想要納入版本控制,需要先用 git add 命令告訴 Git 開始對這些檔案進行跟蹤,然後提交:

$ git add *.java
$ git add README.md
$ git commit -m "inital commit"

以上命令將目錄下以 .java 結尾及 README.md 檔案提交到倉庫中。

複製遠端倉庫 git clone

我們使用 git clone 從現有 Git 倉庫中拷貝專案(類似 svn checkout)。 
克隆倉庫的命令格式為:

$ git clone <repo>

如果我們需要克隆到指定的目錄,可以使用以下命令格式:

$ git clone <repo> <directory>

引數說明:

  • repo:Git 倉庫。
  • directory:本地目錄。

比如,要克隆 Ruby 語言的 Git 程式碼倉庫 Grit,可以用下面的命令:

$ git clone git://github.com/schacon/grit.git

執行該命令後,會在當前目錄下建立一個名為grit的目錄,其中包含一個 .git 的目錄,用於儲存下載下來的所有版本記錄。 
如果要自己定義要新建的專案目錄名稱,可以在上面的命令末尾指定新的名字:

$ git clone git://github.com/schacon/grit.git mygrit

Git基本操作

Git 的工作就是建立和儲存你專案的快照及與之後的快照進行對比。本章將對有關建立與提交你的專案快照的命令作介紹。

獲取與建立專案命令

git init

用 git init 在目錄中建立新的 Git 倉庫。 你可以在任何時候、任何目錄中這麼做,完全是本地化的。 
在目錄中執行 git init,就可以建立一個 Git 倉庫了。比如我們建立 runoob 專案:

$ mkdir wyndam
$ cd wyndam/
$ git init
Initialized empty Git repository in C:/Users/lion/Desktop/wyndam/.git/
# 在 桌面/wyndam/ 目錄初始化空 Git 倉庫完畢。

現在你可以看到在你的專案中生成了 .git 這個子目錄。 這就是你的 Git 倉庫了,所有有關你的此專案的快照資料都存放在這裡。

$ ls -a
.  ..  .git

git clone

使用 git clone 拷貝一個 Git 倉庫到本地,讓自己能夠檢視該專案,或者進行修改。 
如果你需要與他人合作一個專案,或者想要複製一個專案,看看程式碼,你就可以克隆那個專案。 執行命令:

$ git clone [url]

[url] 為你想要複製的專案git地址,就可以了。 
例如我們克隆 Github 上的專案:

$ git clone https://www.github.com/onlynight/Proxy.git
Cloning into 'Proxy'...
remote: Counting objects: 50, done.
remote: Compressing objects: 100% (28/28), done.
remote: Total 50 (delta 13), reused 47 (delta 10), pack-reused 0
Unpacking objects: 100% (50/50), done.
Checking connectivity... done.

克隆完成後,在當前目錄下會生成一個 simplegit 目錄:

$ cd Proxy/
$ ls -a
.  ..  .git  .idea  Proxy.iml  README.md  images  src

預設情況下,Git 會按照你提供的 URL 所指示的專案的名稱建立你的本地專案目錄。 通常就是該 URL 最後一個 / 之後的專案名稱。如果你想要一個不一樣的名字, 你可以在該命令後加上你想要的名稱。

基本快照

Git 的工作就是建立和儲存你的專案的快照及與之後的快照進行對比。本章將對有關建立與提交你的專案的快照的命令作介紹。

新增檔案到快取 git add

git add 命令可將該檔案新增到快取,如我們新增以下兩個檔案:

$ touch README.md
$ touch HelloWorld.java
$ ls
HelloWorld.java  README.md
$ git status -s
?? HelloWorld.java
?? README.md

git status 命令用於檢視專案的當前狀態。 
接下來我們執行 git add 命令來新增檔案:

$ git add README.md HelloWorld.java

現在我們再執行 git status,就可以看到這兩個檔案已經加上去了。

$ git status -s
A  HelloWorld.java
A  README.md

新專案中,新增所有檔案很普遍,我們可以使用 git add . 命令來添加當前專案的所有檔案。 
現在我們修改 README 檔案:

$ vim README
#README.md
This is readme markdown file.
$ git status -s
A  HelloWorld.java
AM README.md

“AM” 狀態的意思是,這個檔案在我們將它新增到快取之後又有改動。改動後我們在執行 git add 命令將其新增到快取中:

$ git add .
$ git status -s
A  HelloWorld.java
A  README.md

當你要將你的修改包含在即將提交的快照裡的時候,需要執行 git add。

檢視狀態 git status

git status 以檢視在你上次提交之後是否有修改。 
我演示該命令的時候加了 -s 引數,以獲得簡短的結果輸出。如果沒加該引數會詳細輸出內容:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   HelloWorld.java
        new file:   README.md

對比改動 git diff

執行 git diff 來檢視執行 git status 的結果的詳細資訊。 
git diff 命令顯示已寫入快取與已修改但尚未寫入快取的改動的區別。git diff 有兩個主要的應用場景。

  • 尚未快取的改動:git diff
  • 檢視已快取的改動: git diff –cached
  • 檢視已快取的與未快取的所有改動:git diff HEAD
  • 顯示摘要而非整個 diff:git diff –stat

在 HelloWorld.java 檔案中輸入以下內容:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

}
$ git status -s
AM HelloWorld.java
A  README.md
$ git diff
diff --git a/HelloWorld.java b/HelloWorld.java
index e69de29..68271e5 100644
--- a/HelloWorld.java
+++ b/HelloWorld.java
@@ -0,0 +1,7 @@
+public class HelloWorld {
+
+       public static void main(String[] args) {
+               System.out.println("Hello World!");
+       }
+
+}

git status 顯示你上次提交更新後的更改或者寫入快取的改動, 而 git diff 一行一行地顯示這些改動具體是啥。 
接下來我們來檢視下 git diff –cached 的執行效果:

$ git add HelloWorld.java
$ git status -s
A  HelloWorld.java
A  README.md
$ git diff --cached
diff --git a/HelloWorld.java b/HelloWorld.java
new file mode 100644
index 0000000..68271e5
--- /dev/null
+++ b/HelloWorld.java
@@ -0,0 +1,7 @@
+public class HelloWorld {
+
+       public static void main(String[] args) {
+               System.out.println("Hello World!");
+       }
+
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8123762
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+#README.md
+
+This is readme markdown file.

提交程式碼到本地倉庫 git commit

使用 git add 命令將想要快照的內容寫入快取區, 而執行 git commit 將快取區內容新增到倉庫中。 
Git 為你的每一個提交都記錄你的名字與電子郵箱地址,所以第一步需要配置使用者名稱和郵箱地址。

$ git config --golbal user.name 'wyndam'
$ git config --golbal user.email '[email protected]'

接下來我們寫入快取,並提交對 hello.php 的所有改動。在首個例子中,我們使用 -m 選項以在命令列中提供提交註釋。

$ git add README.md
$ git add HelloWorld.java
$ git status -s
A  HelloWorld.java
A  README.md
$ git commit -m 'inital commit'
[master (root-commit) fdd5c53] inital commit
 2 files changed, 10 insertions(+)
 create mode 100644 HelloWorld.java
 create mode 100644 README.md

現在我們已經記錄了快照。如果我們再執行 git status:

$ git status
On branch master
nothing to commit, working directory clean

以上輸出說明我們在最近一次提交之後,沒有做任何改動,是一個”working directory clean:乾淨的工作目錄”。 
如果你沒有設定 -m 選項,Git 會嘗試為你開啟一個編輯器以填寫提交資訊。 如果 Git 在你對它的配置中找不到相關資訊,預設會開啟 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
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   HelloWorld.java
#
~
~
".git/COMMIT_EDITMSG" 9L, 257C

如果你覺得 git add 提交快取的流程太過繁瑣,Git 也允許你用 -a 選項跳過這一步。命令格式如下:

$ git commit -a

我們先修改 HelloWorld.java 檔案為以下內容:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!!!");
    }

}

再執行以下命令:

$ git commit -am "修改HelloWorld.java檔案"
[master c2c167c] 修改HelloWorld.java檔案
 1 file changed, 1 insertion(+), 1 deletion(-)

從快取中移除檔案 git reset HEAD

git reset HEAD 命令用於取消已快取的內容。 
我們先改動檔案 README 檔案,內容如下:

#README.md

##This is readme markdown file

HelloWorld.java 檔案修改為:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

}

現在兩個檔案修改後,都提交到了快取區,我們現在要取消其中一個的快取,操作如下:

$ git status -s
 M HelloWorld.java
 M README.md
$ git add .
$ git status -s
M  HelloWorld.java
M  README.md
$ git reset HEAD -- HelloWorld.java
Unstaged changes after reset:
M       HelloWorld.java
$ git status -s
 M HelloWorld.java
M  README.md

現在你執行 git commit,只會將 README.md 檔案的改動提交,而 HelloWorld.java 是沒有的。

$ git commit -m "修改"
[master ad5f6fe] 修改
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git status -s
 M HelloWorld.java

可以看到 HelloWorld.java 檔案的修改併為提交。 
這時我們可以使用以下命令將 HelloWorld.java 的修改提交:

$ git commit -am "修改 HelloWorld.java 檔案"
[master a055c08] 修改 HelloWorld.java 檔案
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git status
On branch master
nothing to commit, working directory clean

簡而言之,執行 git reset HEAD 以取消之前 git add 新增,但不希望包含在下一提交快照中的快取。

從快取以及工作目錄刪除檔案 git rm

git rm 會將條目從快取區中移除。這與 git reset HEAD 將條目取消快取是有區別的。 “取消快取”的意思就是將快取區恢復為我們做出修改之前的樣子。 
預設情況下,git rm file 會將檔案從快取區和你的硬碟中(工作目錄)刪除。 
如果你要在工作目錄中留著該檔案,可以使用 git rm –cached: 
如我們刪除 hello.php檔案:

$ git rm HelloWorld.java
rm 'HelloWorld.java'
$ ls
README.md

不從工作區中刪除檔案:

$ git rm README.md --cached
rm 'README.md'
$ ls
README.md

修改快取中檔名 git mv

git mv 命令做得所有事情就是 git rm –cached 命令的操作, 重新命名磁碟上的檔案,然後再執行 git add 把新檔案新增到快取區。 
我們先把剛移除的 README 添加回來:

$ git add README.md

然後對其重名:

$ git mv README.md README
$ ls
README

Git分支管理

幾乎每一種版本控制系統都以某種形式支援分支。使用分支意味著你可以從開發主線上分離開來,然後在不影響主線的同時繼續工作。 
有人把 Git 的分支模型稱為”必殺技特性”,而正是因為它,將 Git 從版本控制系統家族裡區分出來。 
建立分支命令:

git branch [branch name]

切換分支命令:

git checkout [branch name]

當你切換分支的時候,Git 會用該分支的最後提交的快照替換你的工作目錄的內容, 所以多個分支不需要多個目錄。 
合併分支命令:

git merge

你可以多次合併到統一分支, 也可以選擇在合併之後直接刪除被併入的分支。

Git分支管理

列出分支 git branch

列出分支基本命令:

git branch

沒有引數時,git branch 會列出你在本地的分支。

$ git branch
* master

此例的意思就是,我們有一個叫做”master”的分支,並且該分支是當前分支。 
當你執行 git init 的時候,預設情況下 Git 就會為你建立”master”分支。 
如果我們要手動建立一個分支,並切換過去。執行 git branch (branchname) 即可。

$ git branch testing
$ git branch
* master
  testing

現在我們可以看到,有了一個新分支 testing。 
當你以此方式在上次提交更新之後建立了新分支,如果後來又有更新提交, 然後又切換到了”testing”分支,Git 將還原你的工作目錄到你建立分支時候的樣子 
接下來我們將演示如何切換分支,我們用 git checkout (branch) 切換到我們要修改的分支。

$ ls
README
$ echo 'w3cschool.cc' > test.txt
$ git add .
$ git commit -m 'add test.txt'
[master 048598f] add test.txt
 2 files changed, 1 insertion(+), 3 deletions(-)
 delete mode 100644 hello.php
 create mode 100644 test.txt
$ ls
README      test.txt
$ git checkout testing
Switched to branch 'testing'
$ ls
README.md       HelloWorld.java

當我們切換到”testing”分支的時候,我們新增的新檔案test.txt被移除了, 原來被刪除的檔案hello.php檔案又出現了。切換回”master”分支的時候,它們有重新出現了。

$ git checkout master
Switched to branch 'master'
$ ls
README      test.txt

首先我們在master分支中在新增一個新檔案test2.txt:

$ touch test2.txt
$ git add test2.txt
$ git commit -m 'add test2.txt'
$ ls
README  test.txt  test2.txt

我們也可以使用 git checkout -b (branchname) 命令來建立新分支並立即切換到該分支下,從而在該分支中操作。

$ git checkout -b newtest
Switched to a new branch 'newtest'
$ git rm test2.txt 
rm 'test2.txt'
$ ls
README      test.txt
$ git commit -am 'removed test2.txt'
[newtest 556f0a0] removed test2.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test2.txt
$ git checkout master
Switched to branch 'master'
$ ls
README      test.txt    test2.txt

如你所見,我們建立了一個分支,在該分支的上下文中移除了一些檔案,然後切換回我們的主分支,那些檔案又回來了。 
使用分支將工作切分開來,從而讓我們能夠在不同上下文中做事,並來回切換。

刪除分支 git branch -d

刪除分支命令:

git branch -d [branch name]

例如我們要刪除”testing”分支:

$ git branch
* master
  newtest
  testing
$ git branch -D testing
Deleted branch testing (was 84b13b9).
$ git branch
* master
  newtest

分支合併 git merge

一旦某分支有了獨立內容,你終究會希望將它合併回到你的主分支。 你可以使用以下命令將任何分支合併到當前分支中去:

git merge
$ git branch
* master
  newtest
$ ls
README      test.txt    test2.txt
$ git merge newtest
Updating a055c08..202199d
Fast-forward
 HelloWorld.java     | 7 -------
 README.md => README | 0
 test.txt            | 1 +
 3 files changed, 1 insertion(+), 7 deletions(-)
 delete mode 100644 HelloWorld.java
 rename README.md => README (100%)
 create mode 100644 test.txt
$ ls
README  test.txt

以上例項中我們將 newtest 分支合併到主分支去,test2.txt 檔案被刪除。

合併衝突

合併並不僅僅是簡單的檔案新增、移除的操作,Git 也會合並修改。

$ git branch
* master
  newtest
$ cat test.txt
w3cschool.cc

首先,我們建立一個叫做”change_site”的分支,切換過去,我們將內容改為 www.w3cschool.cc 。

$ git checkout -b change_site
Switched to a new branch 'change_site'
$ vim test.txt 
$ head -1 test.txt 
www.w3cschool.cc
$ git commit -am 'changed the site'
[change_site d7e7346] changed the site
 1 file changed, 1 insertion(+), 1 deletion(-)

將修改的內容提交到 “change_site” 分支中。 現在,假如切換回 “master” 分支我們可以看內容恢復到我們修改前的,我們再次修改test.txt檔案。

$ git checkout master
Switched to branch 'master'
$ head -1 test.txt 
w3cschool.cc
$ vim test.txt 
$ cat test.txt
w3cschool.cc
新增加一行
$ git diff
diff --git a/test.txt b/test.txt
index 704cce7..f84c2a4 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
 w3cschool.cc
+新增加一行
$ git commit -am '新增加一行'
[master 14b4dca] 新增加一行
 1 file changed, 1 insertion(+)

現在這些改變已經記錄到我的 “master” 分支了。接下來我們將 “change_site” 分支合併過來。

$ git merge change_site
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
$ cat test.txt 
<<<<<<< HEAD
w3cschool.cc
新增加一行
=======
www.w3cschool.cc
>>>>>>> change_site

我們將前一個分支合併到 “master” 分支,一個合併衝突就出現了,接下來我們需要手動去修改它。

$ vim test.txt 
$ cat test.txt 
www.w3cschool.cc
新增加一行
$ git diff
diff --cc test.txt
index f84c2a4,bccb7c2..0000000
--- a/test.txt
+++ b/test.txt
@@@ -1,2 -1,1 +1,2 @@@
- w3cschool.cc
+ www.w3cschool.cc
 +新增加一行

在 Git 中,我們可以用 git add 要告訴 Git 檔案衝突已經解決

$ git status -s
UU test.txt
$ git add test.txt 
$ git status -s
M  test.txt
$ git commit
[master 88afe0e] Merge branch 'change_site'

Git 檢視提交歷史 git log

在使用 Git 提交了若干更新之後,又或者克隆了某個專案,想回顧下提交歷史,我們可以使用 git log 命令檢視。 
針對我們前一章節的操作,使用 git log 命令列出歷史提交記錄如下:

$ git log
commit 2b5970dc2a936649791afc8cedb6dbaee46d2176
Merge: e2714c9 d17a0a0
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 17:00:57 2016 +0800

    Merge branch 'change_site'

commit e2714c9ecf376efefc8d149ac219a6e98c80790b
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 16:58:09 2016 +0800

    新增加一行

commit d17a0a0065e1e1d1c1078cfabf18f2c8491f0b7c
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 16:54:13 2016 +0800

    change the site

commit 202199d023f307e74229e46ee90fc351d2e6d4f6
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:50:55 2016 +0800

    add test.txt file

commit a055c0816bc94a9abe21ffe4a4014851943ea139
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:35:50 2016 +0800

    修改 HelloWorld.java 檔案

commit ad5f6fe0474c52c464e94cd41faf45e705445847
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:34:16 2016 +0800

    修改

commit c2c167c36533768be8fc91e4cb3ba0b7d328a074
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:24:41 2016 +0800

    修改HelloWorld.java檔案

commit f9393bf0e7f701248b56c97827a9d101e74b3952
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:21:02 2016 +0800

    third commit
    ``

commit 316fafcf38bb2eb600f4226345ea09a4e37d9ec4
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:18:58 2016 +0800

    second commit

commit fdd5c53457270c10a163a0cf3fcfd9027e6e1ecb
Author: Wyndam <[email protected]>
Date:   Thu Oct 20 15:10:43 2016 +0800

    inital commit

我們可以用 –oneline 選項來檢視歷史記錄的簡潔的版本。

$ git log --oneline
2b5970d Merge branch 'change_site'
e2714c9 新增加一行
d17a0a0 change the site
202199d add test.txt file
a055c08 修改 HelloWorld.java 檔案
ad5f6fe 修改
c2c167c 修改HelloWorld.java檔案
f9393bf third commit ``
316fafc second commit
fdd5c53 inital commit

這告訴我們的是,此專案的開發歷史。 
我們還可以用 –graph 選項,檢視歷史中什麼時候出現了分支、合併。以下為相同的命令,開啟了拓撲圖選項:

$ git log --oneline --graph
*   2b5970d Merge branch 'change_site'
|\
| * d17a0a0 change the site
* | e2714c9 新增加一行
|/
* 202199d add test.txt file
* a055c08 修改 HelloWorld.java 檔案
* ad5f6fe 修改
* c2c167c 修改HelloWorld.java檔案
* f9393bf third commit ``
* 316fafc second commit
* fdd5c53 inital commit

現在我們可以更清楚明瞭地看到何時工作分叉、又何時歸併。 
你也可以用 ‘–reverse’引數來逆向顯示所有日誌。

$ git log --oneline --reverse
fdd5c53 inital commit
316fafc second commit
f9393bf third commit ``
c2c167c 修改HelloWorld.java檔案
ad5f6fe 修改
a055c08 修改 HelloWorld.java 檔案
202199d add test.txt file
d17a0a0 change the site
e2714c9 新增加一行
2b5970d Merge branch 'change_site'

如果只想查詢指定使用者的提交日誌可以使用命令:git log –author , 例如,比方說我們要找 Git 原始碼中 Linus 提交的部分:

$ git log --author=Linus --oneline -5
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
3bb7256 make "index-pack" a built-in
377d027 make "git pack-redundant" a built-in
b532581 make "git unpack-file" a built-in
112dd51 make "mktag" a built-in

如果你要指定日期,可以執行幾個選項:–since 和 –before,但是你也可以用 –until 和 –after。 
例如,如果我要看 Git 專案中三週前且在四月十八日之後的所有提交,我可以執行這個(我還用了 –no-merges 選項以隱藏合併提交):

$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
5469e2d Git 1.7.1-rc2
d43427d Documentation/remote-helpers: Fix typos and improve language
272a36b Fixup: Second argument may be any arbitrary string
b6c8d2d Documentation/remote-helpers: Add invocation section
5ce4f4e Documentation/urls: Rewrite to accomodate transport::address
00b84e9 Documentation/remote-helpers: Rewrite description
03aa87e Documentation: Describe other situations where -z affects git diff
77bc694 rebase-interactive: silence warning when no commits rewritten
636db2c t3301: add tests to use --format="%N"

Git 標籤 git tag

如果你達到一個重要的階段,並希望永遠記住那個特別的提交快照,你可以使用 git tag 給它打上標籤。 
比如說,我們想為我們的 w3cschoolcc 專案釋出一個”1.0”版本。 我們可以用 git tag -a v1.0 命令給最新一次提交打上(HEAD)”v1.0”的標籤。 
-a 選項意為”建立一個帶註解的標籤”。 不用 -a 選項也可以執行的,但它不會記錄這標籤是啥時候打的,誰打的,也不會讓你添加個標籤的註解。 我推薦一直建立帶註解的標籤。

$ git tag -a v1.0

當你執行 git tag -a 命令時,Git 會開啟你的編輯器,讓你寫一句標籤註解,就像你給提交寫註解一樣。 
現在,注意當我們執行 git log –decorate 時,我們可以看到我們的標籤了:

$ git log --oneline --graph --decorate
*   2b5970d (HEAD -> master, tag: v1.0) Merge branch 'change_site'
|\
| * d17a0a0 (change_site) change the site
* | e2714c9 新增加一行
|/
* 202199d (newtest) add test.txt file
* a055c08 修改 HelloWorld.java 檔案
* ad5f6fe 修改
* c2c167c 修改HelloWorld.java檔案
* f9393bf third commit ``
* 316fafc second commit
* fdd5c53 inital commit

如果我們忘了給某個提交打標籤,又將它釋出了,我們可以給它追加標籤。 
例如,假設我們釋出了提交 85fc7e7(上面例項最後一行),但是那時候忘了給它打標籤。 我們現在也可以:

$ git tag -a v0.9 a055c08
$ git log --oneline --graph --decorate
*   2b5970d (HEAD -> master, tag: v1.0) Merge branch 'change_site'
|\
| * d17a0a0 (change_site) change the site
* | e2714c9 新增加一行
|/
* 202199d (newtest) add test.txt file
* a055c08 (tag: v0.9) 修改 HelloWorld.java 檔案
* ad5f6fe 修改
* c2c167c 修改HelloWorld.java檔案
* f9393bf third commit ``
* 316fafc second commit
* fdd5c53 inital commit

如果我們要檢視所有標籤可以使用以下命令:

$ git tag
v0.9
v1.0

指定標籤資訊命令:

git tag -a <tagname> -m "w3cschool.cc標籤"

PGP簽名標籤命令:

git tag -s <tagname> -m "w3cschool.cc標籤"

Git 遠端倉庫

Git 並不像 SVN 那樣有個中心伺服器。 
目前我們使用到的 Git 命令都是在本地執行,如果你想通過 Git 分享你的程式碼或者與其他開發人員合作。 你就需要將資料放到一臺其他開發人員能夠連線的伺服器上。

新增遠端庫 git remote add

要新增一個新的遠端倉庫,可以指定一個簡單的名字,以便將來引用,命令格式如下:

git remote add [shortname] [url]

本例以Github為例作為遠端倉庫,如果你沒有Github可以在官網https://github.com/註冊。 
由於你的本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密的,所以我們需要配置驗證資訊: 
使用以下命令生成SSH Key:

$ ssh-keygen -t rsa -C "[email protected]"

後面的[email protected]改為你在github上註冊的郵箱,之後會要求確認路徑和輸入密碼,我們這使用預設的一路回車就行。成功的話會在~/下生成.ssh資料夾,進去,開啟id_rsa.pub,複製裡面的key。 
回到github上,進入 Account Settings(賬戶配置),左邊選擇SSH Keys,Add SSH Key,title隨便填,貼上在你電腦上生成的key。

Github SSH設定

為了驗證是否成功,輸入以下命令:

$ ssh -T [email protected]
Hi onlynight! You've successfully authenticated, but GitHub does not provide shell access.

輸出以上結果證明已經正確配置金鑰。

之後登入後點擊” New repository ” 如下圖所示:

新建遠端倉庫1

之後在在Repository name 填入 GitAdd(遠端倉庫名) ,description中填寫描述”git add test”,其他保持預設設定,點選”Create repository”按鈕,就成功地建立了一個新的Git倉庫:

新建遠端倉庫2

建立成功後,顯示如下資訊:

新建遠端倉庫完成

以上資訊告訴我們可以從這個倉庫克隆出新的倉庫,也可以把本地倉庫的內容推送到GitHub倉庫。 
現在,我們根據GitHub的提示,在本地的倉庫下執行命令:

$ ls
README  test.txt
$ git remote add origin [email protected]:onlynight/GitAdd.git
$ git push -u origin master
Counting objects: 26, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (26/26), 2.44 KiB | 0 bytes/s, done.
Total 26 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), done.
To [email protected]:onlynight/GitAdd.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

檢視當前的遠端庫 git remote

要檢視當前配置有哪些遠端倉庫,可以用命令:

git remote
$ git remote
origin
$ git remote -v

執行時加上 -v 引數,你還可以看到每個別名的實際連結地址。

提取遠端倉庫

Git 有兩個命令用來提取遠端倉庫的更新。

1. 從遠端倉庫下載新分支與資料: git fetch

git fetch

該命令執行完後需要執行git merge 遠端分支到你所在的分支。

2. 從遠端倉庫提取資料並嘗試合併到當前分支: git pull

git pull

該命令就是在執行 git fetch 之後緊接著執行 git merge 遠端分支到你所在的任意分支。 
假設你配置好了一個遠端倉庫,並且你想要提取更新的資料,你可以首先執行 git fetch [alias] 告訴 Git 去獲取它有你沒有的資料,然後你可以執行 git merge [alias]/[branch] 以將伺服器上的任何更新(假設有人這時候推送到伺服器了)合併到你的當前分支。

接下來我們在 Github 上點選”test.txt” 並在線修改它。之後我們在本地更新修改。

$ git fetch origin
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:onlynight/GitAdd
   774112b..37be49b  master     -> origin/master

以上資訊”774112b..37be49b master -> origin/master” 說明 master 分支已被更新,我們可以使用以下命令將更新同步到本地:

$ git merge origin/master
Updating 774112b..37be49b
Fast-forward
 test.txt | 1 +
 1 file changed, 1 insertion(+)

推送到遠端倉庫 git push

推送你的新分支與資料到某個遠端倉庫命令:

git push [alias] [branch]

以上命令將你的 [branch] 分支推送成為 [alias] 遠端倉庫上的 [branch] 分支,例項如下。

$ git push origin master
Everything up-to-date

刪除遠端分支 git push :

注意:如果要刪除遠端分支同樣也是使用push命令,在分支前加上”:”表示刪除遠端分支,程式碼如下:

$ git push origin :<branch name>

刪除本地倉庫的遠端倉庫連結 git remote rm

刪除遠端倉庫你可以使用命令:

git remote rm [alias]
$ git remote -v
origin  [email protected]:onlynight/GitAdd.git (fetch)
origin  [email protected]:onlynight/GitAdd.git (push)
$ git remote -v
origin  [email protected]:onlynight/GitAdd.git (fetch)
origin  [email protected]:onlynight/GitAdd.git (push)
origin2 [email protected]:onlnynight/GitAdd.git (fetch)
origin2 [email protected]:onlnynight/GitAdd.git (push)
$ git remote rm origin2
$ git remote -v
origin  [email protected]:onlynight/GitAdd.git (fetch)
origin  [email protected]:onlynight/GitAdd.git (push)