其實Git比你覺得的更簡單 -- 實踐篇

git

前言

做爲一個程序猿👨‍💻‍,git能夠說一個必備的技能;可是大部分對git的認識仍是停留在那幾個基本命令,或者是使用圖形工具完成平常操做(不得不說IDE自帶的git用起來真爽),因此這片文章但願能讓你們對git有一個更加全面的認識。html

文章中例子所使用的git版本爲2.18.0,不一樣版本之間的命令效果可能會有不一樣git

本文涉及到的全部命令速查表github

告訴git你是誰

一般在安裝完成以後,git會讓咱們配置兩個基礎的信息:web

git congfig user.name "xxxx" --global
git config user.email "xxx@xx.com" -global
複製代碼

以上這兩行命令就是在全局配置用戶名和用戶郵箱,用於後續對倉庫提交時帶上備註信息,跟蹤是誰作的修改和提交shell

在git中,配置文件用三個做用域local, global, system; system做用域做用於當前電腦的全部用戶,global做用於當前用戶,而local只對某一個倉庫起做用。因此local相對於其餘兩個做用域來講比較特殊,由於它是針對某一個倉庫起做用,因此要求運行這個命令時必須在一個倉庫的路徑下,不然會出相似於fatal: --local can only be used inside a git repository的錯誤,而global和system則沒有這個限制。vim

查看不一樣做用域配置項命令:安全

git config --list --local
git config --list --global
git config --list --system
複製代碼

既然配置文件有不一樣的做用域,那麼不一樣的做用域確定也有優先級的區別;在git中的優先級順序是:local > global > system;這就意味着若是我在global範圍設置了user.name爲」global name「,而且同時在某一個倉庫的local範圍設置user.name爲」local name「, 那麼以後的提交操做中,user.name會使用」local name「。bash

跑通基本流程

在配置完本身的信息後,就開始進行實際的git相關的操做app

初始化倉庫

要想使用git的相關命令,就必須在一個git倉庫中,因此第一步首先要初始化一個git倉庫,通常包括兩種方式:webstorm

  1. 在已存在的項目中新建git倉庫
cd <project-path>
▶ git init

Initialized empty Git repository in /xx/xx/.git/
複製代碼
  1. 新建一個項目而且同時添加git倉庫
▶ git init <project-path>

Initialized empty Git repository in /xx/xx/.git/
複製代碼

文件狀態

在git中,文件的狀態大體能夠分爲四種:

  • Untraked: 未跟蹤的文件(git只記錄tracked文件的修改)
  • Unmodified: 未修改的文件,指已經被git跟蹤,可是相對於上一次提交沒有修改的文件
  • Modified: 已修改的文件,指已經被git跟蹤,可是相對於上一次提交有修改的文件
  • Staged: 已被git存儲的文件

下圖是項目文件在git中基本的狀態的lifecycle,結合下文的內容食用更佳。

lifecycle

在上文已經初始化了git倉庫,在此時能夠運行git status命令查看倉庫狀態

▶ git status

On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
複製代碼

此時的倉庫並無提交(commit),而且它提醒咱們可使用git add命令來跟蹤文件,咱們在項目中新建一個readme.txt文件,在看看倉庫的狀態:

▶ touch readme.txt
▶ git status

On branch master
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
  
        readme.txt
    
nothing added to commit but untracked files present (use "git add" to track)
複製代碼

這個此時的readme.txt文件就是Untracked狀態,此時可使用git add readme.txt命令將文件加入到暫存區(這個概念待會解釋),而後在看看倉庫的狀態:

▶ git add readme.txt
▶ git status

On branch master
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   readme.txt
        
複製代碼

下一步,使用git commit -m "<message>"將本次的修改提交到本地倉庫:

▶ git commit -m "create readme.txt"

[master (root-commit) 40cb86b] create readme.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 readme.txt


▶ git status

On branch master
nothing to commit, working tree clean
複製代碼

此時的readme.txt文件就是Staged狀態,其中的40cb86b這個字符串就是本次提交的id(每次提交的id都是惟一的)。而且因爲工做區的readme.txt文件與本次提交相比並無作出新的修改,因此也是Unmodified狀態,若是此時在readme.txt文件中更改了內容,而且沒有進行git addgit commit操做,那麼readme.txt將會變成Modified狀態:

echo "hello git" > readme.txt
▶ git status

On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

複製代碼

此時,能夠在重複以前的git addgit commit命令來提交新的修改。

既然git保存了修改的記錄,天然也能夠查看記錄,經過git log命令查看提交了那些修改:

▶ git log

commit 832b59c98986a04cb8008f1eb39333504729dc45 (HEAD -> master)
Author: wenjun <wjxu@mail.com>
Date:   Wed Sep 18 00:00:51 2019 +0800

    add new line in readme.txt

commit 40cb86b7830e0606897d0f792f1a332fe74f5037
Author: wenjun <wjxu@mail.com>
Date:   Tue Sep 17 23:44:29 2019 +0800

    create readme.txt
複製代碼

git log命令將提交的id,提交者和提交時間等信息都通通打印了出來。

到此爲止介紹的就是git內文件狀態的轉換流程,以及git statusgit addgit commitgit log命令的最基礎的使用。

三個區域

在前文中提到了暫存區,工做區等名詞,本節就來說講git中這幾個重要的概念。在git中,有三個區域:工做區,暫存區和倉庫。工做區就是項目所在的目錄區域(你能夠在項目工程中看到區域),而倉庫就是存儲全部提交的區域,暫存區算是工做區和倉庫以前的過渡區域,能夠簡單的當作是用來存儲須要提交的文件修改的區域。

three stage

結合上圖,以及前一節已經提到了的內容,git add命令會將所作的修改提交到暫存區,而後git commit命令會將修改提交到倉庫中,此時的暫存區就是乾淨的(能夠暫時認爲暫存區被清空,後面會具體說說暫存區的狀況);而且若是此時工做區沒有更新,那麼工做區就是乾淨的(nothing to commit, working tree clean)。

並非每個修改都必須是git add而後在git commit,還能夠屢次修改,而後使用屢次git add命令,最後在使用git commit命令一次提交全部修改。

首先,咱們在readme.txt文件中再修改一些內容,而且使用git add放入暫存區;在新建一個chapter1.txt文件,再使用git add放入暫存區;最後使用git commit命令提交兩個修改。來看看會發生什麼?

▶ git status

On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git add readme.txt
▶ git status

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

        modified:   readme.txt

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

        chapter1.txt


▶ git add chapter1.txt
▶ git status

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

        new file:   chapter1.txt
        modified:   readme.txt


▶ git commit -m "modify readme.txt & create chapter1.txt"

[master 640029f] modify readme.txt & create chapter1.txt
 2 files changed, 1 insertion(+)
 create mode 100644 chapter1.txt

 
▶ git status
 
On branch master
nothing to commit, working tree clean
複製代碼

在修該了readme.txt後,git會提示你readme.txt已經有改動,能夠提交到暫存區;而後新建chapter1.txt文件後,git會提示readme.txt以及在提交到暫存區中,可是此時chapter1.txt還未被git跟蹤,再使用git add命令後,此時git會提醒暫存區有兩個修改。當把兩個修改commit後,工做區就是乾淨的。

這個就是git三個區域的基本的變更過程。可能有些人會問:爲何要有暫存區的存在呢?爲何不能直接從工做區提交到倉庫,這樣不是更簡單方便嗎?其實暫存區看似使得git的結構更復雜,可是正是因爲暫存區的存在,使得咱們對修改的保存更加靈活。舉個例子,一般狀況下咱們但願每個提交都是單純的,只作一件事,這樣在code review或者版本回退的時候可以更清晰;可是可能有使用寫代碼進入了一個很高效專一的狀態,一會兒完成了function A, function B(假設兩個功能沒有交集),此時咱們能夠先將function A的代碼加入暫存區而且提交,而後在提交function B。若是沒有暫存區,要麼就是不提交,要麼就是全提交,可能就比較難實現這種狀況。

學習更多的命令

經過以前的內容,大概把git基礎的流程過了一遍,也講了一些基本的命令;本節繼續深化對git的更多的流程和經常使用命令(太偏的我也不會)的認識。

提交修改

git add

以前使用git add命令時,都是一次add一個文件。若是須要多個文件可使用:

  • git add -u
  • git add --all或者git add .

git add -u只提交全部已跟蹤過的文件的修改。好比咱們在readme.txtchapter1.txt同時修改內容,而且再新建一個chapter2.txt;此時使用git add -u只會提交readme.txtchapter1.txt的修改到暫存區

▶ git status

On branch 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:   chapter1.txt
        modified:   readme.txt

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

        chapter2.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git add -u
▶ git status

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

        modified:   chapter1.txt
        modified:   readme.txt

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

        chapter2.txt
        
複製代碼

git add --allgit add .兩個命令是等價的,會把全部的修改都提交,無論這個文件有沒有被git所跟蹤。仍是以上面的例子爲參照

▶ git status

On branch 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:   chapter1.txt
        modified:   readme.txt

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

        chapter2.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git add .
▶ git status

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

        modified:   chapter1.txt
        new file:   chapter2.txt
        modified:   readme.txt
        
複製代碼

若是在同一個文件中改動了多個區域,可是又想分別提交,可使用git add -p更細緻話的控制(該命令也會進入一個vim操做界面)。咱們在readme.txt增長兩行內容,而且分兩次提交兩行內容

# 此時的readme.txt多了兩行改動
▶ cat readme.txt

hello git
get further in git

use git commit --amend

-----------------------------
this is first line

-----------------------------
this is second line

# 交互式提交修改,首先會打印出readme.txt的修改內容
▶ git add -p

diff --git a/readme.txt b/readme.txt
index 84790cd..cf524cc 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,4 +1,10 @@
 hello git
 get further in git

-use git commit --amend
\ No newline at end of file
+use git commit --amend
+
+-----------------------------
+this is first line
+
+-----------------------------
+this is second line
\ No newline at end of file
# 使用不一樣的命令,進行不一樣操做;選擇?能夠查看各個命令的說明
Stage this hunk [y,n,q,a,d,e,?]? e

# 進入vim界面,最下面會有解釋如何操做修改,此時咱們只需提交第一行內容,就直接將first line下面的內容刪除保存便可
Manual hunk edit mode -- see bottom for a quick guide.
@@ -1,4 +1,10 @@
 hello git
 get further in git

-use git commit --amend
\ No newline at end of file
+use git commit --amend
+
+-----------------------------
+this is first line
+
+-----------------------------
+this is second line
\ No newline at end of file
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging.
# If it does not apply cleanly, you will be given an opportunity to
# edit again. If all lines of the hunk are removed, then the edit is
# aborted and the hunk is left unchanged.

# 能夠看到readme.txt的一部分修改已經提交到了暫存區,接下來就正常的commit便可
▶ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   readme.txt

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:   readme.txt
複製代碼

git commit

以前已經介紹過git commit -m命令提交,還可使用命令合併add操做直接將工做區的修改提交到倉庫中git commit -a -m或者git commit -am,它至關於git add -ugit commit -m的結合,因此顯然它提交的修改的文件都是已經被git跟蹤。對於commit message的規範能夠參考阮一峯大佬的文章:Commit message 和 Change log 編寫指南

git commit --amend用於從新提交上一次commit,而且能夠加入新的修改。好比上一個提交中只包含了readme.txt的修改,忘了包含chapter1.txt的修改,能夠用這個命令修改上一次commit

▶ git status

On branch 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:   chapter1.txt
        modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git add readme.txt
▶ git commit --m "only commit readme.txt"

[master d5ffbec] only commit readme.txt
 1 file changed, 3 insertions(+), 1 deletion(-)


▶ git log --oneline
# 注意看此時的commit id
d5ffbec (HEAD -> master) only commit readme.txt
640029f modify readme.txt & create chapter1.txt
832b59c add new line in readme.txt
40cb86b create readme.txt


▶ git add .
▶ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   chapter1.txt


▶ git commit --amend
[master b15b67f] only commit readme.txt
 Date: Thu Sep 19 01:45:12 2019 +0800
 2 files changed, 4 insertions(+), 1 deletion(-)


▶ git log --oneline
# 雖然是對上一個提交的修改,可是此時的commit id和以前不同
cd52b05 (HEAD -> master) commit readme.txt & chapter1.txt
640029f modify readme.txt & create chapter1.txt
832b59c add new line in readme.txt
40cb86b create readme.txt

複製代碼

在使用git commit --amend時會進入一個vim的操做界面,在這個界面中第一行就是以前的commit message以及下方要被提交的文件信息。能夠修改新的commit message或者不改也行

only commit readme.txt

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Thu Sep 19 01:45:12 2019 +0800
#
# On branch master
# Changes to be committed:
# modified: chapter1.txt
# modified: readme.txt
#
~
複製代碼

若是你不須要修改上一次提交的commit message,能夠直接使用git commit --amend --no-edit能夠以前沿用以前的message,不須要進入vim界面。(其實若是咱們直接使用git commit不加-m也會進入vim界面讓你添加commit message

查看提交歷史

git diff

隨着咱們不斷的add,commit;三個區域的狀態都會不同,使用git diff命令便可像上面git add -p那樣打印出不一樣區域之間的區別。

git diff

  • git diff:用於查看工做區和暫存區以前的區別
  • git diff --cached:用於查看暫存區和上一個提交之間的區別
  • git diff HEAD:用於展現工做區和上一次提交之間的區別
  • git diff <commit-id> <commit-id>:用於展現兩個提交之間的區別
▶ git status
# 對readme.txt作出更改
On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git diff
# 加號開始的行表示新加的行,減號開始的行表示刪除的行
# 此時使用git diff HEAD效果一致 
diff --git a/readme.txt b/readme.txt
index cf524cc..267e34f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -7,4 +7,7 @@ use git commit --amend
 this is first line

 -----------------------------
-this is second line
\ No newline at end of file
+this is second line
+
+
+change again
\ No newline at end of file
(END)

# 此時查看暫存區和上一次提交併無任何修改
▶ git diff --cached

▶ git add .
▶ git diff --cached

# 此時暫存區和上一次的修改與以前一致
diff --git a/readme.txt b/readme.txt
index cf524cc..267e34f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -7,4 +7,7 @@ use git commit --amend
 this is first line

 -----------------------------
-this is second line
\ No newline at end of file
+this is second line
+
+
+change again
\ No newline at end of file
(END)
複製代碼

其實雖然用git diff能看出不一樣區域直接的區別,可是命令行的方式並非很直觀,這種時候仍是推薦使用圖形化的界面查看更加直觀。

git diff graph

git log

隨着不斷的提交修改,git倉庫中存儲着不少的提交記錄,git log命令就是用於查看提交歷史。

  • git log:用於查看全部的提交
  • git log -<number>:用於查看最近n次提交
  • git log -p:用於展現每次提交log以及每次的改動
  • git log --stat:用於展現每次提交log以及每次的改動的簡要統計
  • git log --oneline:用於展現一行簡略信息
  • git log --graph:用簡單圖形展現
▶ git log --oneline

c22c913efa87642532eccc264cfcb6b3318506f9 (HEAD -> master) commit the rest part
1cf3c61d3c1de7e6b4225c1b96f3e1a75313144d partial commit
a8b85b8054510688602bb3c7736205e539303d56 commit readme.txt & chapter1.txt
640029f6f64ced21f8588236217a788beae9ac44 modify readme.txt & create chapter1.txt
832b59c98986a04cb8008f1eb39333504729dc45 add new line in readme.txt
40cb86b7830e0606897d0f792f1a332fe74f5037 create readme.txt

複製代碼

固然仍是推薦使用圖形化界面操做

git log graph

git show

若是咱們想看某一次提交作了什麼,就輪到了git show上場了。

  • git show:用於展現上一個提交的修改
  • git show <commit-id>:用於展現特定提交的修改
  • git show --name-only <commit-id>:用於展現特定提交的修改的文件名
▶ git show --name-only  a8b85b8054510688602bb3c7736205e539303d56

commit a8b85b8054510688602bb3c7736205e539303d56
Author: wenjun <wjxu@thoughtworks.com>
Date:   Thu Sep 19 01:45:12 2019 +0800

    commit readme.txt & chapter1.txt

chapter1.txt
readme.txt
(END)
複製代碼

不用懷疑,這個仍是推薦用圖形界面查看

git show graph

文件刪除&安全重命名&忽略

git rm

之間的講解都是如何往git裏面添加文件,可是咱們並不老是在作加法,也須要減法。

  • git rm <file-name>:從工做區刪除文件,而且從倉庫中移除對某個文件的跟蹤(確切的說只是從暫存區移除,倉庫的提交歷史依舊會保留該文件
  • git rm --cached <file-name>:只移除對該文件的跟蹤,可是依舊在工做區保留文件
# git rm至關於 rm && git add
▶ git rm chapter1.txt

rm 'chapter1.txt'


▶ git status
# chapter1.txt從工做區刪除
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    chapter1.txt


# 先恢復chapter1.txt,試試另外一個命令
▶ git rm --cached chapter1.txt
rm 'chapter1.txt'

▶ git status
#能夠明顯看到這個以前命令的區別,它在暫存區刪除了對chapter1.txt的跟蹤,因此有一個刪除的修改(相對於上一次提交對比而言);此時工做區chapter1.txt顯示的狀態是未跟蹤
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    chapter1.txt

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

        chapter1.txt


複製代碼

git mv

在通常狀況下,重命名文件沒有什麼問題,git也能正確的推斷出你所作的修改修改

# 將chapter1.txt更名爲chapter12.txt
# 雖然在工做區顯示的是刪除了chapter1.txt,新建了chapter12.txt
▶ git status
On branch 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:    chapter1.txt

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

        chapter12.txt

no changes added to commit (use "git add" and/or "git commit -a")

#可是在提交到暫存區後,git仍是能正確的推薦是重命名操做
▶ git add .
▶ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    chapter1.txt -> chapter12.txt
複製代碼

若是咱們只是更換了文件名的大小寫,又是另外一種狀況:

# 將chapter1.txt更名爲CHAPTER1.txt
# git並無檢測到修改
▶ git status
On branch master
nothing to commit, working tree clean

# 在CHAPTER1.txt中修改內容,發現git仍是認爲這個chapter1.txt作出的修改
▶ git status
On branch 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:   chapter1.txt

no changes added to commit (use "git add" and/or "git commit -a")
複製代碼

出現這個狀況的緣由就在於git默認是不區分文件名大小寫的,因此對於這個狀況使用git mv <old-name> <new-name>就能保證獲得正確的結果

▶ git mv chapter1.txt CHAPTER1.txt
▶ git status

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

        renamed:    chapter1.txt -> CHAPTER1.txt
複製代碼

git mv <old-name> <new-name>至關於mv <old-name> <new-name>git rm --cached <old-name>git add <new-name>三條命令的結合

.gitignore

一個項目下並非全部的文件都須要使用git跟蹤,每每咱們真正須要追蹤的就是源代碼便可,並不須要跟蹤打包構建文件,也不但願它們老是顯示Untracked狀態。這時候能夠在項目的根目錄新建一個.gitignore文件來告訴git哪些文件不須要跟蹤。

.gitignore基本規則:

  • 全部空行或者#開頭的行都會被忽略
  • *表明0或多個任意字符
  • ?表明1個任意字符
  • [abc]匹配任何一個[]中的字符
  • /表明目錄
  • **任意多級中間目錄
  • !表明取反

.gitignore文件例子

# 別看了,這是註釋

# 忽略全部的.txt結尾的文件
*.txt

#可是index.txt例外
!1.txt

#僅忽略根目錄下的index.js文件,若是是sub/index.js則不忽略
/index.js

#忽略build目錄下全部文件
build/

#忽略src下面任意層級目錄中的index.js
src/**/index.js
複製代碼

有一個常見的場景就是一個被跟蹤的文件須要使用.gitignore來忽略。好比某次提交忘了.gitignore加入對.log的忽略,致使.log被git跟蹤,就算此時在.gitignore中加入這個規則,git依舊不會忽略.log的修改(簡而言之就是.gitignore中的規則對已經被git跟蹤的文件不起做用

因此此時須要首先移除git對該文件的的跟蹤,使用git rm --cached命令,而後提交修改。新的規則就能夠生效了。

git clean

  • git clean:用於刪除全部未被git跟蹤的文件,可是不包括.gitignore中忽略的文件
  • git clean -n:打印出將會刪除的文件名,但不會真正執行刪除操做
# 咱們先在項目準備兩個未被跟蹤的文件other.txt和index.txt;可是index.txt被.gitignore忽略
# 提示只會刪除other.txt
▶ git clean -n                      
Would remove other.txt
複製代碼

撤銷修改,代碼回滾

人非聖賢孰能無過,天然咱們也會犯錯。可是好在git給了咱們後悔的機會。

git checkout

如今,咱們在工做區改動了一些代碼,尚未git add推到暫存區中。可是忽然不想要工做區的改動了(就是這麼任性);使用git checkout命令能夠撤銷工做區的修改

  • git checkout <file-name>:撤銷某個文件
  • git checkout .:撤銷全部文件
  • git checkout <commit-id> <file-name>:恢復某個commit的指定文件到暫存區和工做區(無論你當前的工做區暫存區是否有更新,都會被強制恢復,因此謹慎使用
▶ git status

On branch 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:   chapter1.txt
        modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")


▶ git checkout chapter1.txt
▶ git status

On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
複製代碼

git checkout的功能還不僅這些,下文會繼續補充

git reset

若是咱們已經將工做區的一些更改推到的暫存區,咱們但願撤銷暫存區的修改(暫存區的修改會被回退到工做區),可使用git reset HEAD <file-name>

# 此時的改動已經推到了暫存區
▶ git stauts

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

        modified:   readme.txt


▶ git reset HEAD readme.txt 
Unstaged changes after reset:
M       readme.txt


# 改動被回退到了工做區
▶ git status                      
On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
複製代碼

這裏出現HEAD關鍵字(以前前文也出現了),它表明了倉庫當前的版本(不必定是最新版本哦);後文分支部分會詳細講解

除了能撤銷暫存區修改,還能夠回退版本,你還可使用該命令回到某一次的提交的狀態。 使用git reset <commit-id>,該命令有三個模式--soft--hard--mixed(默認模式)

  • --soft:只移動倉庫中HEAD指針的位置,工做區和暫存區的修改都不變
  • --mixed:移動HEAD指針的位置,並使用回退的到版本重置暫存區,工做區的修改保持不變
  • --hard:移動HEAD指針位置,並使用回退的到版本重置工做區和暫存區,保持與指定的提交一致

一般這三個模式直接的區別很容易讓人迷糊,可是其實他們的區別就是上面所說的那麼簡單

soft vs mixed vs hard

# 先看看當前有那些提交
▶ git log --oneline 

# 從`23bcc3e`到`93127f0`這三個提交就是分別在readme.txt新建一行
9c127f0 (HEAD -> master) add third line in readme.txt
ff29824 add second line in readme.txt
23bcc3e add first line in readme.txt
a84a18c add .gitignore

# 如今咱們想回到`23bcc3e`這個提交
# commit id 不須要所有打完,打出前幾位便可
▶ git reset --soft 23bcc3e  
▶ git log --oneline 
# 能夠看到當前的版本已經成功回到了`23bcc3e`
23bcc3e (HEAD -> master) add first line in readme.txt
a84a18c add .gitignore

# 因爲使用的是soft模式,只移動了HEAD指針,因此工做區和暫存區以前沒有改變,可是因爲HEAD指針的改變,致使了當前倉庫狀態和暫存區出現了差別
▶ git status

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

        modified:   readme.txt



# 此時用hard模式試試
▶ git reset --hard 9c127f0 

HEAD is now at 9c127f0 add third line in readme.txt

▶ git log --oneline 

# 倉庫狀態回到了最初的版本
9c127f0 (HEAD -> master) add third line in readme.txt
ff29824 add second line in readme.txt
23bcc3e add first line in readme.txt
a84a18c add .gitignore

# 而且由於hard模式會強制重置工做區和暫存區,使其和HEAD狀態保持一致,因此顯示工做區是乾淨的
▶ git status  

On branch master
nothing to commit, working tree clean

# 此時用mixed模式在回到`23bcc3e`試試
# mixed是默認模式,因此不須要加--mixed
▶ git reset 23bcc3e  
▶ git status    

# 因爲使用的是mixed模式,移動了HEAD指針並重置了暫存區,因此倉庫狀態和暫存區以前沒有改變,而工做區和暫存區出現了差別
# 和以前的soft模式對比看看區別呢
On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
複製代碼

git log命令只會打印出HEAD指針所指向的提交及其以前的全部提交,若是咱們不當心回退多了幾個版本,怎麼撤銷呢?只要你記得以前的commit id,就能夠再次回退回去,就像上面的hard模式所使用的命令那樣,可是若是不記得id呢,可使用git reflog命令,它會打印你最近操做所對應的commit id

▶ git reflog  

23bcc3e (HEAD -> master) HEAD@{0}: reset: moving to 23bcc3e
9c127f0 HEAD@{1}: reset: moving to 9c127f0
23bcc3e (HEAD -> master) HEAD@{2}: reset: moving to 23bcc3e
9c127f0 HEAD@{3}: reset: moving to 9c127f08158bac02b3ce9456160fbc3bcf8ed078
ff29824 HEAD@{4}: reset: moving to ff29824a23747234d142b966889399d702443ab5
9c127f0 HEAD@{5}: commit: add third line in readme.txt
ff29824 HEAD@{6}: commit: add second line in readme.txt
23bcc3e (HEAD -> master) HEAD@{7}: commit (amend): add first line in readme.txt
4f251eb HEAD@{8}: commit (amend): add first line in readme.txt
5cbd51c HEAD@{9}: commit: add first line in readme.txt
a84a18c HEAD@{10}: commit (initial): add .gitignore
複製代碼

git revert

git reset可讓你回到某一個版本,可是若是你想重置衆多提交中的某些提交的操做,那你就須要用到git revert,它會新建一個提交來重置以前的某一個提交(反向操做)

git revert

  • git revert <commit-id>:新建一個提交重置目標提交
  • git revert -n <commit-id>:重置目標提交,可是不會新建提交,而是修改工做區和暫存區
  • git revet <start-id>...<end-id>:重置多個提交(不包括start-id,可是包括end-id)
# 使用該命令後會出現vim窗口提示輸入新的提交的message
▶ git revert head          
[master 2c9da62] Revert "add third line in readme.txt"
 1 file changed, 1 insertion(+), 2 deletions(-)

▶ git log --oneline
# 若是不更改,這個就是默認的message 格式
2c9da62 (HEAD -> master) Revert "add third line in readme.txt"
9c127f0 add third line in readme.txt
ff29824 add second line in readme.txt
23bcc3e add first line in readme.txt
a84a18c add .gitignore
複製代碼

分支

這一節,咱們開始進入git最爲重要的一個特性:分支。分支使得多人協做開發變得什麼方便,每一個人能夠在他們本身專屬的分支幹活,分支之間互不影響;就要同一臺電腦的不一樣帳號同樣;當完成了操做後,再將全部的工做合併在一塊兒。

在前面已經提到了HEAD指針,它指向的是當前倉庫的版本。其實在以前打印log時,在第一行都能看到相似於9c127f0 - (HEAD -> master)這樣的標識。其中的master就是一個分支,當咱們新建了一個git倉庫時,就會默認建立一個master分支。咱們以前全部的改變都是在master分支全部的改變。

git branch

這裏首先拋出一個結論:git內部的每一個提交會以形如單向鏈表的結構組織起來造成如上圖同樣的鏈式結構。而master,HEAD等就是一系列指向不一樣提交的指針,不一樣的是master指針始終指向它所在的分支的最新提交節點,而HEAD則是表示當前倉庫版本,因此它能夠隨意的移動到不一樣的節點。同一個提交節點能夠有多個指針指向它。

基於上面的結論,咱們能夠看出,新建一個分支其實就是新建了一個指針,而從這個指針所指向的節點向前推就是當前分支的全部節點。如上圖develop分支的全部節點是:e137e9b -> f5b32c8 -> c1c3dfe -> e088135

查看分支

  • git branch:列出本地全部分支
  • git branch -r:列出全部遠程分支(後文會講解什麼是遠程分支)
  • git branch -a:列出全部本地和遠程分支
  • git branch -v:查看分支的詳細信息
# 咱們想看看如今本地有哪些分支
▶ git branch
# 行首的*表示當前倉庫所指向的是哪一個分支
* master


▶ git branch -v

* master 9c127f0 add third line in readme.txt
複製代碼

新建&切換&刪除分支

  • git branch <branch-name>:新建分支
  • git checkout -b <branch-name>:新建分支並切換分支
  • git checkout <branch-name>:切換分支
  • git checkout -:切換到上一個分支
  • git branch -d <branch-name>:刪除分支(針對已經合併過的分支)
  • git branch -D <branch-name>:刪除分支(無論是否合併)
# 新建second分支
▶ git branch second                
▶ git branch -v    
# 能夠看到已經新建了second分支,它和master分支如今只想同一個節點
* master 9c127f0 add third line in readme.txt
  second 9c127f0 add third line in readme.txt

# 切換到second分支
▶ git checkout second  
Switched to branch 'second'

# 再新建一個分支
▶ git branch third
▶ git branch
  master
* second
  third

#刪除分支
▶ git branch -D third  
Deleted branch third (was 9c127f0).
複製代碼

分支合併

每一個人在不一樣的分支進行了本身工做的提交後,最後確定是要將各自的工做合併在一塊兒的,這個時候就須要使用git merge命令。

咱們如今second分支上添加幾個提交,如今的歷史以下圖所示:second分支添加了兩個提交,而master分支沒有添加新的提交。因此如今second分支領先master分支兩個提交(黃色的小🏷表示的是HEAD指針)。

log

  • git merge <branch-name>:分別目標分支到當前分支
#先看看second分支readme.txt的狀態
▶ cat readme.txt
this is first line
this is second line
this is third line

this is added by second branch
this is also added by second branch  

# 咱們如今想合併second分支上兩個更新,首先要切換到master分支
▶ git checkout master
# 能夠看到master分支中的readme.txt並無second分支的更新
# 這就是咱們以前所說的分支之間互不影響
▶ cat readme.txt
this is first line
this is second line
this is third line

▶ git merge second                
Updating 9c127f0..a5e61dd
Fast-forward
 readme.txt | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
複製代碼

再來看看此時的狀態:master分支已經和branch分支指向了同一個提交。此時在master分支就能夠看到second分支的更新了。

log

相信你也注意到了在時候git merge命令時,git提示了Fast-forward的文字,其實Fast-forward表示:若是當前分支合併目標分支時,當前分支沒有任何相較於目標分支以後的提交,此時目標分支就是當前分支的直接上游,此時合併只須要將當前分支的指針移到目標分支的最新提交便可。在咱們的例子中,就是second分支兩個新的提交,可是master分支並無新的提交,全部此時second分支就是master的直接上游,master分支合併second就只須要移動指針到second便可。

若是你不想使用這個Fast-forward模式,可使用git merge --no--ff <branch-name>命令,此時無論目標分支是否是當前分支的直接上游,在合併時,都會新建一個合併提交。

▶ git merge --no-ff second 
Merge made by the 'recursive' strategy.
 readme.txt | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
複製代碼

此時的倉庫狀態是這樣:新建一個合併提交,用於合併second分支內容。

log

若是在兩個分支改動了同一個地方,此時合併就會出現衝突。如今咱們在master分支新增一個提交,這個提交改了和second分支的新提交相同的地方

log

▶ git merge second 
# 此時git提示有衝突
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

# 咱們來看看此時的readme.txt內容是什麼
▶ cat readme.txt
this is first line
this is second line
this is third line
# 下面展現有衝突的部分
# 當前master分支的改動
<<<<<<< HEAD
this is added by master branch
# second分支的改動
=======
this is added by second branch
this is also added by second branch
>>>>>>> second
複製代碼

此時就須要手動處理衝突,刪減不須要的部分,而後正常的提交便可。

可是相信你們也會以爲不值觀,容易出錯;並且若是衝突的地方不少,工做量也很大。因此這個時候仍是推薦是一些git的圖形化工具,裏面有很直觀的衝突解決的圖形界面,下圖所示的是webstorm內置的工具:

conflict

解決衝突後正常提交後的git狀態:

log

撿起這顆櫻桃(cherry-pick)

有時候,咱們並不但願合併其餘分支的全部更新的提交,可能咱們只須要其中某一些提交便可,此時就須要git cherry pick命令。

  • git cherry-pick <commit-id>:挑選一個commit合併到當前分支
  • git cherry-pick <branch-name>:挑選指定分支的最新提交
  • git cherry-pick <start-comm-id>...<end-commit-id>:挑選連續多個提交(左開右閉,不包括start-commit)
  • git cherry-pick <start-commid-id>^...<end-commit-id>:挑選連續多個提交(左閉右閉,包括start-commit)

cherry-pick

咱們先恢復一下git倉庫的狀態:

log

# 將`add new line`這個提交加入到master分支
▶ git cherry-pick 469a80b44
[master 72ec082] add new line in readme.txt by second branch
 Date: Sun Sep 22 22:58:18 2019 +0800
 1 file changed, 3 insertions(+), 1 deletion(-)
複製代碼

此時的狀態:

log

若是遇到衝突,可使用:

  • git cherry-pick --continue:在解決衝突後,繼續執行下一個cherry-pick
  • git cherry-pick --quit:退出操做,保留當前進度
  • git cherry-pick --abort:撤銷本次操做

打上Tag

在git中,tag也是一種指針,和分支,HEAD同樣;可是和它們不一樣的是:tag一旦肯定指向那個提交後就不能在移動;因此它特別適合用來標記哪一個提交對應的版本號,也十分易於查找。

git tag

因爲tag一旦肯定就沒法更改,因此tag的操做相對於分支來講就顯得十分的簡單了。

查看tag

  • git tag:查看全部tag
  • git tag -l <tag-name>:篩選相應的tag
  • git tag --points-at <commit-id>:查看某個commit上全部的tag
  • git show <tag-name>:查看某一個tag
  • git show-ref --tags:查看全部tag以及它們分別對應的commit

新建&刪除tag

  • git tag <tag-name>:新建tag
  • git tag <tag-name> <commit-id>:在指定的提交新建tag
  • git tag -a <tag-name> -m <message>:添加一個tag和message
  • git tag -d <tag-name>:刪除tag
# 在指定的commit新建tag
▶ git tag v1.0 71019                                   

#在當前分支的最新提交新建tag
▶ git tag v2.0   

#打印一下當前的tag
▶ git show-ref --tags 
71019047bf04999b475f23409b3158c4a728dfe7 refs/tags/v1.0
91d4eb5400168f699bc33a19959daac89a068406 refs/tags/v2.0

#刪除tag
▶ git tag -d v1.0
Deleted tag 'v1.0' (was 7101904)
複製代碼

緊急加塞,使用stash

你如今正在feature分支上開發新的功能,忽然QA告訴你master分支有一個bug須要趕忙修復;而這個時候你的工做區還有作到一半的修改,這個時候直接切分支會致使本地的更改會消息,若是新建一個提交,又不合理,畢竟不是一個完成的功能;這個時候就要使用git stash命令暫存本地的修改。

新建stash

git stash會將工做區和暫存區的全部修改暫存起來,是工做區和暫存區與上一次提交一致。

# 先在工做區和暫存區添加一些修改
▶ git status

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

        modified:   readme.txt

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:   readme.txt

▶ git stash

Saved working directory and index state WIP on master: 91d4eb5 add sixth line in readme.txt by second branch

# 工做區和暫存區已經乾淨了
▶ git status

On branch master
nothing to commit, working tree clean

複製代碼

若是不單獨指定stash的messge,默認的格式將是WIP on <current-branch>: <last-commit-id> <last-commit-message>

可使用git stash save <message>指定你想要的messge信息。

▶ git stash save "this is a temporary message"

Saved working directory and index state On master: this is a temporary message
複製代碼

git stash默認的做用範圍是已經跟蹤過的文件,也可使用下面的命令擴大做用範圍:

  • git stash -u:將未跟蹤的文件也加入暫存
  • git stash -a:將全部文件加入暫存(即便該文件被git忽略

查看暫存

  • git stash list:查看暫存的歷史
  • git show stash@{<number>}:查看某一個次特定的暫存
▶ git stash list     

stash@{0}: On master: this is a temporary message
stash@{1}: WIP on master: 91d4eb5 add sixth line in readme.txt by second branch

▶ git show stash@{0}

# 展現當前stash的diff
commit 1efaf35f6e15fff0f6545dce28c95d11480d2a8c (refs/stash)
Merge: 91d4eb5 4b8a600
Author: wenjun <wjxu@thoughtworks.com>
Date:   Mon Sep 23 17:19:01 2019 +0800

    On master: this is a temporary message

diff --cc readme.txt
index 394b8bc,394b8bc..ac801af
--- a/readme.txt
+++ b/readme.txt
@@@ -3,4 -3,4 +3,7 @@@ this is second lin
  this is third line
  
  this is added by second branch
--this is also added by second branch
++this is also added by second branch
++
++
++yes

複製代碼

取出&刪除暫存

  • git stash apply:取出最近的暫存
  • git stash apply <number>:取出目標暫存
  • git stash pop:取出最近暫存,並刪除該暫存的記錄
▶ git stash apply          

On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

▶ git stash list 
# 最近的暫存歷史依舊存在
stash@{0}: On master: this is a temporary message
stash@{1}: WIP on master: 91d4eb5 add sixth line in readme.txt by second branch


▶ git stash pop 
On branch 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:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (1efaf35f6e15fff0f6545dce28c95d11480d2a8c)

▶ git stash list
# 最近的暫存歷史已經被刪除
stash@{0}: WIP on master: 91d4eb5 add sixth line in readme.txt by second branch
複製代碼

除了直接把暫存取出來,咱們還能夠爲暫存單獨創建一個分支

  • git stash branch <branch-name>:爲最近一次暫存創建新的分支,而且刪除記錄
  • git stash branch <branch-name> <number>:爲目標暫存創建新的分支,而且刪除記錄
# 新建一個stash-branch分支
▶ git stash branch stash-branch

Switched to a new branch 'stash-branch'
On branch stash-branch
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   readme.txt

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:   readme.txt

Dropped refs/stash@{0} (8ba8cdc6e530fc0c827f6f3c1978039dd2c19bc4)

# 能夠看到已經創建而且切換到了新的分支
▶ git branch

  master
  second
* stash-branch
複製代碼

對於不須要的暫存,可使用下面命令刪除:

  • git stash drop:刪除最近暫存
  • git stash drop <number>:刪除目標暫存
  • git stash clear:清空歷史

變基(rebase)

git裏面有一個超級厲害的操做就作變基(rebase), 雖然聽起來怪怪的,可是人家是一個正經的命令。咱們以前所講的都是如何回退版本,如何撤銷修改。可是並無改變歷史的提交。而rebase能夠真正的作到改變歷史提交,還能夠作到合併分支。

合併分支

先從熟悉的內容入手,咱們以前已經學習了使用git merge命令合併其餘分支,其實git rebase也能夠實現合併分支的功能;使用git rebase <branch-name>

先來看看如今的git狀態,master分支有一個新的提交,second分支有兩個新的提交

rebase

▶ git rebase second

First, rewinding head to replay your work on top of it...
Applying: add a.txt
複製代碼

如今的倉庫狀態變成了:

rebase
rebase操做會將 master分支的更新接在 second分支兩個更新的後面,最後就造成了上圖的最終狀態。
rebase vs merge

若是是直接使用git merge將是:

merge

明顯能看到同時使用rebase操做可以獲得一個更簡單的提交歷史,這是要有些人更願意使用rebase的緣由。

重寫歷史

使用git rebase -i <commit-id>能夠交互式的操做到commi-id爲止的提交(不包括commit-id所指向提交)的全部提交。

以前所學習到的git commit --amend也算是重寫歷史的一種方式

log

若是咱們想更改最後三個提交,對add a.txt重命名,而後合併update readme.txt aaginupdate readme.txt兩個提交

▶ git rebase -i HEAD~3

pick 3baae50 update readme.txt
pick c951be0 update readme.txt again
pick 5a57f77 add a.txt

# Rebase 9c127f0..5a57f77 onto 9c127f0 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# 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

複製代碼

以後就會就如vim界面,咱們全部涉及到的每一次提交前面都有pick關鍵字。咱們能夠替換不一樣的關鍵字實現不一樣的效果:

  • p or pick:不更改,直接保持該commit
  • r or reword:保留該commit,可是更改commit的信息
  • e or edit:編輯commit,相似於amend
  • s or squash:和前一個commit合併,並編輯新的commit的信息
  • f or fixup:和前一個commit合併,直接使用前一個commit的信息
  • d or drop:刪除該commit(或者直接刪除該行,效果一致)

基於咱們想要的效果,最後將關鍵字改寫成:

pick 3baae50 update readme.txt
f c951be0 update readme.txt again
r 5a57f77 add a.txt
複製代碼

而後保存提交就能獲得想要的效果:

log

若是在rebase過程當中,須要衝突可以使用:

  • git rebase --continue:繼續執行下一個操做(解決衝突後)
  • git rebase --skip:跳過當前操做
  • git rebase --abort:放棄rebase操做

rebase經常使用操做技巧

把最初始的提交也放入rebase的範圍內

因爲使用git rebase -i <commit-id>時不會包括commit-id此次提交,全部通常狀況對於第一次提交默認狀況是沒法加入rebase中的,能夠在使用命令後的vim操做界面中第一行添加pick <commit-id>便可囊括其中

將幾個不連續的commit合併成一個

在使用git rebase -i <commit-id>後,把要合併的幾個提交位置調整到一塊兒,將除了要合併的第一個提交外的全部提交的操做符都變成squash或者fixup便可

將一個commit拆分紅幾個

在使用git rebase -i <commit-id>後,在該提交使用操做符爲edit, 使用命令git reset HEAD^將本次提交全部更多撤回到工做區 屢次使用git addgit commit就行提交直到工做區乾淨爲止, 最後使用git rebase --continue完成rebase操做

恢復rebase以前的狀態簡易操做

在rebase開始前,新建一個分支,在執行各類rebase操做,而且完成操做後,可以使用git reset --hard <branch-name>恢復到一開始的狀態

遠程倉庫

咱們以前全部的內容都是基於本地倉庫實現的,但git如今普及度這麼高,不只由於其優秀的版本控制能力,還離不開遠程倉庫的支持,例如全球最大的同性交友網站github,由於遠程操做的存在,使得咱們能夠將本地的修改推送到遠端,也能夠十分方便的從遠端拉取別人提交的更新。

克隆&管理遠程倉庫

若是是一個已經存在的遠程倉庫,咱們但願下載到本地,可使用:

  • git clone <url>:拉取代碼,並使用默認的遠端倉庫的名字
  • git clone <url> <new-name>::拉取代碼,自定義本地倉庫名字

若是是像本文中已經有本地提交的倉庫,能夠在github中新建一個倉庫,賦值連接,而後使用:

  • git remote add <remote-name> <remote-url>:添加遠程倉庫
  • git remote -v:查看遠端倉庫信息
  • git remote remove <remote-name>:刪除遠程倉庫
  • git remote rename <old-remote-name> <new-remote-name>:重命名遠程操做名字
▶ git remote add origin git@github.com:AHOhhhh/git-practice.git                                                                     
▶ git remote -v                                       

origin  git@github.com:AHOhhhh/git-practice.git (fetch)
origin  git@github.com:AHOhhhh/git-practice.git (push)
複製代碼

推送和更新

  • git push <remote-name> <branch-name>:推送分支到特定的遠程倉庫,若是隻有一個遠程倉庫能夠省略,第一次推送須要加入-u參數
  • git push <remote-name> <tag-name>:推送指定tag到遠端
  • git push <remote-name> --tags:推送全部tag到遠端
# 因爲是第一次提交,提示須要加`-u`
▶ git push       
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master


▶ git push -u origin master 

Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (15/15), 2.00 KiB | 1.00 MiB/s, done.
Total 15 (delta 0), reused 0 (delta 0)
To github.com:AHOhhhh/git-practice.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

# 將全部分支推送到遠端後
# 打印全部分支,會發現多了兩個remote的分支,它們表示遠端對應的分支
▶ git branch -a 

* master
  second
  remotes/origin/master
  remotes/origin/second

# 推送全部tag
▶ git push --tags   

Total 0 (delta 0), reused 0 (delta 0)
To github.com:AHOhhhh/git-practice.git
 * [new tag]         v1.0 -> v1.0

複製代碼

當遠端有更新時,可使用:

  • git fetch:拉取更新
  • git pull:獲取遠端倉庫更新,並自動合併到本地分支(至關於git fetch && git merge
  • git pull --rebase:使用rebase方式拉取更新(與以前使用rebase合併本地分支效果相似)
▶ git pull

remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1), pack-reused 0
Unpacking objects: 100% (2/2), done.
From github.com:AHOhhhh/git-practice
   e771fff..a8207fe  master     -> origin/master
Updating e771fff..a8207fe
Fast-forward
 e.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 e.txt
複製代碼

特別提醒:因爲以前所講的git commit --amend,rebase等操做會改變提交歷史,因此最好只做用於本地提交,對於已推送到遠端的提交儘可能不要這樣操做,否則會和遠端有大量的不一樣和衝突

結語

full lifecycle

至此,關於git經常使用的操做大概講解完了,雖然通篇都是在講命令行的使用,可是這並不表明筆者認爲命令行黨比UI黨要高級,其實文章中很多的圖片也是使用圖形的界面結果。可是一直使用圖形界面,對git不少命令會理解的不夠深入,致使總是會被git的一些錯誤絆住腳。

因此但願經過這篇文章,可以對git的經常使用知識點進行梳理,但願你們能到git有更深刻的認識,並結合圖形界面方便的操做,使得之後在git的使用可以更加順利。

更多文章

相關文章
相關標籤/搜索