git exercise
文章目錄
- git exercise
- set user information
- get git repo
- add file to stage
- cancel the staged file
- check the file status
- check the file diffrent
- commit the file
- check commit history
- cancel the file change
- remove file from git
- add remote repo
- rename remote repo
- check the remote repo
- pull from remote repo
- push to remote repo
- when pull operation report err
- fetch from remote repo
- remove remote repo
- list all loacal branch
- creat a new branch
- check the objects which is currently pointed by each branch
- change to another branch and update the work dir
- merge specific branch 's history to current branch
- delete specific branch
- list tag
- creat an tag
- share tag to remote
- check out tag
- delete tag
- rebase
- rewrite history
- modify the last commit
- modify more than one commit
- resort the order of commit
- split commit
- 核武器級選項:filter-branch
- reset
- checkout
- reset 和checkout的比較
- 提交準則
- git 工具
set user information
$ git config --global user.name "[name]"
對你的commit操作設置關聯的用戶名
$ git config --global user.email "[email address]"
對你的commit操作設置關聯的郵箱地址
get git repo
init local repo
$ git init [project-name]
初始化一個本地倉庫,可以指定項目名字,指定後會創建同名文件夾並作爲工作目錄
若不指定則以當前目錄作爲工作目錄
運行 git init,這會創建一個 Git 倉庫,其中的 HEAD 引用指向未創建的分支(master 還不存在)。
git倉庫中:HEAD->master->?
get remote repo
$ git clone [url]
從遠程倉庫完全拷貝工程到本地,可以附加名字,即本地庫名字
可以加-o
參數,如
$ git clone -o remoterepo [url]
那麼遠程庫名字將是remoterepo
而不是默認的origin
clone的本地倉庫的分支會自動跟蹤遠程分支
--depth=1
選項可以只獲取最新的commit
add file to stage
$ git add/stage [file]
- untracked file add to stage
- modified file add to stage
可以添加文件夾,則會遞歸添加文件夾下所有文件到暫存
-i
參數可以查看暫存區內容
git add .
把當前文件夾中的所有文件
cancel the staged file
$ git reset HEAD [file]
取消暫存
實際上暫存區將回到上一次提交時的快照內容。也可以直接使用git reset [file]
。
暫存各文件只有一份
git config --global alias.unstage 'reset HEAD --'
爲命令取別名,這會使下面兩個命令等價:
$ git unstage fileA
$ git reset HEAD -- fileA
check the file status
$ git status
可加參數-s
,查看簡化信息
簡化信息中:
M 代表已修改並已提交暫存
M代表已修改但未提交暫存
A 代表從未被提交過的文件
??代表未被追蹤的文件
check the file diffrent
$ git diff
- 不加參數代表工作目錄中當前文件與暫存區文件間的差異,也就是修改後還沒暫存的內容
- 加參數
--staged/cached
暫存文件與最新版本間(已提交的版本)的不同 $ git diff HEAD
顯示工作版本(Working tree)和HEAD的差別$ git diff SHA1 SHA2
比較兩個歷史版本之間的差異
commit the file
$ git commit -m"[descriptive message]"
將文件快照永久地記錄在版本歷史中
加參數-a
則把所有已追蹤文件暫存起來一併提交
多個子參數可以合起來。。。
像這樣:
$ git commit -am"[descriptive message]"
不要傻傻的分開寫。。。
check commit history
$ git log
顯示提交的歷史
參數-p
顯示提交差異
參數--graph
以圖形表形式顯示分支
cancel the file change
$ git checkout -- [file]
還原文件到暫存狀態(若有暫存)或上次提交(無暫存)
remove file from git
$ git rm [file]
從Git中移除文件
先刪除本地文件,再用rm移除
若文件已添加到暫存,則:
- 加參數
-f
強制移除(也將文件從暫存區移出) - 加參數
--cached
不再追蹤文件(也將文件從暫存區移出),但文件仍保留在硬盤
add remote repo
$ git remote add <shortname> <url>
將本地現有倉庫關聯到遠程倉庫,默認名字是origin
,也可以起別名,必須帶名字
只是添加了遠程引用,與
clone
不同,clone
會添加遠程引用,爲你自動將其命名爲origin
,跟蹤遠程分支,拉取它的所有數據,創建一個指向它的master
分支的指針,並且在本地將其命名爲origin/master
。相當於遠程倉庫的一個副本
設置已有的本地分支跟蹤一個剛剛拉取下來的遠程分支,或者想要修改正在跟蹤的上游分支,你可以在任意時間
使用 -u
或 --set-upstream-to
選項運行 git branch
來顯式地設置。
$ git branch -u origin/master
遠程跟蹤分支是遠程分支狀態的引用。它們是你不能移動的本地引用,當你做任何網絡通信操作時,它們會自動移動。遠程跟蹤分支像是你上次連接到遠程倉庫時,那些分支所處狀態的書籤。
rename remote repo
$ git remote rename [old-name] [new-name]
重命名遠程庫
check the remote repo
$ git remote
查看遠程倉庫
加參數-v
可顯示URL
git remote show [remote-name]
查看更多信息
pull from remote repo
$ git pull <遠程主機名> <遠程分支名>:<本地分支名>
如
$ git pull origin master:master
表示取回origin主機的master分支,與本地的master分支合併。
如果遠程分支是與當前分支合併(即當前爲master分支),則冒號後面的部分可以省略:
git pull origin master
push to remote repo
$ git push <遠程主機名> <本地分支名>:<遠程分支名>
- 如果省略遠程分支名,則表示將本地分支推送與之存在"追蹤關係"的遠程分支(通常兩者同名),如果該遠程分支不存在,則會被新建:
git push origin master
上面命令表示,將本地的master分支推送到origin主機的master分支。如果後者不存在,則會被新建。
- 如果當前分支與多個主機存在追蹤關係,則可以使用
-u
選項指定一個默認主機,這樣後面就可以不加任何參數使用git push
。
反饋如下:
Branch master set up to track remote branch master from [remote-name]
- 如果遠程主機的版本比本地版本更新,推送時Git會報錯,要求先在本地做
git pull
合併差異,然後再推送到遠程主機。這時,如果你一定要推送,可以使用--force
選項。
$ git push --force origin
上面命令使用--force
選項,結果導致遠程主機上更新的版本被覆蓋。除非你很確定要這樣做,否則應該儘量避免使用--force
選項。
when pull operation report err
git pull origin master --allow-unrelated-histories
use this command avoid
refusing to merge unrelated histories
遠程庫存在本地沒有的文件時,push
會報錯,此時pull
會報上面的錯誤
fetch from remote repo
$ git fetch [remote-name]
抓取遠成倉庫中你沒有的數據,但不會自動合併(相較於pull)
當抓取到新的遠程跟蹤分支時,本地不會自動生成一份可編輯的副本(拷貝)。換一句話
說,這種情況下,不會有一個新的分支 - 只有一個不可以修改的指針。
所取回的更新,在本地主機上要用"遠程主機名/分支名"的形式讀取。比如origin
主機的master
,就要用origin/master
讀取。
remove remote repo
$ git remote rm [remote-name]
移除遠程庫,不再關聯
list all loacal branch
$ git branch
-r
選項,可以用來查看遠程分支,-a選項查看所有分支
-vv
選項查看所有跟蹤分支
--merged
選項查看哪些分支已經合併到當前分支
--no-merged
選項查看其他分支
creat a new branch
$ git branch [branch-name]
check the objects which is currently pointed by each branch
$ git log --decorate
change to another branch and update the work dir
$ git checkout [branch-name]
加-b
參數則爲創建一個新分支並切換到那個分支
merge specific branch 's history to current branch
$ git merge [branch-name]
合併衝突時使用git status
來查看衝突,然後可以打開文件並修改來解決衝突,然後使用git add
提交暫存來將其標記爲衝突已解決
也可以運行
$ git mergetool
圖形化工具來解決衝突
delete specific branch
$ git branch -d [branch-name]
list tag
$ git tag
列出標籤
$ git show
可以看到附註標籤的標籤信息與對應的提交信息
creat an tag
- lightweight
$ git tag [tag name]
後面可跟commit id
用來給過去的commit打標籤
- annotated
$ git tag -a [tag name]
加-m
參數,添加存儲在標籤中的信息
share tag to remote
git push [remote name] [tagname]
推送標籤
$ git push [remote name] --tags
推送大量標籤
check out tag
git checkout -b [branchname] [tagname]
將在在特定的標籤上創建一個新分支
delete tag
git tag -d [tagname]
刪除本地標籤
$ git push [remote name] :refs/tags/[tag name]
刪除遠程倉庫標籤
rebase
git rebase [basebranch] [topicbranch]
將topicbranch
中的修改變基到basebranch
上
如果[topicbranch]
即爲當前分支,則可寫爲
git rebase [basebranch]
它的原理是首先找到這兩個分支(即當前分支 [topicbranch]
、變基操作的目標基底分支 [basebranch]
)的最近共同祖先 ,然後對比當前分支相對於該祖先的歷次提交,提取相應的修改並存爲臨時文件,然後將當前分支指向目標基底 [basebranch]
, 最後以此將之前另存爲臨時文件的修改依序應用。
一般我們這樣做的目的是爲了確保在向遠程分支推送時能保持提交歷史的整潔——例如向某個別人維護的項目貢獻代碼時。在這種情況下,你首先在自己的分支裏進行開發,當開發完成時你需要先將你的代碼變基到origin/master 上,然後再向主項目提交修改。這樣的話,該項目的維護者就不再需要進行整合工作,只需要快進合併便可。
無論是通過變基,還是通過三方合併,整合的最終結果所指向的快照始終是一樣的,只不過提交歷史不同罷了。變基是將一系列提交按照原有次序依次應用到另一分支上,而合併是把最終結果合在一起。變基使得提交歷史更加整潔。
不要對在你的倉庫外有副本的分支執行變基。
變基操作的實質是丟棄一些現有的提交,然後相應地新建一些內容一樣但實際上不同的提交。如果你已經將提交推送至某個倉庫,而其他人也已經從該倉庫拉取提交併進行了後續工作,此時,如果你用 git rebase 命令重新整理了提交併再次推送,你的同伴因此將不得不再次將他們手頭的工作與你的提交進行整合,如果接下來你還要拉取並整合他們修改過的提交,事情就會變得一團糟
總的原則是,只對尚未推送或分享給別人的本地修改執行變基操作清理歷史,從不對已推送至別處的提交執行變基操作,這樣,你才能享受到兩種方式帶來的便利。
rewrite history
modify the last commit
$ git commit --amend
直接鍵入以上命令,可以修改上次的提交信息。若想修改上次快照的提交內容,可以通過修改文件然後運行 git add
或 git rm
一個已追蹤的文件,隨後運行git commit --amend
拿走當前的暫存區域並使其做爲新提交的快照.使用這個技巧的時候需要小心,因爲修正會改變提交的 SHA-1 校驗和。它類似於一個小的變基 - 如果已經推送了最後一次提交就不要修正它。
modify more than one commit
爲了修改在提交歷史中較遠的提交,必須使用更復雜的工具。Git 沒有一個改變歷史工具,但是可以使用變基工具來變基一系列提交,基於它們原來的 HEAD
而不是將其移動到另一個新的上面。通過交互式變基工具,可以在任何想要修改的提交後停止,然後修改信息、添加文件或做任何想做的事情。可以通過給 git rebase
增加 -i
選項來交互式地運行變基。必須指定想要重寫多久遠的歷史,這可以通過告訴命令將要變基到的提交來做到。
再次記住這是一個變基命令 - 在範圍內的每一個提交都會被重寫,無論你是否修改信息。不要涉及任何已經推送到中央服務器的提交 - 這樣做會產生一次變更的兩個版本,因而使他人困惑。
$ git rebase -i HEAD~3
pick 46ad177 3commit
pick 65a142c 2commit
pick 60849fd 1commit
# Rebase 5e482cb..60849fd onto 5e482cb (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
resort the order of commit
如果想要移除 “added cat-file” 提交然後修改另外兩個提交引入的順序,可以將變基腳本從這樣:
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
改爲這樣:
pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit
當保存並退出編輯器時,Git 將你的分支帶回這些提交的父提交,應用 310154e 然後應用 f7f3f6d,最後停止。事實修改了那些提交的順序並完全地移除了 “added cat-file” 提交。
split commit
將要拆分的提交的指令修改爲 “edit”,當保存並退出編輯器時,會依次應用到你修改的那個commit爲止,然後讓你進入命令行。那裏,可以通過 git reset HEAD^ 做一次針對那個提交的混合重置,實際上將會撤消那次提交併將修改的文件未暫存。現在可以暫存並提交文件直到有幾個提交,然後當完成時運行 git rebase --continue
,Git 在腳本中應用後續提交。
–continue.再一次,這些改動了所有在列表中的提交的 SHA-1 校驗和,所以要確保列表中的提交還沒有推送到共享倉庫中。
核武器級選項:filter-branch
暫時用不到
reset
樹 | 用途 |
---|---|
HEAD | 上一次提交的快照,下一次提交的父結點 |
Index | 預期的下一次提交的快照 |
Working Directory | 沙盒 |
HEAD
HEAD 是當前分支引用的指針,它總是指向該分支上的最後一次提交。這表示 HEAD 將是下一次提交的父結點。通常,理解 HEAD 的最簡方式,就是將它看做 你的上一次提交 的快照。
索引
索引(index)是你的預期的下一次提交。我們也會將這個概念引用爲 Git 的 “暫存區域”,這就是當你運行 gitcommit 時 Git 看起來的樣子。
工作目錄
最後,你就有了自己的工作目錄。另外兩棵樹以一種高效但並不直觀的方式,將它們的內容存儲在 .git 文件夾中。工作目錄會將它們解包爲實際的文件以便編輯。你可以把工作目錄當做 沙盒。在你將修改提交到暫存區並記錄到歷史之前,可以隨意更改。
reset
reset的三種基本操作:
第 1 步:移動 HEAD
git reset --soft HEAD~
reset 做的第一件事是移動 HEAD 的指向。這與改變 HEAD 自身不同(checkout 所做的);reset 移動HEAD 指向的分支。無論你調用了何種形式的帶有一個提交的 reset,它首先都會嘗試這樣做–使用 reset --soft
,它將僅僅停在那兒,不會改變索引和工作目錄。。
第 2 步:更新索引(–mixed)
git reset HEAD~
reset 會用 HEAD 指向的當前快照的內容來更新索引。如果指定 --mixed 選項,reset 將會在這時停止。這也是默認行爲,所以如果沒有指定任何選項(在本例中只是 git reset HEAD~),這就是命令將會停止的地方.
第 3 步:更新工作目錄(–hard)
git reset --hard HEAD~
這將撤銷最後的提交、git add 和 git commit 命令以及工作目錄中的所有工作。必須注意,–hard 標記是 reset 命令唯一的危險用法,它也是 Git 會真正地銷燬數據的僅有的幾個操作之一。
其他任何形式的 reset 調用都可以輕鬆撤消,但是 --hard 選項不能,因爲它強制覆蓋了工作目錄中的文件。若想找回撤銷前的提交,可以通過reflog
來找回,但未提交的修改部分則無法恢復了。
通過路徑來重置
運行 git reset file.txt(這其實是 git reset --mixed HEAD file.txt 的簡寫形式,因爲你既沒有指定一個提交的 SHA-1 或分支,也沒有指定 --soft 或 --hard).它本質上是將file.txt 從 HEAD 複製到索引中。我們可以不讓 Git 從 HEAD 拉取數據,而是通過具體指定一個提交來拉取該文件的對應版本。我們只需運行類似於 git reset eb43bf file.txt
的命令即可。還有一點同 git add 一樣,就是 reset 命令也可以接受一個 --patch 選項來一塊一塊地取消暫存的內容。這樣你就可以根據選擇來取消暫存或恢復內容了。
Apply this hunk to index [y,n,q,a,d,/,e,?]? ?
y - apply this hunk to index
n - do not apply this hunk to index
q - quit; do not apply this hunk or any of the remaining ones
a - apply this hunk and all later hunks in the file
d - do not apply this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
需要注意的是若針對文件,則HEAD指向不會改變,否則HEAD指向也會改變。
壓縮
壓縮提交可以利用rebase
的交互工具來完成,也可以利用這裏的reset
,使用git reset --soft [commit]
將HEAD回退到某個版本,此時暫存區工作區的內容都未有任何改變,此時commit即可創建一個從回退到的版本到回退前版本的直接提交,從而達到壓縮的目的。
checkout
不帶路徑
運行 git checkout [branch]
與運行git reset --hard [branch]
非常相似,它會更新所有三棵樹使其看起來像 [branch]
,不過有兩點重要的區別。
首先不同於 reset --hard
,checkout
對工作目錄是安全的,它會通過檢查來確保不會將已更改的文件吹走。其實它還更聰明一些。它會在工作目錄中先試着簡單合併一下,這樣所有_還未修改過的_文件都會被更新。而reset --hard
則會不做檢查就全面地替換所有東西。第二個重要的區別是如何更新 HEAD
。reset
會移動 HEAD
分支的指向,而 checkout
只會移動 HEAD
自身來指向另一個分支。
帶路徑
運行 checkout
的另一種方式就是指定一個文件路徑,它就像git reset [branch] file
那樣用該次提交中的那個文件來更新索引,但是它也會覆蓋工作目錄中對應的文件,但不會改變HEAD指向。
reset 和checkout的比較
HEAD | Index | Workdir | WD Safe? | |
---|---|---|---|---|
Commit Level | ||||
reset --soft [commit] | REF | NO | NO | YES |
reset [commit] | REF | YES | NO | YES |
reset --hard [commit] | REF | YES | YES | NO |
checkout [commit] | HEAD | YES | YES | YES |
File Level | ||||
reset (commit) [file] | NO | YES | NO | YES |
checkout (commit) [file] | NO | YES | YES | NO |
提交準則
- 找出空白錯誤
$ git diff --check
- 嘗試讓每一個提交成爲一個邏輯上的獨立變更集
如果可以,嘗試讓改動可以理解 - 不要在整個週末編碼解決五個問題,然後在週一時將它們提交爲一個巨大的提交。即使在週末期間你無法提交,在週一時使用暫存區域將你的工作最少拆分爲每個問題一個提交,並且爲每一個提交附帶一個有用的信息。如果其中一些改動修改了同一個文件,嘗試使用
git add --patch
來部分暫存文件。
- 提交信息
有一個創建優質提交信息的習慣會使 Git 的使用與協作容易的多。一般情況下,信息應當以少於 50 個字符(25個漢字)的單行開始且簡要地描述變更,接着是一個空白行,再接着是一個更詳細的解釋Git 項目要求一個更詳細的解釋,包括做改動的動機和它的實現與之前行爲的對比 - 這是一個值得遵循的好規則。
git 工具
- 簡短的 SHA-1
你只需要提供 SHA-1 的前幾個字符就可以獲得對應的那次提交
之前看到教程上別人都用短的sha碼,我都不知道短的碼從哪裏來的¯_(ツ)_/¯,原來這個是要那個好長的碼的前幾位(至少4位)就行了。。。
下面命令等價(無歧義情況下):
$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d
- 分支引用
指明一次提交最直接的方法是有一個指向它的分支引用。這樣你就可以在任意一個 Git 命令中使用這個分支名來代替對應的提交對象或者 SHA-1 值。
例如,你想要查看一個分支的最後一次提交的對象,假設 topic1 分支指向ca82a6d ,那麼以下的命令是等價的:
$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1
- 引用日誌
git reflog
引用日誌記錄了最近幾個月你的 HEAD 和分支引用所指向的歷史。
-
祖先引用
祖先引用是另一種指明一個提交的方式。如果你在引用的尾部加上一個 ^, Git 會將其解析爲該引用的上一個提交。可以使用HEAD^
來查看上一個提交(HEAD可以看做當前分支),也就是 “HEAD 的父提交”。你也可以在^
後面添加一個數字——例如d921970^2
代表 “d921970 的第二父提交”。這個語法只適用於合併(merge)的提交,因爲合併提交會有多個父提交。第一父提交是你合併時所在分支,而第二父提交是你所合併的分支。
另一種指明祖先提交的方法是~
。同樣是指向第一父提交,因此HEAD~
和HEAD^
是等價的。而區別在於你在後面加數字的時候。HEAD~2
代表 “第一父提交的第一父提交”,也就是 “祖父提交” —— Git 會根據你指定的次數獲取對應的第一父提交。HEAD~3
也可以也可以寫成HEAD^^^
,也是第一父提交的第一父提交的第一父提交。你也可以組合使用這兩個語法 —— 你可以通過HEAD~3^2
來取得上一個引用的第二父提交(假設它是一個合併提交)(也就是第一父提交的第一父提交的第一父提交的第二父提交(#`皿´))。 -
提交區間
- 雙點
選出在一個分支中而不在另一個分支中的提交。
假如你有兩個分支master
和experiment
, 你想要查看experiment
分支中還有哪些提交尚未被合併入master
分支。你可以使用master..experiment
來讓 Git 顯示這些提交。也就是 “在 experiment 分支中而不在 master 分支中的提交”。
git log master..experiment
另一個常用的場景是查看你即將推送到遠端的內容:
$ git log origin/master..HEAD
- 多點
Git 允許你在任意引用前加上^
字符或者--not
來指明你不希望提交被包含其中的分支。因此下列3個命令是等價的:
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA
這個語法很好用,因爲你可以在查詢中指定超過兩個的引用,這是雙點語法無法實現的。比如,你想查看所有被refA 或 refB 包含的但是不被 refC 包含的提交,你可以輸入下面中的任意一個命令:
$ git log refA refB ^refC
$ git log refA refB --not refC
- 三點
這個語法可以選擇出被兩個引用中的一個包含但又不被兩者同時包含的提交。如果你想看 master 或者 experiment 中包含的但不是兩者共有的提交,你可以執行:
$ git log master...experiment
可加參數 --left-right
,它會顯示每個提交到底處於哪一側的分支。這會讓輸出數據更加清晰。
- 交互式暫存
運行git add
時使用-i
或者--interactive
選項,Git 將會進入一個交互式終端模式:
$ git add -i
staged unstaged path
1: unchanged +63/-4 learn.md
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
- 暫存與取消暫存
如果在 What now> 提示符後鍵入 2 或 u,腳本將會提示想要暫存哪個文件:
What now> 2
staged unstaged path
1: unchanged +63/-4 learn.md
Update>>
要暫存 TODO 與 index.html 文件,可以輸入數字:
Update>> 1
staged unstaged path
* 1: unchanged +63/-4 learn.md
Update>>
每個文件前面的 * 意味着選中的文件將會被暫存。如果在 Update>> 提示符後不輸入任何東西並直接按回車,Git 將會暫存之前選擇的文件:
updated 1 path
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 1
staged unstaged path
1: +63/-4 nothing learn.md
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
現在可以看到文件已被暫存,如果這時想要取消暫存TODO 文件,使用 3 或 r(撤消)選項:
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 3
staged unstaged path
1: +63/-4 nothing learn.md
Revert>> 1
staged unstaged path
* 1: +63/-4 nothing learn.md
Revert>>
reverted 1 path
再次查看 Git 狀態,可以看到已經取消暫存:
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 1
staged unstaged path
1: unchanged +63/-4 learn.md
如果想要查看已暫存內容的區別,可以使用 6 或 d(區別)命令。它會顯示暫存文件的一個列表,可以從中選擇想要查看的暫存區別。這跟你在命令行指定 git diff --cached 非常相似:
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 1
staged unstaged path
1: +63/-4 nothing learn.md
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 6
staged unstaged path
1: +63/-4 nothing learn.md
Review diff>> 1
diff --git a/learn.md b/learn.md
index acfbb81..bdf46ad 100644
--- a/learn.md
+++ b/learn.md
@@ -259,13 +259,14 @@ $ git push [remote name] :refs/tags/[tag name]
刪除遠程倉庫標籤
***
...
----------
- 暫存補丁
Git 也可以暫存文件的特定部分。例如,如果在learn.md
文件中做了幾處修改,但只想要暫存其中的一個而不是另一個,Git 會幫你輕鬆地完成。從交互式提示符中,輸入5
或p
(補丁)。Git 會詢問你想要部分暫存哪些文件;然後,對已選擇文件的每一個部分,它都會一個個地顯示文件區別並詢問你是否想要暫存它們:
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 1
staged unstaged path
1: unchanged +63/-4 learn.md
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now> 5
staged unstaged path
1: unchanged +63/-4 learn.md
Patch update>> 1
staged unstaged path
* 1: unchanged +63/-4 learn.md
Patch update>>
diff --git a/learn.md b/learn.md
index acfbb81..bdf46ad 100644
--- a/learn.md
+++ b/learn.md
@@ -259,13 +259,14 @@ $ git push [remote name] :refs/tags/[tag name]
刪除遠程倉庫標籤
***
...
----------
some change...
Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?
這時有很多選項。輸入 ? 顯示所有可以使用的命令列表:
Stage this hunk [y,n,q,a,d,/,j,J,g,s,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
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
也可以不必在交互式添加模式中做部分文件暫存 - 可以在命令行中使用 git add -p 或 git add --patch 來啓動同樣的腳本。
8. 儲藏與清理
有時,當你在項目的一部分上已經工作一段時間後,所有東西都進入了混亂的狀態,而這時你想要切換到另一個分支做一點別的事情。問題是,你不想僅僅因爲過會兒回到這一點而爲做了一半的工作創建一次提交。針對這個問題的答案是 git stash save
或git stash
命令。儲藏會處理工作目錄的髒的狀態 - 即,修改的跟蹤文件與暫存改動 - 然後將未完成的修改保存到一個棧上,而你可以在任何時候重新應用這些改動。git stash save
可以直接跟註釋信息。
$ 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: main.c
no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on master: 163617c Creat the first file main.c
$ git status
On branch master
nothing to commit, working tree clean
$ git stash list
stash@{0}: WIP on master: 163617c Creat the first file main.c
通過git stash apply將你剛剛儲藏的工作重新應用:
$ git stash apply
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: main.c
no changes added to commit (use "git add" and/or "git commit -a")
如果想要應用其中一個更舊的儲藏,可以通過名字指定它,像這樣:git stash apply stash@{2}
。如果不指定一個儲藏,Git 認爲指定的是最近的儲藏。
本次應用儲藏時有一個乾淨的工作目錄,並且嘗試將它應用在保存它時所在的分支;但是有一個乾淨的工作目錄與應用在同一分支並不是成功應用儲藏的充分必要條件。可以在一個分支上保存一個儲藏,切換到另一個分支,然後嘗試重新應用這些修改。當應用儲藏時工作目錄中也可以有修改與未提交的文件 - 如果有任何東西不能幹淨地應用,Git 會產生合併衝突。git stash apply
只能恢復工作目錄,如果想把暫存區也按照貯藏時的暫存區恢復的話,可以加上--index
。
應用選項只會嘗試應用暫存的工作 - 在堆棧上還有它。可以運行git stash drop
加上將要移除的儲藏的名字來移除它,也可以運行git stash pop
來應用儲藏然後立即從棧上扔掉它。git satsh clear
可以刪除所有stash。
創造性儲藏
- 有幾個儲藏的變種可能也很有用。第一個非常流行的選項是
stash save
命令的--keep-index
選項。它告訴Git 不要儲藏任何你通過git add
命令已暫存的東西。當你做了幾個改動並只想提交其中的一部分,過一會兒再回來處理剩餘改動時,這個功能會很有用。 - 另一個經常使用儲藏來做的事情是像儲藏跟蹤文件一樣儲藏未跟蹤文件。默認情況下,
git stash
只會儲藏已經在索引中的文件。如果指定--include-untracked
或-u
標記,Git 也會儲藏任何創建的未跟蹤文件。 - 最終,如果指定了
--patch
標記,Git 不會儲藏所有修改過的任何東西,但是會交互式地提示哪些改動想要儲藏、哪些改動需要保存在工作目錄中。
從儲藏創建一個分支
如果儲藏了一些工作,將它留在那兒了一會兒,然後繼續在儲藏的分支上工作,在重新應用工作時可能會有問題。如果應用嘗試修改剛剛修改的文件,你會得到一個合併衝突並不得不解決它。如果想要一個輕鬆的方式來再次測試儲藏的改動,可以運行git stash branch
創建一個新分支,檢出儲藏工作時所在的提交,重新在那應用工作,然後在應用成功後扔掉儲藏。
- 清理工作目錄
git clean
它被設計爲從工作目錄中移除未被追蹤的文件,你需要謹慎地使用這個命令,因爲移除的文件很可能找不回來了。一個更安全的選項是運行 git stash --all 來移除每一樣東西並存放在棧中。你可以使用git clean
命令去除冗餘文件或者清理工作目錄。使用git clean -f -d
命令來移除工作目錄中所有未追蹤的文件以及空的子目錄。-f 意味着 強制 或 “確定移除”。如果只是想要看看它會做什麼,可以使用 -n 選項來運行命令,這意味着 “做一次演習然後告訴你 將要 移除什麼”。
默認情況下,git clean 命令只會移除沒有忽略的未跟蹤文件。任何與 .gitiignore 或其他忽略文件中的模式匹配的文件都不會被移除。如果你也想要移除那些文件,例如爲了做一次完全乾淨的構建而移除所有由構建生成的 .o 文件,可以給 clean
命令增加一個 -x
選項。加-i
參數可以以交互模式運行clean
命令。
- 搜索
- Git Grep
Git 提供了一個 grep 命令,你可以很方便地從提交歷史或者工作目錄中查找一個字符串或者正則表達式。
可以傳入-n
參數來輸出 Git 所找到的匹配行行號。
使用--count
選項來使 Git 輸出概述的信息,僅僅包括哪些文件包含匹配以及每個文件包含了多少個匹配。
如果你想看匹配的行是屬於哪一個方法或者函數,你可以傳入-p
選項.
使用--break
和--heading
選項可以使輸出更加容易閱讀。
- Git日誌搜索
或許你不想知道某一項在 哪裏 ,而是想知道是什麼 時候 存在或者引入的。git log
命令有許多強大的工具可以通過提交信息甚至是 diff 的內容來找到某個特定的提交。
使用-S
選項來顯示新增和刪除字符串的提交。
使用-G
選項來使用正則表達式搜索。
使用-L
選項展示代碼中一行或者一個函數的歷史。 - 子模塊
子模塊允許你將一個 Git 倉庫作爲另一個 Git 倉庫的子目錄。它能讓你將另一個倉庫克隆到自己的項目中,同時還保持提交的獨立。