盤點那些不知名卻經常使用的 Git 操做

Git 很是複雜。我即便幾乎天天都在用,也不敢保證對 Git 的每個角落都瞭如指掌。
本文試圖盤點一些不知名,但在我看來較經常使用的操做。若是沒有你預期的操做,說明要麼在我看來它很知名,要麼在我看來它不太經常使用。git

  • git log --graph --abbrev-commit --decorate --all --onelinegithub

  • git cherryshell

  • git show ref:pathvim

  • git reset [--hard|--soft|--keep]緩存

  • git update-index --assume-unchangedless

git log --graph --abbrev-commit --decorate --all --oneline

若是要看項目中的分支狀況,一般的作法是打開一個 Git GUI 軟件,經過 GUI 界面來查看全景。
對於有些人來講,這是裝 GUI 的惟一需求。
其實這個需求能夠砍掉,由於 Git 提供了在終端中輸出提交記錄全景的操做:編輯器

git log --graph --abbrev-commit --decorate --all --oneline

輸出結果至關驚豔,你能夠像看 GUI 界面同樣,在終端中查看不一樣分支的提交信息。
git-log.png
(這裏採用了一個開源項目的提交歷史來示例,若是是公司的商業項目,輸出會更炫目)lua

這個輸出跟 man xxx 同樣,會經過 $PAGER(一般是 less) 顯示在終端上。這意味着你能夠在輸出中搜索特定的提交或 tag。
許多 GUI 界面並不提供這一功能,致使用戶只能瞪大眼睛,一點點地挪動,才能揪出特定的提交。
就這一點上,終端版的功能要比 GUI 版本勝出許多。
終端版的另外一個優勢是,提供了自由組合各類選項的能力。你能夠自定義輸出信息和顯示的提交範圍。
若是嫌命令太長,能夠給它一個 alias(經過 git alias 或 shell 的 alias 功能)。spa

git cherry

有一個經常使用的 Git 操做是 git cherry-pickgit cherry 顧名思義,天然跟 cherry-pick 有關。
git cherry 能夠比較兩個分支,篩選出存在於甲分支卻不存在於乙分支的提交。顯而易見,這是在爲後面的 cherry-pick 作準備。插件

¥ git cherry 4.2.0 | tail
+ bb5f4b02340b3c269d7a8e11842d4a16b2b8eba1
+ 2451c0c202dd48bc610ef9731c503ea54f19af83
+ 64b4a599e8af4b31444f2a86559d4860401925f4
+ c80b4e773f746ffe11aca9010b4433f6b6ba13ad
+ b2c7de9a5a5c8ea0254001a07ae24ffc27118dbb
+ 719dd2c3af9ba801114101ccdec1cd9e2f1bbc5d
+ 518db6e648aaf646db4be3067a583bdcc37ee2a8
+ b01359efc5761a17cd3b893fd51219a005009641
+ 422c9a8e69acc5cf013340715f8d2fa7d7cabf75
+ cc0dff2f49cfbd786eca498fe2532de0455e1759

美中不足的是,git cherry 的輸出是 sha1,對機器來講友好,對人來講就是天書。若是要看具體的提交信息,須要借其餘命令之力。好比 git show

git show --no-patch --format='%s' cc0dff2f49cfbd786eca498fe2532de0455e1759

git show ref:path

git show 是我最喜歡的命令之一。輸出提交的內容,是 git show 的拿手好戲之一。舉個例子,git show @ 能夠顯示當前分支上最新提交。(@HEAD
的別名,能少敲三個字符呢)

不過這不算 git show 的殺手鐗。git show 的絕活,是能在不檢出特定提交的前提下,顯示特定提交的某個文件的內容。
假設咱們想看看 xxx 提交上的 db.lua,純粹只想看一看,不涉及調試或其餘複雜的操做。咱們固然能夠 git checkout xxx,而後想看啥就看啥。然而用 git show 的話,就能保持當前分支不變,直接顯示 xxx 提交上的 db.lua 了:

git show xxx:path/to/db.lua

編輯器的 Git 插件通常支持在編輯器內直接打開 git show 的輸出。若是你用的是 Vim,又裝了 fugitive
經過敲 :Gedit revision:%,能夠打開當前文件的特定版本。
若是想找到哪幾個提交修改了特定文件,能夠先用 git log --format='%s' -- /path/to/your/file 獲取涉及的提交。

git reset [--hard|--soft|--keep]

git reset 可不能算是「不知名」操做。任何 Git 入門教程,都會提到怎麼用 git reset 把文件移出暫存區。但在本人的平常開發流程中,移出暫存區實際上是最少用上的
git reset 操做。因此我以爲能夠打個擦邊球,講講 git reset 其餘的打開方式。

移出暫存區的 git reset 操做,至關於 git reset --mixed。除了 --mixed,經常使用的選項還有下面三個:

  • --soft

  • --hard

  • --keep

開發中常有的狀況:劈劈啪啪寫了一堆代碼,連續好幾個提交。而後腦子裏靈機一動,頓悟了更好的作法。這個作法是如此地好,以至於以前的提交記錄都成了你的黑歷史。你巴不得
把這些提交記錄一筆勾銷,但該怎麼辦呢?這時候就輪到 reset --soft 上場了。
reset --soft 俗稱 squash,能夠在保留修改的同時,把最近的幾個提交歷史給抹掉。好比 git reset --soft @~3 就能重置到倒數第四個提交,但保留被抹掉的三個提交的更改。
這麼操做以後再提交一次,而後選一個夜深人靜的時刻,push -f 到遠程倉庫,你的黑歷史就煙消雲散了。固然仍是會留下些痕跡什麼的,但至少別人通常發現不了……

--soft 對應的是 --hard--hard 也會抹掉最近的幾個提交,但不保留修改。若是感到本身的代碼實在無法看,能夠直接 reset --hard 試試。不過 reset --hard 倒不失清理環境的好方法。

--keep 正好在 --soft--hard 之間。--keep 會保留未提交的更改,這一點跟 --soft 同樣;同時會抹掉已經提交的更改,這一點跟 --hard 相同。
有些時候,這一特性會派上用場。

若是你在開發的時候,忽然發現本身忘記切分支了,能夠這麼作:

git branch feature/you_need
git reset --keep comit_your_hack_starts_from
git checkout feature/you_need

這樣作既消除了錯誤分支上的提交,又保留了工做區裏未提交的內容。

提到 reset,不能不提誤操做時的補救辦法。

  1. 被抹掉的內容已經提交了。這種狀況好辦。經過 git reflog,咱們能夠找到被抹掉的提交,而後 cherry-pick回來,抑或 reset --hard HEAD{x} 到對應的提交上去。

  2. 被抹掉的內容原來在暫存區裏。這個比較蛋疼。你須要 git fsck | grep blob 揀出每個 dangling blob,逐個 git show xxx 看看,應該能找回被抹掉的內容。這種感受,就像在垃圾桶裏翻出丟失的手稿同樣。

  3. 被抹掉的內容不在暫存區裏。靠 Git 已經救不回來了。要不找下編輯器的備份文件,要不嘗試能不能從文件系統緩存裏把文件摳出來。若是不行,試試磁盤數據恢復程序……

說這麼多,關鍵記住一點:reset 有風險,用時需謹慎。

git update-index --assume-unchanged

假設代碼倉庫裏存在這麼一個配置文件:每一個人在開發時,會根據本地狀況修改裏面的值。好比某些 IDE 的項目描述文件,裏面可能夾雜着項目的路徑。
有什麼辦法,能夠避免本地的修改不會提交到倉庫裏去呢?
我的認爲 git update-index --assume-unchanged 是衆多解決方法中最好的。
git update-index 能夠修改 Git 對特定路徑下的文件的處理方式。其中 --assume-unchanged 選項告訴 Git,指定路徑下的文件不會有修改。
即便在本地修改了那些文件,也不會被 Git 記錄在案。
若是我有一天須要修改這個配置文件併入庫,能夠用 --no-assume-unchanged 選項解開封印,讓 Git 從新追蹤修改。

¥ gs
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:   check_integrity.sh

no changes added to commit (use "git add" and/or "git commit -a")
 ¥ git update-index --assume-unchanged check_integrity.sh
 ¥ gs
On branch master
nothing to commit, working tree clean
 ¥ git update-index --no-assume-unchanged check_integrity.sh
 ¥ gs
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:   check_integrity.sh
相關文章
相關標籤/搜索