Git工具
選擇修訂版本
Git能夠以多種方式來(lái)指定單個(gè)提交、一組提交或者是一定范圍內(nèi)的提交。
單個(gè)修訂版本
可以通過(guò)任意一個(gè)提交時(shí)生成的40個(gè)字符的完整SHA-1散列值來(lái)指定一個(gè)提交。
簡(jiǎn)短的SHA-1
通常,Git中,使用一部分的SHA-1散列值就能夠唯一確定一個(gè)提交記錄,我們?cè)?code>git log中加上--abbrev-commit選項(xiàng)就可以為每一個(gè)提交顯示簡(jiǎn)短的唯一散列值。例如
$ git log --abbrev-commit --pretty=oneline
67520cb (HEAD -> master) 新建一個(gè)hello.c文件
分支引用
-
我們還可以直接使用分支名來(lái)指定一個(gè)提交記錄,這時(shí)候,分支名指定的記錄就是分支指針當(dāng)前指向的最新提交記錄。例如
$ git show master commit 67520cb3fac87c26c2eb11b501c151c993b95c30 (HEAD -> master) Author: Square John <1042009398@qq.com> Date: Sat May 30 16:37:20 2020 +0800 新建一個(gè)hello.c文件 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3110669 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +a.exe \ No newline at end of file diff --git a/hello.c b/hello.c new file mode 100644 index 0000000..852836c --- /dev/null +++ b/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main(void){ + + printf("Hello World\n"); + return 0; +}
-
我們還可以使用
rev-parse工具獲取一個(gè)分支當(dāng)前所指向的提交記錄的SHA-1值。例如$ git rev-parse master 67520cb3fac87c26c2eb11b501c151c993b95c30
引用日志
-
當(dāng)我們?cè)诠ぷ鲿r(shí),Git會(huì)在后臺(tái)保存一個(gè)引用日志(==reflog==),引用日志保存了我們近幾個(gè)月來(lái)的==HAED==和分支指針?biāo)赶虻臍v史。因此我們可以使用
git reflog來(lái)查看引用日志,例如$ git reflog 67520cb (HEAD -> master) HEAD@{0}: commit (initial): 新建一個(gè)hello.c文件
每當(dāng)我們的==HEAD==指針的指向發(fā)生了變化,Git就會(huì)將這個(gè)信息存儲(chǔ)在引用日志這個(gè)歷史記錄里。我們可以通過(guò)引用日志數(shù)據(jù)來(lái)獲取之前的提交歷史。
-
如果我們想要查看HEAD最近的5次之前所指向的提交記錄(也就是倒著往回?cái)?shù)第6次的提交記錄,我們可以使用
@{5}來(lái)引用reflog中輸出的提交記錄。例如$ git reflog a5d2b56 (HEAD -> master) HEAD@{0}: commit: 添加一行'Hello C' b1fc8a9 HEAD@{1}: commit: 將換行符作為單獨(dú)一行輸出 67520cb HEAD@{2}: commit (initial): 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git show HEAD@{1} commit b1fc8a98292d9a97d786732d3fa575475348f5f9 Author: Square John <1042009398@qq.com> Date: Sun May 31 09:44:57 2020 +0800 將換行符作為單獨(dú)一行輸出 diff --git a/hello.c b/hello.c index 852836c..e04f5f2 100644 --- a/hello.c +++ b/hello.c @@ -2,6 +2,7 @@ int main(void){ - printf("Hello World\n"); + printf("Hello World"); + printf("\n); return 0; }- 該命令實(shí)際上就是輸出
reflog日志中的相應(yīng)的第HEAD@{n}次記錄
- 該命令實(shí)際上就是輸出
-
我們同樣可以使用這樣的語(yǔ)法來(lái)查看某一個(gè)分支在指定時(shí)間前的位置。例如
$ git show master@{yesterday} warning: log for 'master' only goes back to Sat, 30 May 2020 16:37:20 +0800 commit 67520cb3fac87c26c2eb11b501c151c993b95c30 Author: Square John <1042009398@qq.com> Date: Sat May 30 16:37:20 2020 +0800 新建一個(gè)hello.c文件 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3110669 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +a.exe \ No newline at end of file diff --git a/hello.c b/hello.c new file mode 100644 index 0000000..852836c --- /dev/null +++ b/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int main(void){ + + printf("Hello World\n"); + return 0; +}
-
可以使用
git log -g來(lái)查看類似于git log輸出格式的引用日志信息。例如$ git log -g master commit a5d2b563e6ffa56ef36383d4a1eb7bb5b690d1a1 (HEAD -> master) Reflog: master@{0} (Square John <1042009398@qq.com>) Reflog message: commit: 添加一行'Hello C' Author: Square John <1042009398@qq.com> Date: Sun May 31 09:49:11 2020 +0800 添加一行'Hello C' commit b1fc8a98292d9a97d786732d3fa575475348f5f9 Reflog: master@{1} (Square John <1042009398@qq.com>) Reflog message: commit: 將換行符作為單獨(dú)一行輸出 Author: Square John <1042009398@qq.com> Date: Sun May 31 09:44:57 2020 +0800 將換行符作為單獨(dú)一行輸出 commit 67520cb3fac87c26c2eb11b501c151c993b95c30 Reflog: master@{2} (Square John <1042009398@qq.com>) Reflog message: commit (initial): 新建一個(gè)hello.c文件 Author: Square John <1042009398@qq.com> Date: Sat May 30 16:37:20 2020 +0800 新建一個(gè)hello.c文件- 如果不指定后面的分支名,就默認(rèn)為輸出當(dāng)前分支的引用日志信息
-
注意:
- 引用日志只存在于本地倉(cāng)庫(kù),它只是一個(gè)記錄我們?cè)谧约旱膫}(cāng)庫(kù)里做過(guò)什么的日志
- 其他人拷貝的倉(cāng)庫(kù)里的引用日志不會(huì)和我們的相同
- 如果我們剛剛新克隆了一個(gè)倉(cāng)庫(kù),那么我們克隆所得的本地庫(kù)中的引用日志是空的,因?yàn)槲覀冊(cè)谶@個(gè)倉(cāng)庫(kù)里面還沒(méi)有任何操作
-
git show HEAD@{two.month.ago}這一條命令只有當(dāng)我們的本地倉(cāng)庫(kù)至少已經(jīng)存在了兩個(gè)月才能夠顯示匹配的提交
祖先引用
祖先引用是另一種指明一個(gè)提交的方式。
-
如果我們?cè)谝玫暮竺婕由弦粋€(gè)
^(脫字符),Git就會(huì)將其解析為該引用的上一個(gè)提交。例如$ git log --oneline a5d2b56 (HEAD -> master) 添加一行'Hello C' b1fc8a9 將換行符作為單獨(dú)一行輸出 67520cb 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git show HEAD^ commit b1fc8a98292d9a97d786732d3fa575475348f5f9 Author: Square John <1042009398@qq.com> Date: Sun May 31 09:44:57 2020 +0800 將換行符作為單獨(dú)一行輸出 diff --git a/hello.c b/hello.c index 852836c..e04f5f2 100644 --- a/hello.c +++ b/hello.c @@ -2,6 +2,7 @@ int main(void){ - printf("Hello World\n"); + printf("Hello World"); + printf("\n); return 0; }- 結(jié)果就是==b1fc8a9 將換行符作為單獨(dú)一行輸出==這一個(gè)提交記錄
-
在==Windows==的
cmd中^是一個(gè)特殊字符,應(yīng)該這樣做$ git show HEAD^ #error $ git show "HEAD^" #ok $ git show HEAD^^ #ok
-
我們還可以在
^后面跟上一個(gè)數(shù)字指明我們想要的父提交。但是這種做法只適用于有多個(gè)父提交合并提交。例如$ git log --oneline --graph --all * 25dd4cc (HEAD -> master) Merge branch 'newbranch' |\ | * 35241b9 (newbranch) 為readme文件新增了一行 * | 14e9ff1 刪除了打印hello world這一行 |/ * 2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤 * 62ed47d 新增一個(gè)readme文件 * a5d2b56 添加一行'Hello C' * b1fc8a9 將換行符作為單獨(dú)一行輸出 * 67520cb 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git show HEAD^2 commit 35241b91e2957c7dc9c22b47f0c394d473215c3a (newbranch) Author: Square John <1042009398@qq.com> Date: Sun May 31 10:43:26 2020 +0800 為readme文件新增了一行 diff --git a/readme b/readme index b34569e..6638245 100644 --- a/readme +++ b/readme @@ -1 +1,2 @@ 這是一個(gè)說(shuō)明文檔 +用于說(shuō)明一些問(wèn)題-
HEAD^2就是newbranch中的==35241b9==這一個(gè)提交記錄,也就是HEAD的第二個(gè)父提交
-
另一種指明祖先提交的方法是在引用的后面加一個(gè)
~號(hào),HEAD~和HEAD^一樣,都是指向HEAD的第一個(gè)父提交。但是HEAD~2表示的卻是HEAD的第一個(gè)父提交的第一個(gè)父提交。對(duì)于HEAD~3,那就是HEAD的第一個(gè)父提交的第一個(gè)父提交的父提交,其余以此類推。其實(shí)HEAD~3也可以這樣表示HEAD~~~^和~還可以進(jìn)行組合。例如HEAD~2^2就表示HEAD的第一個(gè)父提交的第一個(gè)父提交的第二個(gè)父提交
提交區(qū)間
雙點(diǎn)
最常用的指明提交區(qū)間的語(yǔ)法是雙點(diǎn),這種語(yǔ)法可以選出在一個(gè)分支中但是不在另一個(gè)分支中的提交歷史
-
例如
$ git log --graph --oneline --all * 7c3bc83 (HEAD -> master) 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 * 25dd4cc Merge branch 'newbranch' |\ * | 14e9ff1 刪除了打印hello world這一行 | | * 95302bd (newbranch) 在readme末尾新加了一行說(shuō)明 | |/ | * 35241b9 為readme文件新增了一行 |/ * 2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤 * 62ed47d 新增一個(gè)readme文件 * a5d2b56 添加一行'Hello C' * b1fc8a9 將換行符作為單獨(dú)一行輸出 * 67520cb 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git log --oneline master..newbranch 95302bd (newbranch) 在readme末尾新加了一行說(shuō)明- 這個(gè)命令選出了在
newbranch分支中但是還沒(méi)有合并到master分支中的提交歷史記錄 - 這樣的語(yǔ)法可以幫助我們即使了解分支的最新情況,以及將要合并的內(nèi)容
- 這個(gè)命令選出了在
-
這個(gè)語(yǔ)法的另外一個(gè)常用的場(chǎng)景就是用于查看我們將要推送到遠(yuǎn)方的內(nèi)容
$ git log origin/master..HEAD- 這個(gè)命令會(huì)輸出在我們當(dāng)前的分支但是不在
origin/master分支的提交歷史 - 如果我們執(zhí)行
git push命令,并且我們當(dāng)前的分支正在跟蹤origin/master分支,則上面的命令所輸出的提交內(nèi)容就是我們將要提交的內(nèi)容 - 如果我們留空了其的一邊,Git會(huì)默認(rèn)為
HEAD,例如git log origin/master..,那么我們也會(huì)得到和上面一致的結(jié)果。Git會(huì)使用HEAD來(lái)代替留空的一邊
- 這個(gè)命令會(huì)輸出在我們當(dāng)前的分支但是不在
多點(diǎn)
? 有時(shí)候我們需要兩個(gè)以上的分支才能確定我們所需要的修訂。比如查看哪些提交是被包含在某些分支中的一個(gè),但是不在當(dāng)前的分支上
-
Git有這樣的語(yǔ)法,在任意引用前加上一個(gè)
^或者是--not用來(lái)指明不包含在指定分支中的提交。例如$ git log --oneline --all --graph * 7c3bc83 (master) 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 * 25dd4cc Merge branch 'newbranch' |\ * | 14e9ff1 刪除了打印hello world這一行 | | * 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 | |/ | * 35241b9 為readme文件新增了一行 |/ * 2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤 * 62ed47d 新增一個(gè)readme文件 * a5d2b56 添加一行'Hello C' * b1fc8a9 將換行符作為單獨(dú)一行輸出 * 67520cb 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (newbranch) $ git log --oneline master..newbranch 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 helloworld@surface MINGW64 ~/Desktop/cpl (newbranch) $ git log --oneline ^master newbranch 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 helloworld@surface MINGW64 ~/Desktop/cpl (newbranch) $ git log --oneline newbranch --not master 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明-
其中這三條命令是等價(jià)的
$ git log --oneline master..newbranch $ git log --oneline ^master newbranch $ git log --oneline newbranch --not master- 列出的都是在
newbranch中但是不在master中的提交歷史
- 列出的都是在
-
但是注意,下面這兩個(gè)命令是不一樣的
$ git log --oneline newbranch --not master $ git log --oneline --not master newbranch- 前者是指,包含在
newbranch中但是不包含在master中的提交記錄 - 后者是不包含在
newbranch以及master中的記錄
- 前者是指,包含在
-
但是下面這兩個(gè)命令是一樣的
$ git log --oneline ^master newbranch $ git lig --oneline newbranch ^master- 都是不在
master中但是在newbranch中的提交記錄
- 都是不在
也就是說(shuō),
--not是對(duì)其后所有的分支的否定,就是其后的分支都不包含的提交記錄。而^只是對(duì)其后緊接著的一個(gè)分支的否定。
-
-
這樣的語(yǔ)法就可以這樣使用
$ git log --oneline ba bb ^bc- 這就表示,包含在
ba和bb中但是不包含在bc中的提交記錄
- 這就表示,包含在
三點(diǎn)
這個(gè)語(yǔ)法可以可以選擇出被兩個(gè)引用之一包含但是又不同時(shí)被二者包含的提交歷史
-
例子如下
$ git log --oneline master...newbranch 7c3bc83 (master) 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 25dd4cc Merge branch 'newbranch' 14e9ff1 刪除了打印hello world這一行- 該命令就列出了所有只在
master或者是newbranch分支中的其中一個(gè)的所有的提交記錄
- 該命令就列出了所有只在
-
在該命令中添加
--left-right選項(xiàng)能夠顯示每一個(gè)提交所屬的分支,這會(huì)讓輸出數(shù)據(jù)更加清晰。例如$ git log --oneline --graph --all * 7c3bc83 (master) 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 * 25dd4cc Merge branch 'newbranch' |\ * | 14e9ff1 刪除了打印hello world這一行 | | * 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 | |/ | * 35241b9 為readme文件新增了一行 |/ * 2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤 * 62ed47d 新增一個(gè)readme文件 * a5d2b56 添加一行'Hello C' * b1fc8a9 將換行符作為單獨(dú)一行輸出 * 67520cb 新建一個(gè)hello.c文件 helloworld@surface MINGW64 ~/Desktop/cpl (newbranch) $ git log --oneline --left-right master...newbranch < 7c3bc83 (master) 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 > 95302bd (HEAD -> newbranch) 在readme末尾新加了一行說(shuō)明 < 25dd4cc Merge branch 'newbranch' < 14e9ff1 刪除了打印hello world這一行
交互式暫存
本節(jié)的幾個(gè)交互式Git可以幫助我們將文件的特定部分組合成提交。當(dāng)我們修改了大量文件之后,希望將這些改動(dòng)能夠拆分為若干個(gè)單獨(dú)的提交而不是混雜在一起成為一個(gè)提交時(shí),這些工具特別有用。
-
在運(yùn)行
git add時(shí)使用-i或者--interactive選項(xiàng),Git會(huì)進(jìn)入一個(gè)交互式終端模式。如下所示$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: hello.c modified: readme Untracked files: (use "git add <file>..." to include in what will be committed) multipleAB.c no changes added to commit (use "git add" and/or "git commit -a") helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git add -i staged unstaged path 1: unchanged +0/-3 hello.c 2: unchanged +1/-0 readme *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>- 該命令會(huì)將已經(jīng)進(jìn)行了跟蹤的文件列出來(lái)分為兩列,其中一列為已暫存狀態(tài)的內(nèi)容的變化(就是對(duì)比本地庫(kù)和暫存區(qū)中的對(duì)應(yīng)文件差別),另外一列為為暫存狀態(tài)的內(nèi)容的變化(也就是對(duì)比工作區(qū)和暫存區(qū)中相應(yīng)的文件的差異)
- 然后我可以使用==Commdans==下面的命令交互式地對(duì)文件進(jìn)行操作
文件的暫存和取消暫存
-
如果我們?cè)?=What now>==之后輸入==2==或者是==u==或者是==update==,接下來(lái)就會(huì)出現(xiàn)如下界面
What now> 2 staged unstaged path 1: unchanged +0/-3 hello.c 2: unchanged +1/-0 readme Update>>- 這時(shí)候它問(wèn)我們需要暫存哪些文件
-
加入我們輸入如下,然后就會(huì)
Update>> 1,2 staged unstaged path * 1: unchanged +0/-3 hello.c * 2: unchanged +1/-0 readme Update>>- 前面打上了==*****==號(hào)的文件表示將要被暫存的文件
-
如果我們?cè)?=Update>>==之后什么也不輸入而是直接回車,就會(huì)把前面帶有==*****==號(hào)的文件進(jìn)行暫存,接著界面就變成下面這樣
updated 2 paths *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>
-
加入我們這個(gè)時(shí)候想要撤銷對(duì)
readme文件的暫存,我們可以輸入==3==或者是==r[evert]==。如下所示What now> 3 staged unstaged path 1: +0/-3 nothing hello.c 2: +1/-0 nothing readme Revert>>
-
這時(shí)候我們就可以選擇要撤銷暫存的文件
Revert>> 2 staged unstaged path 1: +0/-3 nothing hello.c * 2: +1/-0 nothing readme Revert>>- 此時(shí)前面帶有==*****==號(hào)的文件表示將要撤銷暫存的文件
-
和前面一樣,直接回車就可以將上面選擇的文件撤銷暫存
Revert>> reverted 1 path *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>
-
然后選擇==1==或者是==s[tatus]==就可以查看這些已被追蹤文件的狀態(tài)
What now> s staged unstaged path 1: +0/-3 nothing hello.c 2: unchanged +1/-0 readme *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>
-
然后選擇==6==或者是==d[iff]==就可以查看本地庫(kù)中的文件和暫存區(qū)中相應(yīng)的文件的差異,該命令和
git diff --cached效果一樣。首先是出現(xiàn)如下界面,讓我們選擇需要進(jìn)行對(duì)比的文件What now> 6 staged unstaged path 1: +0/-3 nothing hello.c Review diff>>
-
然后我們選擇==1==,結(jié)果如下
Review diff>> 1 diff --git a/hello.c b/hello.c index 0384c93..1f84282 100644 --- a/hello.c +++ b/hello.c @@ -3,8 +3,5 @@ int main(void){ printf("Hello C\n"); - int a = 10; - int b = 20; - printf("%d + %d = %d\n", a, b, a + b); return 0; } *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now>
- 然后選擇==7==或者==q[uit]==退出交互式界面
暫存補(bǔ)丁
如果我們一個(gè)文件的多個(gè)地方進(jìn)行了修改,但是我們只想要暫存其中的一個(gè)修改,那么這個(gè)Git也能輕松做到
-
在上一節(jié)的交互式命令中,選擇==5==或者是==p[atch]==,然后就會(huì)進(jìn)入如下的選擇界面
What now> 5 warning: LF will be replaced by CRLF in multipleAB.c. The file will have its original line endings in your working directory staged unstaged path 1: unchanged +5/-3 multipleAB.c 2: unchanged +2/-0 readme Patch update>>
-
然后選擇相應(yīng)的文件,如下所示
Patch update>> 2 staged unstaged path 1: unchanged +5/-3 multipleAB.c * 2: unchanged +2/-0 readme Patch update>> -
然后回車,進(jìn)入如下界面
Patch update>> diff --git a/readme b/readme index 6638245..7cbb288 100644 --- a/readme +++ b/readme @@ -1,2 +1,4 @@ 這是一個(gè)說(shuō)明文檔 用于說(shuō)明一些問(wèn)題 +就是想添加一行文字 +又添加一行文字 (1/1) Stage this hunk [y,n,q,a,d,e,?]?
-
然后輸入==?==回車就可以看到各個(gè)選項(xiàng)的意義
(1/1) Stage this hunk [y,n,q,a,d,e,?]? ? y - stage this hunk n - do not stage this hunk q - quit; do not stage this hunk or any of the remaining ones a - stage this hunk and all later hunks in the file d - do not stage this hunk or any of the later hunks in the file e - manually edit the current hunk ? - print help @@ -1,2 +1,4 @@ 這是一個(gè)說(shuō)明文檔 用于說(shuō)明一些問(wèn)題 +就是想添加一行文字 +又添加一行文字 (1/1) Stage this hunk [y,n,q,a,d,e,?]?
然后我們可以選擇==y==暫存這部分內(nèi)容,隨后就可以使用==1==來(lái)查看文件的狀態(tài)
實(shí)際上上面這個(gè)功能可以通過(guò)
git add --patch/-p啟動(dòng)
貯藏和清理
- 有時(shí)候我們可能會(huì)在某一個(gè)分支上進(jìn)行了一些工作,做了一些修改,然后想要切換到另外一個(gè)分支進(jìn)行一點(diǎn)工作,但是這個(gè)時(shí)候我們不想要將這些部分的還未完成的工作進(jìn)行提交,我們可以使用
git stash命令 - 貯藏(stash)會(huì)處理工作目錄的臟的狀態(tài),即跟蹤文件的修改和暫存文件的改動(dòng),然后將未完成的修改保存到一個(gè)棧上,隨后我們還可以重新應(yīng)用這些改動(dòng)
貯藏工作
-
先在工作目錄中修改幾個(gè)文件,然后暫存其中的一個(gè),使用
git status查看當(dāng)前倉(cāng)庫(kù)的狀態(tài)$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: newfile Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: readme
-
將新的修改推送到棧上貯藏,使用
git stash或者是git stash push命令$ git stash Saved working directory and index state WIP on master: d414efe 新建了一個(gè)newile文件,并在其中輸入了一行文字- 這時(shí)候會(huì)輸出改動(dòng)的內(nèi)容
-
然后我們?cè)诓榭磦}(cāng)庫(kù)的狀態(tài)
$ git status On branch master nothing to commit, working tree clean- 我們可以看到,倉(cāng)庫(kù)目錄狀態(tài)是干凈的
-
然后我們就可以切換到其他分支上工作了。而如果我們想要查看貯藏的東西,可以執(zhí)行
git stash list命令$ git stash list stash@{0}: WIP on master: d414efe 新建了一個(gè)newile文件,并在其中輸入了一行文字
-
使用
git stash apply命令重新應(yīng)用貯藏$ git stash apply On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: newfile modified: readme no changes added to commit (use "git add" and/or "git commit -a")
如果想要應(yīng)用一個(gè)更舊版本的貯藏,可以使用它的名字指定它,例如
git stash apply stash@{2}。如果不指定,就默認(rèn)使用最新版的貯藏貯藏的內(nèi)容并不一定要應(yīng)用到進(jìn)行貯藏的分支,也不要求應(yīng)用貯藏時(shí)候的目錄是干凈的。但是如果這時(shí)候修改的是剛剛才修改了的文件,這時(shí)候會(huì)產(chǎn)生合并沖突。
我們從上面的結(jié)果可以看到貯藏被重新應(yīng)用了,但是剛才暫存的文件的內(nèi)容被恢復(fù)了但是沒(méi)有被重新暫存
如果我們想要讓剛才已經(jīng)暫存的文件在重新應(yīng)用貯藏之后也被重新暫存,我們可以在
git stash apply之后加上--index選項(xiàng)-
應(yīng)用了貯藏之后,堆棧上依然保留著這個(gè)貯藏的內(nèi)容,我們可以使用
git stash drop <name>刪除指定貯藏內(nèi)容,例如$ git stash list stash@{0}: WIP on master: 7244031 每一個(gè)文件增加了一行數(shù)字2 stash@{1}: WIP on master: 92e51d0 每一個(gè)文件中寫入了一行數(shù)字1 stash@{2}: WIP on master: 1577b44 清空所有文件 stash@{3}: WIP on tempbranch: 91d9942 不知道怎么回事的一個(gè)提交 stash@{4}: WIP on master: d414efe 新建了一個(gè)newile文件,并在其中輸入了一行文字 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git stash drop stash@{4} Dropped stash@{4} (d9d901347cfaa02cebfb55d6fe207a631c3a2ed6) helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git stash list stash@{0}: WIP on master: 7244031 每一個(gè)文件增加了一行數(shù)字2 stash@{1}: WIP on master: 92e51d0 每一個(gè)文件中寫入了一行數(shù)字1 stash@{2}: WIP on master: 1577b44 清空所有文件 stash@{3}: WIP on tempbranch: 91d9942 不知道怎么回事的一個(gè)提交
- 我們還可以使用
git stash pop命令在應(yīng)用貯藏之后立即刪除它
貯藏的創(chuàng)意性使用
-
git stash --keep-index不僅將已暫存的文件主藏起來(lái),還會(huì)將其保留在暫存區(qū)中。例如$ git stash --keep-index Saved working directory and index state WIP on master: 10c1009 為三個(gè)文件增加一行數(shù)字3 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: a.txt
-
默認(rèn)的
git stash不會(huì)將新建的文件貯藏起來(lái),只會(huì)貯藏哪些已經(jīng)跟蹤了的文件,對(duì)于還沒(méi)有跟蹤的文件是不會(huì)貯藏的。例如$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: a.txt modified: newfile modified: readme Untracked files: (use "git add <file>..." to include in what will be committed) b no changes added to commit (use "git add" and/or "git commit -a") helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git stash Saved working directory and index state WIP on master: db19a07 為各個(gè)文件新增一行4 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) b nothing added to commit but untracked files present (use "git add" to track)
-
可以使用
---include-untracked或者是-u選項(xiàng)讓Git的貯藏包含未跟蹤的文件。當(dāng)然這一個(gè)選項(xiàng)依然不會(huì)包含那些被忽略的文件。例如$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: a.txt modified: newfile modified: readme Untracked files: (use "git add <file>..." to include in what will be committed) b no changes added to commit (use "git add" and/or "git commit -a") helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git stash -u warning: LF will be replaced by CRLF in b. The file will have its original line endings in your working directory Saved working directory and index state WIP on master: db19a07 為各個(gè)文件新增一行4 helloworld@surface MINGW64 ~/Desktop/cpl (master) $ git status On branch master nothing to commit, working tree clean
如果想要將忽略的文件也包含其中,可以使用
--all或者是-a選項(xiàng)如果指定了
--patch,Git就不會(huì)貯藏所有的修改,而是進(jìn)入交互式界面讓我們選擇需要進(jìn)行貯藏的部分修改進(jìn)行貯藏
從貯藏創(chuàng)建一個(gè)分支
- 如果我們?cè)谫A藏了一些工作,然后繼續(xù)在貯藏的分支上工作,那之后重新應(yīng)用貯藏的時(shí)候可能就會(huì)出現(xiàn)問(wèn)題。如果應(yīng)用嘗試修改剛剛修改的文件,你會(huì)得到一個(gè)合并沖突并不得不解決它。
- 如果我們想要通過(guò)一個(gè)輕松的方式再次測(cè)試貯藏的改動(dòng),我們可以使用
git stash branch <branchname>命令新建一個(gè)分支,并且會(huì)將貯藏的工作應(yīng)用于這一個(gè)新的分支。我們就可以在應(yīng)用成功后刪除該貯藏的內(nèi)容。 - 這是一個(gè)可以輕松地在一個(gè)新的分支上恢復(fù)貯藏工作并且繼續(xù)進(jìn)行工作的一個(gè)不錯(cuò)的方法。
清理工作目錄
- Git中可以使用
git clean命令來(lái)刪除工作目錄中的一些目錄和文件。 -
git clean命令會(huì)刪除工作目錄中未被追蹤的文件。如果我們改變了主意,我們也不一定能夠找回這些內(nèi)容。 - 一個(gè)更加安全的做法是
git stash --all用來(lái)移除移除每一個(gè)目錄和文件并且存放在棧中。 - 我們可以使用
git clean命令清理冗余文件和工作目錄,使用git clean -f -d命令可以移除工作目錄中所有的未被追蹤的文件以及所有空的子目錄。要使用-f選項(xiàng)要設(shè)置Git中的配置變量clean.requireForce沒(méi)有顯示為false。 - 如果我們只是想看看
git clean命令所做的事情,我們可以使用--dry-run或者是-n選項(xiàng)來(lái)做一次演示操作 - 默認(rèn)情況下,
git clean只會(huì)移除沒(méi)有被忽略的未跟蹤文件。如果想要移除那些被忽略的文件,需要增加一個(gè)-x選項(xiàng) - 還可以使用
-i選項(xiàng)進(jìn)行交互式清理操作。 -
==注意==: 如果我們的工作目錄中復(fù)制了別的倉(cāng)庫(kù),這時(shí)候,我們即使使用
git clean -f -d也不能夠刪除這些目錄。這時(shí)候我們?nèi)绻獎(jiǎng)h除這些目錄,需要加上第二個(gè)-f選項(xiàng)。
搜索
不論倉(cāng)庫(kù)中的代碼量有多少,我們經(jīng)常需要查找一個(gè)函數(shù)是在哪里被調(diào)用和定義的,或者是我們想要了解一個(gè)方法的變更歷史。Git提供了兩個(gè)有用的工具用于快速地從其數(shù)據(jù)庫(kù)中瀏覽代碼和提交。
Git Grep
Git提供了一個(gè)
grep命令,可以方便地從提交歷史、工作目錄甚至是索引中查找一個(gè)字符串或者正則表達(dá)式-
默認(rèn)情況下
git grep命令查找的是我們的工作目錄下的文件。我們可以使用-n或者--line-number選項(xiàng)輸出匹配行的行號(hào)。例如$ git grep -n main hello.c:3:int main(void){ multipleAB.c:3:int main(void){
-
-c或者--count選項(xiàng)用于輸出概述信息。這些信息包括那些包含匹配字符串的文件以及每一個(gè)文件包含了多少匹配。例如$ git grep -c int hello.c:2 multipleAB.c:5
-
如果我們還關(guān)心搜索字符串的上下文,那么可以使用
-p或者是--show-function選項(xiàng)來(lái)顯示每一個(gè)匹配的字符串所在的方法或者函數(shù)。例如$ git grep --show-function int hello.c:int main(void){ hello.c: printf("Hello C\n"); multipleAB.c:int main(void){ multipleAB.c: int a; multipleAB.c: int b; multipleAB.c: printf("輸入兩個(gè)數(shù)\n"); multipleAB.c: printf("%d * %d = %d\n", a, b, a * b);
Git日志搜索
有時(shí)候我們可能并不想知道某一項(xiàng)在哪里,我們更加關(guān)心的是這樣的字符串是什么時(shí)候引入的
git log命令有許多強(qiáng)大的功能可以通過(guò)提交信息甚至是diff的內(nèi)容來(lái)找到某個(gè)特定的提交-
使用
-S選項(xiàng)來(lái)顯示新增和刪除某一個(gè)字符串的提交。例如$ git log -S a --oneline e8d6683 為multipleAB.c源程序添加了交互式輸入的功能 ce7e504 新建一個(gè)multipleAB的c源代碼文件,用于計(jì)算兩個(gè)整數(shù)的乘積 7c3bc83 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 67520cb 新建一個(gè)hello.c文件
- 如果我們想要更加精確的搜索結(jié)果,我們可以使用
-G選項(xiàng)來(lái)使用正則表達(dá)式搜索。
行日志搜索
行日志搜索是另一個(gè)相當(dāng)高級(jí)并且有用的日志搜索功能。在
git log后面跟上-L選項(xiàng)即可調(diào)用,它可以展示代碼中一行或者是一個(gè)函數(shù)的歷史-
例如,如果我們想要查看
main函數(shù)在multipleAB.c中的每一次變更,可以使用如下的命令$ git log -L :main:multipleAB.c commit e8d66837996c4857c25ebd44a8a522918c765388 Author: Square John <1042009398@qq.com> Date: Sun May 31 17:22:05 2020 +0800 為multipleAB.c源程序添加了交互式輸入的功能 diff --git a/multipleAB.c b/multipleAB.c --- a/multipleAB.c +++ b/multipleAB.c @@ -3,6 +3,8 @@ int main(void){ - int a=6; - int b=10; + int a; + int b; + printf("輸入兩個(gè)數(shù)\n"); + scanf("%d %d", &a, &b); printf("%d * %d = %d\n", a, b, a * b); return 0; } commit ce7e50424747351da5ea68108c673163e496c4a4 Author: Square John <1042009398@qq.com> Date: Sun May 31 15:12:37 2020 +0800 新建一個(gè)multipleAB的c源代碼文件,用于計(jì)算兩個(gè)整數(shù)的乘積 diff --git a/multipleAB.c b/multipleAB.c --- /dev/null +++ b/multipleAB.c @@ -0,0 +3,6 @@ +int main(void){ + int a=6; + int b=10; + printf("%d * %d = %d\n", a, b, a * b); + return 0; +}
重寫歷史
- 很多時(shí)候我們可能想要修改我們的提交歷史。這可能涉及到改變提交的順序、改變提交中的信息或者是文件、將提交壓縮或者是拆分,甚至是完全移除提交。
- 我們應(yīng)該注意,我們上面的這些操作都應(yīng)該是在我們將我們進(jìn)行的工作與他人進(jìn)行共享之前在本地進(jìn)行,一旦我們將倉(cāng)庫(kù)的內(nèi)容進(jìn)行了共享,就不應(yīng)該隨便重寫這些提交的歷史
修改最后一次提交
修改我們的最近一次提交可能是所有修改歷史提交操作中最常見(jiàn)的一個(gè)。
對(duì)于我們的最近的一次提交,我們往往想做兩件事:一個(gè)是簡(jiǎn)單地修改提交信息,另外一個(gè)就是通過(guò)添加、移除或者是修改文件更改實(shí)際的提交內(nèi)容。
-
如果只想要修改最近一次的提交信息,我們可以使用
git commit --amend命令。執(zhí)行這個(gè)命令之后,就會(huì)跳轉(zhuǎn)到提交信息編輯界面供我們修改提交信息。-
最后一次提交信息修改前
$ git log --oneline a32930d (HEAD -> master) 為hello.c新增加一行6 db19a07 為各個(gè)文件新增一行4 10c1009 為三個(gè)文件增加一行數(shù)字3 7244031 每一個(gè)文件增加了一行數(shù)字2 92e51d0 每一個(gè)文件中寫入了一行數(shù)字1 1577b44 清空所有文件 d414efe 新建了一個(gè)newile文件,并在其中輸入了一行文字 e8d6683 為multipleAB.c源程序添加了交互式輸入的功能 df951bd 為readme新增加了一行 345fecd 又給a.txt新增加一行 de97888 新增一個(gè)a.txt文件 ce7e504 新建一個(gè)multipleAB的c源代碼文件,用于計(jì)算兩個(gè)整數(shù)的乘積 7c3bc83 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果 25dd4cc Merge branch 'newbranch' 14e9ff1 刪除了打印hello world這一行 35241b9 為readme文件新增了一行 2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤 62ed47d 新增一個(gè)readme文件 a5d2b56 添加一行'Hello C' b1fc8a9 將換行符作為單獨(dú)一行輸出 67520cb 新建一個(gè)hello.c文件
-
- 最后一次提交信息修改之后
```bash
$ git commit --amend
hint: Waiting for your editor to close the file...
[main 2020-06-13T03:07:11.693Z] update#setState idle
[master 81fc22d] 為a.txt新增加一行6
Date: Sat Jun 13 11:06:36 2020 +0800
1 file changed, 2 insertions(+)
helloworld@surface MINGW64 ~/Desktop/cpl (master)
$ git log --oneline
81fc22d (HEAD -> master) 為a.txt新增加一行6
db19a07 為各個(gè)文件新增一行4
10c1009 為三個(gè)文件增加一行數(shù)字3
7244031 每一個(gè)文件增加了一行數(shù)字2
92e51d0 每一個(gè)文件中寫入了一行數(shù)字1
1577b44 清空所有文件
d414efe 新建了一個(gè)newile文件,并在其中輸入了一行文字
e8d6683 為multipleAB.c源程序添加了交互式輸入的功能
df951bd 為readme新增加了一行
345fecd 又給a.txt新增加一行
de97888 新增一個(gè)a.txt文件
ce7e504 新建一個(gè)multipleAB的c源代碼文件,用于計(jì)算兩個(gè)整數(shù)的乘積
7c3bc83 為hello.c添加了一段程序用于求兩個(gè)整數(shù)的相加的結(jié)果
25dd4cc Merge branch 'newbranch'
14e9ff1 刪除了打印hello world這一行
35241b9 為readme文件新增了一行
2b3775c 修改了hello.c文件中的換行符位置錯(cuò)誤
62ed47d 新增一個(gè)readme文件
a5d2b56 添加一行'Hello C'
b1fc8a9 將換行符作為單獨(dú)一行輸出
67520cb 新建一個(gè)hello.c文件
```
-
另一方面,如果我們想要修改最后一次提交的實(shí)際內(nèi)容,其流程如下
先補(bǔ)上想做的修改,
然后暫存它們,
然后使用
git commit --amend命令使用新的提交代替舊的提交-
例如
-
修改前的提交
$ git log --oneline -5 81fc22d (HEAD -> master) 為a.txt新增加一行6 db19a07 為各個(gè)文件新增一行4 10c1009 為三個(gè)文件增加一行數(shù)字3 7244031 每一個(gè)文件增加了一行數(shù)字2 92e51d0 每一個(gè)文件中寫入了一行數(shù)字1
-
- 修改后的提交
```bash
$ git log --oneline -5
8210372 (HEAD -> master) 為a.txt新增加一行6以及新增了一行7
db19a07 為各個(gè)文件新增一行4
10c1009 為三個(gè)文件增加一行數(shù)字3
7244031 每一個(gè)文件增加了一行數(shù)字2
92e51d0 每一個(gè)文件中寫入了一行數(shù)字1
```
使用
--amend選項(xiàng)的時(shí)候要注意:這樣的修改會(huì)改變提交的SHA-1校驗(yàn)和。它類似于一個(gè)小變基,所以我們?cè)谶@之前已經(jīng)將最后一次提交進(jìn)行了推送,那么我們就不應(yīng)該使用它。-
如果我們的修改是瑣碎的(例如修改了一個(gè)比武或者是添加了一個(gè)忘記暫存的文件),那么這種時(shí)候我們可能不需要修改提交信息,那么我們就可以使用
--no-edit選項(xiàng)跳過(guò)修改提交信息的步驟。具體命令如下$ git commit --amend --no-edit
重置揭秘
工作流程
經(jīng)典的Git工作流程是通過(guò)操縱下面這三個(gè)區(qū)域來(lái)以更加連續(xù)的狀態(tài)記錄項(xiàng)目快照的。

-
git add命令會(huì)將文件復(fù)制到Index中 -
git commit會(huì)取得Index中的內(nèi)容并將其保存為一個(gè)永久的快照,然后創(chuàng)建一個(gè)指向該快照的提交對(duì)象,然后更新master來(lái)指向本次提交
重置(reset)的作用
-
git reset --soft HEAD~會(huì)同步移動(dòng)HEAD以及其所指向的指針 -
git reset [--mixed] HEAD~在移動(dòng)HEAD以及其指向的指針之后會(huì)將HEAD所指向的分支的文件復(fù)制到Index中。值得一說(shuō)的是,這個(gè)--mixed可以忽略,默認(rèn)就是這個(gè)選項(xiàng) -
git reset --hard HEAD~在--mixed的基礎(chǔ)上,還會(huì)將Index中的內(nèi)容復(fù)制到Working Derictory中
通過(guò)路徑來(lái)重置
git reset [HEAD] <filename>會(huì)將當(dāng)前HEAD所指向的分支的提交中的指定文件恢復(fù)到Index中-
我們還可以指定一個(gè)提交版本(使用其校驗(yàn)和或者是部分校驗(yàn)和)中的文件用于進(jìn)行恢復(fù)。例如
$ git reset [HashCode] <filename>
壓縮
我們還可以使用reset命令進(jìn)行壓縮的提交。
- 假設(shè)有一個(gè)提交,實(shí)際上是一個(gè)未完成的工作,屬于接下來(lái)將要提交的一個(gè)中間過(guò)程,那么我們就可以使用
git reset --soft HEAD^1將HAD以及其所指向的分支重置到最新提交的父提交上; - 然后我們?cè)俅芜\(yùn)行
git commit命令,就相當(dāng)于我們丟棄了那個(gè)中間的提交,然后新創(chuàng)建了一個(gè)提交,這個(gè)提交指向那個(gè)被拋棄的中間提交的父提交。
檢出(checkout)
不帶路徑
-
git checkout <branchname>和git reset --hard <branchname>類似。不過(guò)其有兩點(diǎn)區(qū)別首先一點(diǎn)就是和
reset --hard不同的是,checkout對(duì)于工作目錄是安全的,它會(huì)通過(guò)檢查以確保不會(huì)將已經(jīng)更改的文件弄丟,而reset --hard直接不檢查就覆蓋工作目錄中的內(nèi)容另外一個(gè)是
checkout只會(huì)移動(dòng)HEAD,而不移動(dòng)其所指的分支-
如圖所示
image-20200613182157005
帶路徑
如果checkout指定一個(gè)文件路徑,那么它就和reset一樣不會(huì)移動(dòng)HEAD,而是直接用HEAD所指向的提交中的相應(yīng)文件更新索引,還會(huì)覆蓋工作目錄中的對(duì)應(yīng)文件。這就有點(diǎn)像git reset --hard [branch] <filename>(當(dāng)然,Git并不允許這樣的操作)。因此,這對(duì)于工作目錄也是不安全的。示例
$ git checkout -- <filename>
