Git學(xué)習(xí)總結(jié)——簡單易懂的教程

安裝Git

Git的下載地址:Git官網(wǎng)下載地址

Git本地倉庫和命令

配置用戶

下載完Git后,右鍵會(huì)有一個(gè)Git Bash here的選項(xiàng)褪尝,點(diǎn)擊后會(huì)彈出一個(gè)類似于命令行的窗口:

Git界面

在此輸入此命令配置用戶名和郵箱:

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

注意抹沪,--global參數(shù),表示你這臺(tái)機(jī)器上所有的Git倉庫都會(huì)使用這個(gè)配置,當(dāng)然也可以對某個(gè)倉庫指定不同的用戶名和Email地址颊郎。

創(chuàng)建版本庫

什么是版本庫呢?版本庫又名倉庫亭枷,英文名repository袭艺,你可以簡單理解成一個(gè)目錄,這個(gè)目錄里面的所有文件都可以被Git管理起來叨粘,每個(gè)文件的修改猾编、刪除瘤睹,Git都能跟蹤,以便任何時(shí)刻都可以追蹤歷史答倡,或者在將來某個(gè)時(shí)刻可以“還原”轰传。

1、選擇一個(gè)目錄瘪撇,使用命令創(chuàng)建一個(gè)目錄:

Administrator@XXX MINGW64 /e/git
$ mkdir learngit

Administrator@XXX MINGW64 /e/git
$ cd learngit

Administrator@XXX MINGW64 /e/git/learngit
$ pwd
/e/git/learngit

其中获茬,mkdir命令用于創(chuàng)建目錄,pwd命令用于顯示當(dāng)前目錄倔既。

注意: 目錄中最好不要有中文恕曲。

2、使用命令git init渤涌,將此目錄變成一個(gè)倉庫:

Administrator@XXX MINGW64 /e/git/learngit
$ git init
Initialized empty Git repository in E:/git/learngit/.git/

當(dāng)前目錄下多了一個(gè).git的目錄佩谣,這個(gè)目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動(dòng)修改這個(gè)目錄里面的文件实蓬,不然改亂了茸俭,就把Git倉庫給破壞了。
如果沒有看到.git的目錄安皱,輸入命令ls -ah就能看見调鬓。

3、添加文件到版本庫

所有的版本控制系統(tǒng)酌伊,其實(shí)只能跟蹤文本文件的改動(dòng)腾窝,圖片、視頻腺晾、Word這些二進(jìn)制文件無法有效控制燕锥,因此建議以純文本的形式編寫。

learngit目錄下悯蝉,新建一個(gè)文本readme.txt归形,內(nèi)容如下:

We don't talk anymore.
Like we used to do.

(1)使用命令git addreadme.txt添加到倉庫:

Administrator@XXX MINGW64 /e/git/learngit (master)
$ git add readme.txt

(2)使用明明git commitreadme.txt提交到倉庫:

Administrator@XXX MINGW64 /e/git/learngit (master)
$ git commit -m "create a readme file"
[master (root-commit) 93b4ff1] create a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

其中,-m后面是本次提交的說明鼻由,1 file changed表示有一個(gè)文件發(fā)生改動(dòng)暇榴,2 insertions表示插入了兩行內(nèi)容。

如果我們不小心直接使用了git commit操作蕉世,而不是git commit -m "XXX"操作的話蔼紧,會(huì)彈出這樣一個(gè)窗口提示我們輸入為什么要合入本次修改:

直接使用git commit命令

此時(shí),我們可以按i鍵狠轻,進(jìn)入輸入修改的解釋(圖中黃色部分)奸例,輸入完后按Esc退出修改,再輸入:wq按回車鍵就可以了。

修改文件

1查吊、首先谐区,將我們的readme.txt文件的第一行修改一下,修改后如下:

We don't talk anymore.  Yes.
Like we used to do.

可以看見逻卖,添加了一個(gè)yes宋列。

2、使用git status查看當(dāng)前倉庫的修改狀態(tài):

$ 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")

其中评也,modified: readme.txt告訴我們炼杖,readme.txt被修改了。

3盗迟、如果我們要看具體修改的是什么內(nèi)容坤邪,使用git diff命令來查看:

$ git diff
diff --git a/readme.txt b/readme.txt
index d27965f..cd08cf5 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-We don't talk anymore.
+We don't talk anymore.  Yes.
 Like we used to do.
\ No newline at end of file

其中,可以看出readme.txt被修改了罚缕,修改內(nèi)容是We don't talk anymore.這一句被改成了+We don't talk anymore. Yes.罩扇。

4、知道了修改內(nèi)容怕磨,認(rèn)為沒有問題就可以將它提交到倉庫里面了翅阵,也是同樣的步驟git add <file>紧帕,git commit

(1)執(zhí)行$ git add readme.txt后陵霉,沒有任何提示兆览;

(2)執(zhí)行git commit之前西壮,我們再看一下倉庫的狀態(tài)溺拱,執(zhí)行git status

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

        modified:   readme.txt

其中讯嫂,Changes to be committed:modified: readme.txt這兩句代碼告訴我們谬盐,將要提交的修改包括readme.txt氯材;

(3)接下來就可以執(zhí)行git commit命令去提交修改的文件了:

$ git commit -m "add Yes"
[master 6a32611] add Yes
 1 file changed, 1 insertion(+), 1 deletion(-)

(4)接下來渣锦,我們再使用git status命令查看當(dāng)前的倉庫狀態(tài):

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

表示沒有要提交的修改,其中氢哮,working tree clean表示當(dāng)前倉庫是干凈的袋毙。

版本回退

為了說明版本回退,我再修改提交一次readme.txt文件冗尤,將它修改成如下這樣并提交:

We don't talk anymore.  Yes.
Like we used to do. No.

提交的代碼如下:

$ git commit -m "add No."
[master 0440b0f] add No.
 1 file changed, 1 insertion(+), 1 deletion(-)

現(xiàn)在听盖,我們的版本庫里面就有了三個(gè)版本的readme.txt文件:

  1. create a readme file
  2. add Yes
  3. add No

如果版本太多,怎么看我們到底修改了多少次呢裂七?使用git log命令皆看,可以看到我們歷史提交的數(shù)據(jù):

$ git log
commit 0440b0f8a14578b1efb38fbf3ca95f312d44db2f (HEAD -> master)    
Author: XXX <XXX@qq.com>
Date:   Sat Jul 28 14:31:51 2018 +0800

    add No.

commit 6a326110a8adc7d7856c72eb2e1c9fad97504fc8
Author: XXX <XXX@qq.com>
Date:   Sat Jul 28 14:24:01 2018 +0800

    add Yes

commit 93b4ff11e85f94a16ba6d9b0cff1ea2cdf226b60
Author: XXX <XXX@qq.com>
Date:   Fri Jul 27 22:32:43 2018 +0800

    create a readme file

git log 顯示的是從最近到最遠(yuǎn)的提交記錄,如上背零,可以看出我們提交了三次修改腰吟。

其中,上面第二行的commit 0440b0f8a14578b1efb38fbf3ca95f312d44db2f中的0440b...表示的這次提交的commit id徙瓶,HEAD -> master表示add No這次提交是當(dāng)前的版本毛雇,上次的版本就是HEAD^表示嫉称,上上次就是HEAD^^,如果版本太久遠(yuǎn)禾乘,就會(huì)用類似HEAD~100這種形式來表示澎埠。

現(xiàn)在,我們要把add No版本回退到add Yes版本始藕,我們使用命令git reset實(shí)現(xiàn):

$ git reset --hard HEAD^
HEAD is now at 6a32611 add Yes

現(xiàn)在蒲稳,我們看看readme.txt中的內(nèi)容是否被還原了:

We don't talk anymore.  Yes.
Like we used to do.

確實(shí)變成了add Yes的版本。
我們再來查看當(dāng)前版本歷史記錄:

$ git log
commit 6a326110a8adc7d7856c72eb2e1c9fad97504fc8 (HEAD -> master)
Author: XXX <XXX@qq.com>
Date:   Sat Jul 28 14:24:01 2018 +0800

    add Yes

commit 93b4ff11e85f94a16ba6d9b0cff1ea2cdf226b60
Author: XXX <XXX@qq.com>
Date:   Fri Jul 27 22:32:43 2018 +0800

    create a readme file

可以看到伍派,add No的版本已經(jīng)不見了江耀。那么如果我想回退到新版本,應(yīng)該如何操作呢诉植?有兩種辦法:

1祥国、如果你還記得add No的commit id,也就是上面所說的0440b...那一串?dāng)?shù)字晾腔,那么執(zhí)行如下命令:

$ git reset --hard 0440b
HEAD is now at 0440b0f add No.

--hard后面輸入了0440b舌稀,這是add No的commit id的前幾位,只需要輸入commit id的前幾位就行了灼擂,git會(huì)自動(dòng)去尋找對應(yīng)的id壁查。

現(xiàn)在,再看一下readme.txt的內(nèi)容剔应,發(fā)現(xiàn)果然還原到了add No的版本:

We don't talk anymore.  Yes.
Like we used to do. No.

2睡腿、如果你記不住commit id了,也沒關(guān)系峻贮,git提供了一個(gè)命令行席怪,來記錄我們每次的命令git reflog

$ git reflog
6a32611 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
0440b0f HEAD@{1}: reset: moving to 0440b
6a32611 (HEAD -> master) HEAD@{2}: reset: moving to HEAD^
0440b0f HEAD@{3}: commit: add No.
6a32611 (HEAD -> master) HEAD@{4}: commit: add Yes
93b4ff1 HEAD@{5}: commit (initial): create a readme file

其中,從0440b0f HEAD@{3}: commit: add No.這一句中纤控,我們可以看出來挂捻,add No的版本的commit id是0440b0f
找到了commit id嚼黔,再次使用git reset命令细层,就能回退到指定的版本了:

$ git reset --hard 0440b
HEAD is now at 0440b0f add No.

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

工作區(qū)(Working Directory)

工作區(qū)就是我們能看到的目錄,比如learngit目錄就是工作區(qū)唬涧。

版本庫(Repository)

工作區(qū)有一個(gè)隱藏目錄.git疫赎,這個(gè)不算工作區(qū),而是Git的版本庫碎节。
Git的版本庫里存了很多東西捧搞,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master,以及指向master的一個(gè)指針叫HEAD胎撇。

工作區(qū)和版本庫

如圖介粘,我們可以知道,我們在工作區(qū)修改的內(nèi)容晚树,經(jīng)過git add命令姻采,會(huì)將修改的內(nèi)容存儲(chǔ)到stage區(qū)域,也就是暫存區(qū)爵憎,然后再經(jīng)過git commit命令慨亲,才會(huì)將我們的修改內(nèi)容合入到master分支上。

我們來試驗(yàn)一下宝鼓,先給readme.txt新增加一行內(nèi)容:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.

然后刑棵,我們在learngit目錄下,新增一個(gè)文本文件LICENSE.txt愚铡,內(nèi)容隨便填寫蛉签。

先用git status命令查看一下當(dāng)前目錄的狀態(tài):

$ 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

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

        LICENSE.txt

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

其中,modified: readme.txt可以知道沥寥,readme.txt的內(nèi)容被修改了碍舍,而LICENSE.txt還未被添加,所以狀態(tài)是Untracked邑雅。
關(guān)于git status的狀態(tài)種類乒验,可以看這里:Git教學(xué)篇3-文件狀態(tài)之git status與git diff

現(xiàn)在,使用命令git add readme.txt和命令git add LICENSE.txt后蒂阱,使用git status命令查看當(dāng)前倉庫狀態(tài):

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

        new file:   LICENSE.txt
        modified:   readme.txt

現(xiàn)在,暫存區(qū)的狀態(tài)就變成了:


暫存區(qū)狀態(tài)

然后執(zhí)行git commit命令狂塘,將暫存區(qū)的文件提交到master分支上:

$ git commit -m "understand how stage works"
[master 7126739] understand how stage works
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 LICENSE.txt

此時(shí)录煤,我們用git status查看倉庫狀態(tài):

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

此時(shí),倉庫變成這樣:

倉庫狀態(tài)

補(bǔ)充:
git diff是工作區(qū)和暫存區(qū)的比較荞胡,git diff --cached是暫存區(qū)和master的比較妈踊。
git status是比較本地工作區(qū)的變更。

管理修改

Git最重要的一個(gè)特性是泪漂,git管理的是文件的修改廊营,而不是文件本身。比如你新增了一行萝勤,這就是一個(gè)修改露筒,刪除了一行,也是一個(gè)修改敌卓,更改了某些字符慎式,也是一個(gè)修改,刪了一些又加了一些,也是一個(gè)修改瘪吏,甚至創(chuàng)建一個(gè)新文件癣防,也算一個(gè)修改。

舉例說明掌眠,首先蕾盯,我們給readme.txt新增加一行:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

然后使用git add命令添加到暫存區(qū),然后再次修改readme.txt

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
Add new new Line.

然后git commit這次提交:

$ git commit -m "add two lines"
[master ea3fc04] add two lines
 1 file changed, 2 insertions(+), 1 deletion(-)

此時(shí)蓝丙,我們看一下提交狀態(tài):
$ 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")

如上级遭,提示我readme.txt被修改了,但是還沒有add到暫存區(qū)迅腔,原因是因?yàn)槲覀兊牟僮黜樞蚴切薷奈募?>git add->修改文件->git commit装畅,我們再第一次修改文件后執(zhí)行了add操作,將文件add到暫存區(qū)沧烈,而第二次沒有掠兄,因此,git commit命令只是將我們第一次的修改提交到了本地倉庫中锌雀,如果我們需要第二次的修改也提交到倉庫中蚂夕,那么我們需要對第二次的操作也進(jìn)行git addgit commit操作∫改妫或者婿牍,我們可以在第一次修改文件后不做git add操作,而是在修改完所有內(nèi)容后惩歉,再一次性的git add等脂。

撤銷修改

我們先給readme.txt文件添加一行內(nèi)容:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
Add new new Line.
I am a error.

我們在最后一行添加了一句I am a error.,這時(shí)撑蚌,我們用git status看一下當(dāng)前的本地狀態(tài):

$ 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")

其中上遥,有一句(use "git checkout -- <file>..." to discard changes in working directory告訴我們可以丟棄工作區(qū)的修改:

$ git checkout -- readme.txt

此時(shí),我們的readme.txt變成了這樣:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

可以看見争涌,最后兩行都不見了粉楚,這是因?yàn)樽詈髢尚械膬?nèi)容都沒有被添加到暫存區(qū)(沒有執(zhí)行git commit命令),因此亮垫,它們都被丟棄了模软。
那么,如果我添加I am a error后又將此修改add到了暫存區(qū)后饮潦,那么git checkout會(huì)變成什么樣呢燃异?

首先,我們先說明一下git checkout的作用范圍继蜡。
我們修改一下readme.txt文件:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
I am an error.

然后使用git add命令將此修改添加到暫存區(qū)特铝,然后使用git ckeckout命令后暑中,查看readme.txt文件:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
I am an error.

最后一句依然在,那么鲫剿,我們對readme.txt內(nèi)容做一次修改:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
I am an error.
I am an anotner error.

然后再git checkout

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
I am an error.

可以看到鳄逾,readme.txt變成了上次git add后的內(nèi)容(readme.txt添加了I am an error.這一句后的git add操作),也就是說灵莲,git checkout操作雕凹,可以將工作區(qū)的內(nèi)容回退到最近一次git add或者git commit后的狀態(tài)。

但是政冻,如果我已經(jīng)將I am an error.這句話add到了暫存區(qū)枚抵,那么,如何才能撤銷本次暫存區(qū)的內(nèi)容呢明场?
我們先將readme.txt的內(nèi)容修改成這樣汽摹,并add到暫存區(qū):

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.
I am an error.

然后使用git reset HEAD <file>命令,將暫存區(qū)的內(nèi)容撤銷到工作區(qū)(也就是將本次git add的內(nèi)容撤銷到工作區(qū)):

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

其中苦锨,當(dāng)我們用HEAD時(shí)逼泣,表示最新的版本。
再使用git status查看工作區(qū)狀態(tài)舟舒,可以看見工作區(qū)的內(nèi)容沒有被添加到暫存區(qū):

$ 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命令,將本次修改移除掉秃励。使用命令后氏仗,我們的readme.txt文件變成了這樣:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

版本回退和撤銷修改場景總結(jié)

假如readme.txt原內(nèi)容為A,修改后為A+B:

1夺鲜、此時(shí)沒有執(zhí)行git add操作皆尔,工作區(qū)想要恢復(fù)為A,則執(zhí)行:

$ git checkout -- readme.txt

執(zhí)行前币励,工作區(qū)內(nèi)容為A+B床佳,暫存區(qū)內(nèi)容為A,版本庫內(nèi)容為A榄审。
執(zhí)行后,工作區(qū)內(nèi)容變?yōu)锳杆麸,暫存區(qū)內(nèi)容為A搁进,版本庫內(nèi)容為A。

2昔头、此時(shí)執(zhí)行了git add操作饼问,想要撤回本次git add操作(工作區(qū)恢復(fù)為A+B,暫存區(qū)恢復(fù)為A)則執(zhí)行:

$ git reset readme.txt

此命令等同于命令:

$ git reset --mixed readme.txt

--mixed表示重置HEAD指針和暫存區(qū)揭斧,但是工作區(qū)內(nèi)容保持不變莱革。

執(zhí)行前峻堰,工作區(qū)內(nèi)容為A+B,暫存區(qū)內(nèi)容為A+B盅视,版本庫內(nèi)容為A捐名。
執(zhí)行后,工作區(qū)內(nèi)容為A+B闹击,暫存區(qū)內(nèi)容為A镶蹋,版本庫內(nèi)容為A。

3赏半、此時(shí)執(zhí)行了git add操作贺归,想要撤回本次git add操作(工作區(qū)恢復(fù)為A,暫存區(qū)恢復(fù)為A)断箫,則執(zhí)行:

$ git reset readme.txt
$ git checkout -- readme.txt

或者執(zhí)行如下命令:

$ git reset --hard head

執(zhí)行前拂酣,工作區(qū)內(nèi)容為A+B,暫存區(qū)內(nèi)容為A+B仲义,版本庫內(nèi)容為A婶熬。
執(zhí)行后,工作區(qū)內(nèi)容為A光坝,暫存區(qū)內(nèi)容為A尸诽,版本庫內(nèi)容為A。

4盯另、此時(shí)執(zhí)行了git add操作和git commit操作性含,想要撤回本次操作(工作區(qū)恢復(fù)為A+B,暫存區(qū)恢復(fù)為A+B鸳惯,版本庫恢復(fù)為A)商蕴,則執(zhí)行:

$ git reset --soft HEAD^

--soft表示僅僅重置HEAD指針,不重置工作區(qū)和暫存區(qū)的內(nèi)容芝发。

執(zhí)行前绪商,工作區(qū)內(nèi)容為A+B,暫存區(qū)內(nèi)容為A+B辅鲸,版本庫內(nèi)容為A+B格郁。
執(zhí)行后,工作區(qū)內(nèi)容為A+B独悴,暫存區(qū)內(nèi)容為A+B例书,版本庫內(nèi)容為A。

5刻炒、此時(shí)執(zhí)行git add操作和git commit操作决采,想要撤回本次操作(工作區(qū)恢復(fù)為A,暫存區(qū)恢復(fù)為A坟奥,版本庫恢復(fù)為A)树瞭,則執(zhí)行:

$ git reset --hard HEAD^

--hard表示重置HEAD指針拇厢、暫存區(qū)、工作區(qū)內(nèi)容晒喷。

執(zhí)行前孝偎,工作區(qū)內(nèi)容為A+B,暫存區(qū)內(nèi)容為A+B厨埋,版本庫內(nèi)容為A+B邪媳。
執(zhí)行后,工作區(qū)內(nèi)容為A荡陷,暫存區(qū)內(nèi)容為A雨效,版本庫內(nèi)容為A。

  • --mixed:重置HEAD指針和暫存區(qū)废赞,工作區(qū)保持不變徽龟。
    說明:--mixed后面可以接文件名或者指定的指針比如HEAD^,接文件名時(shí)表示僅僅重置當(dāng)前的暫存區(qū)(暫存區(qū)的內(nèi)容還是HEAD的)唉地,接指針比如HEAD^時(shí)据悔,表示重置當(dāng)前的指針到HEAD^,暫存區(qū)內(nèi)容變?yōu)?code>HEAD時(shí)的內(nèi)容(也就是空的)耘沼。

  • --soft:后面只能接指針极颓,僅僅重置版本(比如將當(dāng)前版本HEAD改為HEAD^,但是暫存區(qū)和工作區(qū)的內(nèi)容還是HEAD的)群嗤。

  • --hard:后面只能接指針菠隆,重置版本、暫存區(qū)和工作區(qū)內(nèi)容(比如將當(dāng)前版本HEAD改為HEAD^狂秘,暫存區(qū)和工作區(qū)的內(nèi)容都變成HEAD^的)骇径。

版本回退和撤銷修改還有一種命令git revert,這個(gè)我們在后面再介紹者春。

刪除文件

我們先在learngit目錄下新建一個(gè)test.txt文本文件破衔,并commit到本地版本庫中。
當(dāng)我們在本地將此文件刪除后钱烟,
1晰筛、如果是確實(shí)要?jiǎng)h除,則使用命令刪除此文件:

$ git rm test.txt
rm 'test.txt'

然后在刪除后做git commit操作更新本地倉庫就行拴袭。
2读第、如果是誤刪,那么也沒關(guān)系稻扬,我們的本次倉庫中還有這個(gè)文件,我們只需要從倉庫中取出就行了:

$ git checkout -- test.txt

此時(shí)羊瘩,我們工作區(qū)的test.txt就又回來了泰佳。

Git遠(yuǎn)程倉庫

在本地倉庫對文件的修改我們已經(jīng)學(xué)習(xí)的差不多了盼砍,那么,下面就到了和遠(yuǎn)程倉庫如何交互的學(xué)習(xí)了逝她。

遠(yuǎn)程倉庫我們沒有也沒有關(guān)系浇坐,可以利用GitHub這個(gè)神奇的網(wǎng)站來實(shí)現(xiàn)。

添加遠(yuǎn)程倉庫

1黔宛、生成秘鑰

首先近刘,由于GitHub和本地的倉庫關(guān)聯(lián)是通過SSH加密的,所以臀晃,我們需要先在本地添加一下公鑰和私鑰觉渴。

創(chuàng)建SSH Key的命令是:

$ ssh-keygen -t rsa -C "youremail@example.com"

不用設(shè)置密碼,一路回車就行徽惋。
然后在我們的用戶目錄下會(huì)生成一個(gè).ssh的文件夾案淋,此文件夾下面會(huì)生成id_rsaid_rsa.pub兩個(gè)文件。id_rsa是私鑰险绘,不能泄露出去踢京,id_rsa.pub是公鑰,可以告訴任何人宦棺。

2、配置秘鑰

登錄GitHub官網(wǎng)蹈丸,點(diǎn)擊頭像 - Settings - SSH and GPG keys - New SSH key
id_rsa.pub文件中的內(nèi)容粘貼進(jìn)去,然后點(diǎn)擊添加即可管搪。

為什么GitHub需要SSH Key呢?因?yàn)镚itHub需要識別出你推送的提交確實(shí)是你推送的,而不是別人冒充的顶别,而Git支持SSH協(xié)議,所以剩失,GitHub只要知道了你的公鑰,就可以確認(rèn)只有你自己才能推送。
當(dāng)然绽媒,GitHub允許你添加多個(gè)Key猎提。假定你有若干電腦疙教,你一會(huì)兒在公司提交葵诈,一會(huì)兒在家里提交理疙,只要把每臺(tái)電腦的Key都添加到GitHub,就可以在每臺(tái)電腦上往GitHub推送了。
最后友情提示,在GitHub上免費(fèi)托管的Git倉庫粤攒,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放進(jìn)去。

3芯丧、關(guān)聯(lián)本地倉庫

登錄GitHub后骗露,點(diǎn)擊頭像旁邊的+,選擇new repository,在Repository name里面填入learngit后,其余保持默認(rèn)后點(diǎn)擊Create repository优俘。

生成后會(huì)看到如圖所示的一個(gè)頁面财饥,點(diǎn)擊SSH后會(huì)看到我們的git地址:

Git遠(yuǎn)程倉庫地址

然后我們在本地的learngit倉庫下打開git bash,直接運(yùn)行圖中標(biāo)紅的那部分的命令(其實(shí)應(yīng)該是下面那個(gè) or oush an existing ...那部分):

git remote add origin git@github.com:XXX/learngit.git

此時(shí)本地倉庫就和遠(yuǎn)程倉庫關(guān)聯(lián)上了,然后我們運(yùn)行標(biāo)紅框下面那一句命令,將本地的文件推送到遠(yuǎn)程倉庫中:

$ git push -u origin master
Counting objects: 25, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (25/25), 2.13 KiB | 0 bytes/s, done.
Total 25 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To github.com:XXX/learngit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

問題解決
我在執(zhí)行git push -u origin master時(shí)魂莫,爆出如下錯(cuò)誤:

The authenticity of host 'github.com (52.74.223.119)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)? 

此時(shí)不要選擇直接回車还蹲,而是要輸入yes后再回車,原因是我們本地.ssh文件夾中只有兩個(gè)秘鑰耙考,缺少了一個(gè)known_hosts的文件谜喊,選擇yes后此文件會(huì)自動(dòng)生成。
接著倦始,又爆出了如下錯(cuò)誤:

Warning: Permanently added 'github.com,52.74.223.119' (RSA) to the list of known hosts.
packet_write_wait: Connection to 52.74.223.119 port 22: Broken pipe
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

此時(shí)不要慌張最易,這只是表示我們已經(jīng)把GitHub的Key添加到本機(jī)的一個(gè)信任列表里了。只要再次執(zhí)行一次git push -u origin master命令弥虐,即可推送成功。

由于遠(yuǎn)程庫是空的鲁沥,我們第一次推送master分支時(shí)读处,加上了-u參數(shù)阿逃,Git不但會(huì)把本地的master分支內(nèi)容推送的遠(yuǎn)程新的master分支,還會(huì)把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來,在以后的推送或者拉取時(shí)就可以簡化命令,推送命令:

$ git push origin master

從遠(yuǎn)程倉庫克隆

如果我們已經(jīng)有了一個(gè)遠(yuǎn)程庫箩绍,如何將它拉取到本地呢?

我們先在GitHbu上創(chuàng)建一個(gè)倉庫gitskills,并且勾選圖中紅框部分,表示給我們的項(xiàng)目添加一個(gè)README.md文件艘希。

新建gitskills倉庫

新的倉庫建完之后,我們可以在此倉庫的頁面找到一個(gè)clone or download的圖標(biāo)啸驯,點(diǎn)擊后會(huì)有一個(gè)我們倉庫的地址客扎,類似于git@github.com:XXX/gitskills.git,這時(shí)罚斗,我們只要在本地使用如下命令(最好不要在learngit目錄下執(zhí)行此命令)徙鱼,則就可以將遠(yuǎn)程倉庫拉取到本地并關(guān)聯(lián)了:

$ git clone git@github.com:XXX/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

執(zhí)行完后在當(dāng)前目錄就會(huì)有一個(gè)gitskills的git倉庫了。

分支管理

如果在多人協(xié)作的項(xiàng)目中针姿,我們有一個(gè)新的功能要去實(shí)現(xiàn)袱吆,當(dāng)前我們已經(jīng)實(shí)現(xiàn)了50%,如果此時(shí)我們將代碼合入master分支距淫,就有可能影響其他人無法工作绞绒,如果我們不合入master分支,則會(huì)有代碼丟失的風(fēng)險(xiǎn)榕暇。
那么蓬衡,針對這種情況喻杈,我們就可以新建一個(gè)只有自己能看見的分支,別人看不到狰晚,還繼續(xù)在原來的分支上正常工作筒饰,而你在自己的分支上干活,想提交就提交家肯,直到開發(fā)完畢后龄砰,再一次性合并到原來的分支上,這樣讨衣,既安全换棚,又不影響別人工作。

創(chuàng)建與合并分支

前面版本回退的時(shí)候反镇,我們說了HEAD -> masterHEAD是表示當(dāng)前的版本固蚤,這是因?yàn)槲覀冎挥幸粋€(gè)分支master,其實(shí)實(shí)際上歹茶,指向版本是master這個(gè)指針夕玩,我們提交的內(nèi)容也是通過master指向的指針版本去更新內(nèi)容,而HEAD其實(shí)是指向master的指針惊豺。每次你的提交master都會(huì)向前移一步燎孟,而HEAD會(huì)永遠(yuǎn)跟隨master移動(dòng)。
如果我們現(xiàn)在創(chuàng)建一個(gè)新的分支dev尸昧,Git就會(huì)新建一個(gè)指針dev揩页,并指向master指向的內(nèi)容,并且把HEAD指向dev烹俗,表示dev是當(dāng)前使用的分支爆侣。那么此時(shí),我們在工作區(qū)的修改和提交就會(huì)在dev分支上進(jìn)行幢妄,每一次提交兔仰,dev分支就會(huì)向前移動(dòng)一步,而master分支不變蕉鸳。
如果dev分支上的內(nèi)容開發(fā)完畢乎赴,就需要合并兩個(gè)分支,最簡單的方法就是直接將master的指針指向dev分支指向的內(nèi)容潮尝。

實(shí)戰(zhàn)

首先无虚,我們在learngit上創(chuàng)建一個(gè)新的分支:

$ git checkout -b dev
Switched to a new branch 'dev'

然后我們用git branch命令查看當(dāng)前分支:

$ git branch
* dev
  master

其中,*表示的是當(dāng)前的分支衍锚。

然后惯吕,我們修改readme.txt文件诊笤,然后提交:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

然后浴骂,我們切換回master分支:

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

此時(shí),再打開readme.txt文件踢匣,可以看到,我們剛才提交的內(nèi)容不見了:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

現(xiàn)在戈抄,我們把剛才提交的內(nèi)容合并到master分支上:

$ git merge dev
Updating 563fbc4..4fb19e4
Fast-forward
 readme.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

其中离唬,Fast-forward表示快進(jìn)模式,表示當(dāng)前的合并非郴耄快输莺。

此時(shí),readme.txt的內(nèi)容變成了:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

此時(shí)裸诽,dev分支的任務(wù)完成了嫂用,我們就可以刪除dev分支了:

$ git branch -d dev
Deleted branch dev (was 4fb19e4).

此時(shí),查看剩余分支丈冬,只剩下了master分支了:

$ git branch
* master

關(guān)于分支的一些命令:

  • 查看分支:git branch

  • 創(chuàng)建分支:git branch <name>

  • 切換分支:git checkout <name>

  • 創(chuàng)建+切換分支:git checkout -b <name>

  • 合并某分支到當(dāng)前分支:git merge <name>

  • 刪除分支:git branch -d <name>

解決沖突

上述情況是在理想的情況下可以進(jìn)行嘱函,那么如果master分支和dev分支都對readme.txt文件進(jìn)行了修改,那么如何解決沖突呢埂蕊?

首先往弓,我們新建一個(gè)分支feature1:

$ git checkout -b feature1
Switched to a new branch 'feature1'

然后,我們修改readme.txt文件如下蓄氧,并提交:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

I am FEATURE1 branch.

然后函似,切換到master分支上:

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

Your branch is ahead of 'origin/master' by 1 commit.這一句是git提示我們,我們本地的版本比遠(yuǎn)程倉庫的版本還要新一個(gè)版本喉童。

然后撇寞,我們把readme.txt最后一行也改動(dòng)如下,并提交:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

I am MASTER branch.

此時(shí)泄朴,我們嘗試著將兩個(gè)分支合并:

$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

此時(shí)重抖,Git告訴我們露氮,有沖突發(fā)生了祖灰!我們可以通過 git status查看發(fā)生沖突的文件:

On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   readme.txt

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

如上提示,readme.txt發(fā)生了沖突畔规。

現(xiàn)在局扶,我們查看readme.txt的內(nèi)容:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

<<<<<<< HEAD
I am MASTER branch.
=======
I am FEATURE1 branch.
>>>>>>> feature1

Git用<<<<<<<=======叁扫,>>>>>>>標(biāo)記出不同分支的內(nèi)容三妈,我們修改如下后保存:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)

此時(shí),合并工作完成了莫绣,我們可以刪除feature1分支了畴蒲。

遠(yuǎn)程倉庫版本回退

前面介紹了git checkoutgit reset兩種回退方法,其中git checkout是用來撤銷本地工作區(qū)的內(nèi)容对室,而git reset可以撤銷本地暫存區(qū)的內(nèi)容和本地版本庫的內(nèi)容模燥。
其實(shí)git reset也同樣可以用來撤銷遠(yuǎn)程倉庫的版本咖祭,我們只需要在本地將版本回退到我們需要的版本,然后git push到遠(yuǎn)程倉庫就行蔫骂,但是這樣做的時(shí)候么翰,往往會(huì)報(bào)如下的錯(cuò)誤提示:

$ git push origin master
To github.com:XXX/learngit.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:XXX/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

其中,Updates were rejected because the tip of your current branch is behind提示我們本地代碼的版本比遠(yuǎn)程的版本要低辽旋,我們通過git diff 本地分支名 遠(yuǎn)程倉庫名/遠(yuǎn)程分支名git diff master origin/master)就能看出區(qū)別浩嫌,這時(shí),我們只要使用強(qiáng)制推送就可以成功了:

$ git push origin master --force
Total 0 (delta 0), reused 0 (delta 0)
To github.com:TokyoAndroid/learngit.git
 + a1dcb7a...f631cdb master -> master (forced update)

但是补胚,這樣做非常不推薦码耐。因?yàn)檫@樣會(huì)直接將我們提交版本之后的所有提交都給刪除,這樣在多人協(xié)作開發(fā)的時(shí)候會(huì)給其他人帶來很大的困惑糖儡!

因此伐坏,我們還可以使用另一種版本回退命令git revertgit revert也是將我們指定的某一個(gè)版本撤銷握联,但不會(huì)刪除該版本后續(xù)的提交信息桦沉,只是在最新的提交上面新建一個(gè)提交,這個(gè)新建提交的內(nèi)容就是撤銷掉我們指定版本的提交金闽。
聽起來有點(diǎn)繞纯露,我們舉例來說明:
首先,我們在readme.txt文件后面增加一句AAAAA并提交代芜,然后我們在后面再增加一句BBBBB再提交埠褪,然后我們在后面再增加一句CCCCC再提交:

$ git add readme.txt
$ git commit -m "add AAAAA"

$ git add readme.txt
$ git commit -m "add BBBBB"

$ git add readme.txt
$ git commit -m "add CCCCC"

通過git log命令,我們可以看到當(dāng)前我們有三次提交記錄:

$ git log --oneline
fb3527b (HEAD -> master) add CCCCC
4369360 add BBBBB
c591acb add AAAAA
...

此時(shí)挤庇,如果我們想要撤銷掉最后一次提交钞速,也就是commit id為fb3527b的這次,我們可以使用命令git revert來實(shí)現(xiàn):

$ git revert fb3527B
[master 9494e61] Revert "add CCCCC"
 1 file changed, 1 insertion(+), 2 deletions(-)

此時(shí)嫡秕,我們再用git log查看提交記錄:

$ git log --oneline
9494e61 (HEAD -> master) Revert "add CCCCC"
fb3527b add CCCCC
4369360 add BBBBB
c591acb add AAAAA
...

可以看到渴语,fb3527b的這次提交信息還在,只是在此基礎(chǔ)上新增了一個(gè)提交昆咽,然后驾凶,我們再通過命令git push便可以將這次修改推送到遠(yuǎn)程倉庫中了。
如果你只想撤銷本次提交掷酗,而不想再次提交的話调违,可以使用命令git revert <commit-id> --no-commit來實(shí)現(xiàn)。

如果我們想要撤銷某一次的版本泻轰,也可以使用此命令來實(shí)現(xiàn)技肩,比如,我們先回到fb3527b之前的版本浮声,現(xiàn)在去撤銷4369360的版本(注意虚婿,由于4369360這個(gè)提交是提交的add BBBBB的操作殖告,因此撤銷到這個(gè)提交之前的內(nèi)容是只有AAAAA):

$ git reset --hard fb3527
HEAD is now at fb3527b add CCCCC

$ git log --oneline
fb3527b (HEAD -> master) add CCCCC
4369360 add BBBBB
c591acb add AAAAA
...

$ git revert 4369360
error: could not revert 4369360... add BBBBB
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

撤銷失敗,因?yàn)橛袥_突雳锋,我們需要先解決沖突黄绩,打開readme.txt文件:

...

<<<<<<< HEAD
AAAAA
BBBBB
CCCCC
=======
AAAAA
>>>>>>> parent of 4369360... add BBBBB

如上可以看見,當(dāng)前的內(nèi)容是:

AAAAA
BBBBB
CCCCC

撤銷到4369360之前的內(nèi)容是:

AAAAA

此時(shí)玷过,我們解決沖突爽丹,將文本改成這樣:

AAAAA
after Revert 
BBBBB
CCCCC

然后重新git addgit commit來提交修改并推送到遠(yuǎn)程倉庫:

$ git add readme.txt

$ git commit -m "Revert add BBBBB"
[master 233a610] Revert add BBBBB
 1 file changed, 2 insertions(+), 1 deletion(-)

$ git log --oneline
233a610 (HEAD -> master) Revert add BBBBB
fb3527b add CCCCC
4369360 add BBBBB
c591acb add AAAAA
...

$ git push origin master
Counting objects: 12, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 998 bytes | 0 bytes/s, done.
Total 12 (delta 8), reused 0 (delta 0)
remote: Resolving deltas: 100% (8/8), completed with 2 local objects.
To github.com:XXX/learngit.git
   f631cdb..233a610  master -> master

分支管理策略

通常,合并分支時(shí)辛蚊,如果可能粤蝎,Git會(huì)用Fast forward模式,但這種模式下袋马,刪除分支后初澎,會(huì)丟掉分支信息。

如果要強(qiáng)制禁用Fast forward模式虑凛,Git就會(huì)在merge時(shí)生成一個(gè)新的commit碑宴,這樣,從分支歷史上就可以看出分支信息桑谍。

我們新建一個(gè)分支dev并修改后提交延柠,然后切換到master分支,合并dev锣披,此時(shí)我們禁用掉Fast forward模式:

$ git merge --no-ff -m "merge dev with no of" dev
Merge made by the 'recursive' strategy.
 readme.txt | 2 ++
 1 file changed, 2 insertions(+)

其中贞间,--no-ff表示禁掉Fast forward模式,后面的-m "merge dev with no of"是由于我們本次的merge會(huì)生成一個(gè)新的提交雹仿,因此需要寫上提交的信息增热。
這時(shí),我們用git log命令查看本次的分支歷史:

$ git log --graph --pretty=oneline --abbrev-commit
*   276bfb7 (HEAD -> master) merge dev with no of
|\
| * 41c356f (dev) test no off fast forward
|/
*   1cd720d  modify by master 1
|\
| * d49f6d7 modify by feature1
* | 1cf5452 modify by master
|/
* 4fb19e4 add a new branch
* 563fbc4 (origin/master) add test.txt 2 d^Z
* d91c29b delete text.txt
* 5188978 add test.txt
* 47045f4 eight modify
* 9eaa421 six modify
* ea3fc04 add two lines
* 7126739 understand how stage works
* 0440b0f add No.
* 6a32611 add Yes
* 93b4ff1 create a readme file

緊急情況(Bug分支)

假如我現(xiàn)在在dev分支上干活胧辽,工作進(jìn)行了一半峻仇,還沒有辦法合入master分支中,但此時(shí)master上有一個(gè)緊急bug需要修改票顾,如果此時(shí)合入我們未完成的內(nèi)容础浮,則可能導(dǎo)致master分支不穩(wěn)定帆调,而如果不合入我們的修改而直接切回master分支時(shí)奠骄,我們的修改內(nèi)容也會(huì)跟著被帶到master分支上,并且master分支提交時(shí)番刊,也會(huì)將我們在dev分支上的內(nèi)容提交:

$ git checkout master
Switched to branch 'master'
M       readme.txt

其中含鳞,M readme.txt中的M表示在dev分支上有修改并且沒有提交的內(nèi)容被帶到了master分支上。

總之這兩種方式都會(huì)對代碼造成影響芹务,那么此時(shí)如何解決呢蝉绷?

還好鸭廷,Git給我們提供了一個(gè)命令git stash,用來解決這種情況熔吗。

首先我們修改dev分支下的readme.txt文件辆床,但是并不add,同時(shí)新建一個(gè)文件testStash.txt并add桅狠,這樣讼载,我們在dev分支有兩個(gè)文件的修改,其中一個(gè)add了中跌,另一個(gè)沒有咨堤,這樣,是否add的情況我們都考慮到了:

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

        new file:   testStash.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

現(xiàn)在漩符,我們需要在master分支上拉取一個(gè)緊急分支bug101來解決這個(gè)編號為101的Bug一喘,那么我們先執(zhí)行git stash將我們在dev分支上的工作現(xiàn)場給“隱藏”起來:

$ git stash
Saved working directory and index state WIP on dev: 276bfb7 merge dev with no of

通過命令git status查看當(dāng)前dev分支上的工作內(nèi)容確實(shí)已經(jīng)被隱藏起來了:

$ git status
On branch dev
nothing to commit, working tree clean

并且learngit目錄下的testStash.txt文件已經(jīng)不見了,readme.txt上的修改也消失了嗜暴。

然后我們切換到master分支上去拉取一個(gè)新的分支:

$ git checkout -b bug101
Switched to a new branch 'bug101'

現(xiàn)在凸克,我們把readme.txt內(nèi)的內(nèi)容后面增加一行并提交:

We don't talk anymore.  Yes.
Like we used to do. No.
Now You See Me.
Add new Line.

Add a new Branch.

I am MASTER&FEATURE1 branch.

I am Fast forward.

Bug is over.

然后切換到master分支上,合并bug101分支上的內(nèi)容闷沥,并刪除bug101分支:

$ git merge --no-ff -m "merge bug101 resolve bug" bug101
Merge made by the 'recursive' strategy.
 readme.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git branch -d bug101
Deleted branch bug101 (was c1e5ce5).

Bug修復(fù)完畢后触徐,重新切換到dev分支完成任務(wù),這時(shí)dev分支時(shí)干凈的狐赡,我們需要恢復(fù)上次的工作現(xiàn)場撞鹉,輸入命令git stash list命令查看工作現(xiàn)場:

$ git stash pop
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   testStash.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} (e9413549106498377c06d20c48df660040ab260b)

可以看見,我們的testStash.txt又回來了颖侄!

同時(shí)鸟雏,我們用命令git stash list查看隱藏的工作現(xiàn)場,發(fā)現(xiàn)已經(jīng)沒有了:

$ git stash list

這是git stash pop的用法览祖,它會(huì)在恢復(fù)現(xiàn)場的同時(shí)孝鹊,將隱藏的工作現(xiàn)場都給刪除;還有一種用法是使用命令git stash apply來恢復(fù)展蒂,但是恢復(fù)后又活,隱藏的工作現(xiàn)場都不會(huì)刪除,你需要調(diào)用git stash drop來刪除锰悼。
首先用命令git stash apply stash@{0}恢復(fù)工作現(xiàn)場:

$ git stash apply stash@{0}
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   testStash.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 list查看是否隱藏的工作現(xiàn)場還存在:

$ git stash list
stash@{0}: WIP on dev: 276bfb7 merge dev with no of

然后使用命令git stash drop來刪除隱藏的工作現(xiàn)場:

$ git stash drop stash@{0}
Dropped stash@{0} (003664b3a57eb40941908e6a7fddffe7a7b3b1b9)

再用命令git stash list查看柳骄,發(fā)現(xiàn)隱藏的工作現(xiàn)場已經(jīng)沒有了。

強(qiáng)行刪除分支

如果我們在dev分支上拉取一個(gè)新分支dev1去開發(fā)新功能箕般,開發(fā)完畢并且提交后耐薯,切換回dev分支準(zhǔn)備進(jìn)行合并分支,此時(shí)如果突然不想要這個(gè)新功能了,那么我們就要去銷毀這個(gè)分支曲初,當(dāng)我們執(zhí)行銷毀dev1分支命令時(shí)体谒,會(huì)出現(xiàn)以下的情況:

$ git branch -d dev1
error: The branch 'dev1' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev1'.

刪除失敗,但是Git會(huì)友情提示我們臼婆,如果要?jiǎng)h除抒痒,會(huì)丟失所有修改,并且使用-D參數(shù)颁褂,現(xiàn)在我們用此參數(shù)來刪除dev1分支:

$ git branch -D dev1
Deleted branch dev1 (was a74fcdb).

多人協(xié)作

當(dāng)我們本地倉庫和遠(yuǎn)程倉庫對應(yīng)起來后评汰,我們可以通過git remotegit remote -v來查看遠(yuǎn)程庫的信息。

我們可以使用命令git push origin master來將本地master分支推送到遠(yuǎn)程倉庫origin分支痢虹,如果要推送到其他分支被去,則可以使用命令git push origin dev推送到dev分支上。

至于哪些分支需要同步奖唯,則要視項(xiàng)目情況而論惨缆,一般master分支和dev分支一般都是必須要時(shí)刻保持同步的。

抓取分支

當(dāng)另一個(gè)開發(fā)人員從我們的learngit倉庫clone代碼到本地時(shí)丰捷,他只能看到master分支坯墨,而無法看到dev分支。
然后病往,他需要在dev分支開發(fā)的話捣染,就需要新建一個(gè)dev分支,現(xiàn)在停巷,他新建了一個(gè)dev分支耍攘,并新建了一個(gè)newDev.txt文件,里面只有一句話:

James newDev.

并推送到了遠(yuǎn)程倉庫:

$ git push origin dev
Counting objects: 2, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 242 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:XXX/learngit.git
 * [new branch]      dev -> dev

同時(shí)畔勤,碰巧我們在dev分支下也創(chuàng)建了一個(gè)newDev.txt文件蕾各,并且有一句話是Master newDev.
當(dāng)我們將這個(gè)新建的文件也推送到遠(yuǎn)程倉庫時(shí)就會(huì)因?yàn)闆_突而報(bào)錯(cuò):

$ git push origin dev
To github.com:TokyoAndroid/learngit.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'git@github.com:TokyoAndroid/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

其中庆揪,hint: (e.g., 'git pull ...') before pushing again.提示我們先git pull遠(yuǎn)程代碼后再git push式曲。
執(zhí)行此操作,同樣也報(bào)錯(cuò):

$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 2), reused 4 (delta 1), pack-reused 0
Unpacking objects: 100% (5/5), done.
From github.com:TokyoAndroid/learngit
 * [new branch]      dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> dev

根據(jù)There is no tracking information for the current branch.我們知道這是因?yàn)闆]有指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接缸榛,根據(jù)提示吝羞,設(shè)置devorigin/dev的鏈接,同樣最后一句也給出了鏈接的命令git branch --set-upstream-to=origin/<branch> dev内颗。

$ git branch --set-upstream-to=origin/dev dev
Branch dev set up to track remote branch dev from origin.

然后再一次pull

$ git pull
Auto-merging newDev.txt
CONFLICT (add/add): Merge conflict in newDev.txt
Automatic merge failed; fix conflicts and then commit the result.

這次pull成功钧排,但是有沖突,我們需要解決沖突(解決方法和上面的解決方式完全一樣)起暮,并且提交后卖氨,再git push

$ git push origin dev
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 837 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To github.com:XXX/learngit.git
   4018c1b..c5e7d93  dev -> dev

這次,就成功了负懦。

補(bǔ)充:在本地創(chuàng)建和遠(yuǎn)程倉庫對應(yīng)的分支時(shí)筒捺,可以使用如下命令:

$ git checkout -b <branch-name> origin/<branch-name>

Git補(bǔ)充功能

設(shè)置命令顏色

給Git設(shè)置命令顏色,使我們的命令輸出更醒目:

$ git config --global color.ui true

設(shè)置忽略文件

比如有些文件需要放在Git倉庫目錄下纸厉,但是又不需要提交到Git的系吭,可以新建一個(gè)名稱為.gitignore的文件,然后把你不想要被提交的文件添加進(jìn)去颗品。很多開發(fā)語言的忽略文件都已經(jīng)寫好了:忽略文件肯尺,我們只需要再往里面添加自己想要添加的就可以了。

設(shè)置別名

比如我覺得輸入git status太麻煩躯枢,想簡化成git st行嗎则吟?當(dāng)然可以,給git status配置別名:

$ git config --global alias.st status

標(biāo)簽

當(dāng)我們需要一個(gè)指定的版本的時(shí)候锄蹂,通常需要這個(gè)版本的commit id氓仲,但是commit id我們一般記不住,則我們可以使用git tag給某個(gè)版本打上一個(gè)標(biāo)簽得糜。commit id和tag的關(guān)系類似于網(wǎng)站的IP地址和域名的關(guān)系敬扛。

給當(dāng)前版本打上tag:

$ git tag v1.0

給歷史版本打上標(biāo)簽,先找到commit id朝抖,再打標(biāo)簽(給resolve bug101這個(gè)版本打上標(biāo)簽):

$ git log --pretty=oneline --abbrev-commit
5a92d6b (HEAD -> master, tag: v1.0, origin/master) merge dev stash
b19befc commit dev modify
9e374a8 merge bug101 resolve bug
c1e5ce5 resolve bug101
4bcf5a8 test dev no add
276bfb7 merge dev with no of
41c356f test no off fast forward
1cd720d  modify by master 1
1cf5452 modify by master
d49f6d7 modify by feature1
4fb19e4 add a new branch
563fbc4 add test.txt 2 d^Z
d91c29b delete text.txt
5188978 add test.txt
47045f4 eight modify
9eaa421 six modify
ea3fc04 add two lines
7126739 understand how stage works
0440b0f add No.
6a32611 add Yes
93b4ff1 create a readme file

$ git tag v0.9 c1e5ce5

查看標(biāo)簽:

$ git tag
v0.9
v1.0

查看具體標(biāo)簽對應(yīng)的版本提交信息:

$ git show v0.9
commit c1e5ce59eccf9253d7adfab0facad8faab2c9919 (tag: v0.9)
Author: TokyoZ <344738736@qq.com>
Date:   Sat Jul 28 21:37:58 2018 +0800

    resolve bug101

diff --git a/readme.txt b/readme.txt
index 110244a..81560d3 100644
--- a/readme.txt
+++ b/readme.txt
@@ -9,4 +9,4 @@ I am MASTER&FEATURE1 branch.

 I am Fast forward.

-I am dev.
\ No newline at end of file
+Bug is over.
\ No newline at end of file

刪除標(biāo)簽:

$ git tag -d v0.9
Deleted tag 'v0.9' (was c1e5ce5)

推送標(biāo)簽到遠(yuǎn)程倉庫:

$ git push origin v0.9
Total 0 (delta 0), reused 0 (delta 0)
To github.com:XXX/learngit.git

  • [new tag] v0.9 -> v0.9

刪除遠(yuǎn)程標(biāo)簽:
需要先刪除本地標(biāo)簽啥箭,再用命令git push origin :refs/tags/<tag-name>刪除遠(yuǎn)程標(biāo)簽:

$ git tag -d v0.9
Deleted tag 'v0.9' (was c1e5ce5)

$ git push origin :refs/tags/v0.9
To github.com:XXX/learngit.git
 - [deleted]         v0.9

參考資料

廖雪峰的官方網(wǎng)站-Git教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市治宣,隨后出現(xiàn)的幾起案子急侥,更是在濱河造成了極大的恐慌,老刑警劉巖侮邀,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缆巧,死亡現(xiàn)場離奇詭異,居然都是意外死亡豌拙,警方通過查閱死者的電腦和手機(jī)陕悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來按傅,“玉大人捉超,你說我怎么就攤上這事∥ㄉ埽” “怎么了拼岳?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長况芒。 經(jīng)常有香客問我惜纸,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任耐版,我火速辦了婚禮祠够,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粪牲。我一直安慰自己古瓤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布腺阳。 她就那樣靜靜地躺著落君,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亭引。 梳的紋絲不亂的頭發(fā)上绎速,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音焙蚓,去河邊找鬼朝氓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛主届,可吹牛的內(nèi)容都是我干的赵哲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼君丁,長吁一口氣:“原來是場噩夢啊……” “哼枫夺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绘闷,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤橡庞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后印蔗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扒最,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年华嘹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吧趣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耙厚,死狀恐怖强挫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情薛躬,我是刑警寧澤俯渤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站型宝,受9級特大地震影響八匠,放射性物質(zhì)發(fā)生泄漏絮爷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一梨树、第九天 我趴在偏房一處隱蔽的房頂上張望坑夯。 院中可真熱鬧,春花似錦劝萤、人聲如沸渊涝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胸私,卻和暖如春厌处,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背岁疼。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工阔涉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捷绒。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓瑰排,卻偏偏與公主長得像,于是被迫代替她去往敵國和親暖侨。 傳聞我的和親對象是個(gè)殘疾皇子椭住,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1.git的安裝 1.1 在Windows上安裝Git msysgit是Windows版的Git,從https:/...
    落魂灬閱讀 12,649評論 4 54
  • Git常用語法 [TOC] Git簡介 描述 ? Git(讀音為/g?t/字逗。)是一個(gè)開源的分布式版本控制系統(tǒng)京郑,...
    君惜丶閱讀 3,497評論 0 13
  • 1、一起小心肝葫掉!我國每年約有42.2萬人死于肝癌些举,占全球肝癌死亡病例數(shù)的51%。(人民日報(bào)) 2俭厚、據(jù)中央氣象臺(tái)户魏,受...
    財(cái)知道閱讀 208評論 0 0
  • 真正的強(qiáng)者 不是沒有眼淚的人 而是含著眼淚奔跑的人
    W王霞閱讀 69評論 0 0
  • 何必去爭绪抛,何必去吵,擇一處佳境电禀,孤獨(dú)終老幢码。
    曲文影閱讀 202評論 0 0