安裝Git
Git的下載地址:Git官網(wǎng)下載地址
Git本地倉庫和命令
配置用戶
下載完Git后,右鍵會(huì)有一個(gè)Git Bash here
的選項(xiàng)褪尝,點(diǎn)擊后會(huì)彈出一個(gè)類似于命令行的窗口:
在此輸入此命令配置用戶名和郵箱:
$ 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 add
將readme.txt
添加到倉庫:
Administrator@XXX MINGW64 /e/git/learngit (master)
$ git add readme.txt
(2)使用明明git commit
將readme.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è)窗口提示我們輸入為什么要合入本次修改:
此時(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
文件:
create a readme file
add Yes
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ū)修改的內(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)就變成了:
然后執(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í),倉庫變成這樣:
補(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 add
和git 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_rsa
和id_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地址:
然后我們在本地的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
文件艘希。
新的倉庫建完之后,我們可以在此倉庫的頁面找到一個(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 -> master
中HEAD
是表示當(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 checkout
和git 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 revert
。git 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 add
和git 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 remote
或git 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è)置dev
和origin/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