十分鐘瞭解git那些「不經常使用」命令

本文主要是介紹git 不經常使用初期不太會用的命令,但願你看了能理解這些命令的使用,並在平時使用過程當中一點點地刻意進行練習,逐步熟練並知道什麼時候須要用到這些命令去解決你的問題。
( 我也在不斷熟練中:D

基礎命令

若是你仍是剛剛接觸git命令,還不清楚 倉庫工做流分支提交 的童鞋能夠先看下 git使用簡易指南,這個應該是我初學git看的第一份且收藏至今的指南了~ 圖解很清晰易懂,真10分鐘入門的資料:Dcss

而後你會發現以下基礎命令將會成爲你以後幾乎天天都要用到的80%的命令git

  • git clone git@github.com:nohosts/nohost.git 克隆遠程倉庫的內容到本地
  • git pull origin master 獲取遠程分支master並merge到當前分支
  • git branch -a 查看所有分支(遠程+本地)
  • git checkout -b bugFix新建bugFix,並切換到到此分支。(若是分支已存在則去掉-b便可)
  • git status 查看當前~~~~版本狀態(是否修改)
  • git add . 增長當前子目錄~~~~下全部文件更改至暫存區
  • git commit -m 'xxx' 提交暫存區的修改至本地的版本庫, 修改備註爲xxx
  • git push 將本地版本推送到遠程分支
  • git tag v1.0 dfb02e6e4f2f7b573337763e5c0013802e392818 增長v1.0的tag到某個提交上
  • git merge testBranch 合併testBranch分支至當前分支`
  • git stash 暫存本地的當前修改,將本地代碼重置爲HEAD狀態。(若是須要取出修改,命令後加一個pop便可)
  • git log 顯示提交日誌(若是想每一個提交信息顯示在一行,能夠加上--pretty=oneline)
  • git show dfb02e6e4f2f7b573337763e5c0013802e392818顯示某個提交的詳細內容
  • git reset --hard HEAD 將當前版本重置爲HEAD

注意這兩個命令的區別github

git pull = fetch + merge

git pull --rebase = fetch + rebase

「不經常使用」命令

1、git rebase 變基

在 Git 中整合來自不一樣分支的修改主要有兩種方法: merge 以及 rebase。 在本節中咱們將學習什麼是「變基」,怎樣使用「變基」,並將展現該操做的驚豔之處,以及指出在何種狀況下你應避免使用它。—— git-scm變基

說明:後面的舉例每一個 分支 都有不一樣的顏色,*前綴 表示如今所處的分支,而 commitid 都由C0、C一、C2代替每個提交的哈希值,箭頭 表示分支的繼承ide

咱們以前整合分支用的最多的就是merge了,那merge和rebase有什麼區別呢?學習

1. merge

merge 合併兩個分支時會產生一個特殊的提交記錄,它有兩個父節點。簡單說就是:「我要把這兩個父節點自己及它們全部的祖先都包含進來。」
git checkout master; git merge bugFix

下圖中左、右兩張圖分別是執行以下代碼先後的樣子:fetch

merge-1

能夠看出來,紅色圈圈是最主要的改變—— merge 合併分支後,會在master分支上 新增一個C4提交 ,而C4提交裏面有master和bugFix代碼庫全部的修改。網站

此時的bugFix代碼還沒和master 同步(顏色不一樣),咱們還須要執行以下代碼:ui

git checkout bugFix; git merge master

merge-2

2. rebase

rebase 實際上就是取出一系列的提交記錄,「複製」它們,而後在另一個地方逐個的放下去。它的優點就是能夠創造更線性的提交歷史。
git checkout bugFix; git rebase master

下圖中左、右兩張圖分別是執行代碼先後的樣子:spa

變基-1

bugFix 分支裏的內容經過 rebase 直接 複製 到 master 分支上。如今 bugFix 分支上的工做在 master 的最頂端,同時咱們也獲得了一個更 線性 的提交序列。日誌

注意:提交記錄 C3 依然存在(樹上那個半透明的節點),而 C3' 是咱們 rebase 到 master 分支上的 C3 的 副本(內容是同樣的,只是commitid更新了)。

可是,此時master尚未和bugFix 同步(顏色不一樣),咱們還須要執行以下代碼:

git checkout master; git rebase bugFix

變基-2.png

因爲bugFix繼承自master,因此 Git 只是簡單的把master分支的引用向前移動了一下而已。

3. rebase的延伸用法

3.1 省去切換分支便可rebase

git rebase targetBranch originBranch

表示切換到originBranch,而後執行git rebase targetBranch

3.2 修改某幾回提交

git rebase -i commitid

變基-3.png
如上圖標註的,傳的commitid爲你想修改的提交的 前一個commitid。執行命令後進入vi模式,會提示你一些操做命令(p、r、e...)你只須要在最上方修改默認的pick爲你想要的操做,而後退出並wq保存便可生效。

具體操做:

  • pick 使用(啥也沒變)
  • reword 使用並修改commit msg, 改後commit id也會更新
  • edit 使用並編輯commit時的文件
    編輯後git add . 而後git commit —amend還能夠更新最新的commit msg。 git rebase —continue 把後面的內容加進來並解決衝突, 最後提交。最新的commit id也更新
  • squash 合併commit
    選擇最新的commit去合併,而後continue發現這一次和上一次的commit msg都有,你能夠刪除只留下想要的也能夠進行修改 而後 continue和push。若是你不刪的話會發現所有文本行都組成了一個多行的commit msg
    若是commit再往前已經沒有了 就不能再squash,不然會報錯( error: cannot 'squash' without a previous commit )。而後 git rebase --edit-todo 能夠繼續vi編輯
  • fixup 合併commit到前面並且commit,commit msg也沒了
  • drop 刪除某個commit

注意
若是想要恢復這一次rebase操做,則能夠執行 git rebase —abort
若是想徹底恢復本地分支到遠程的狀態,能夠執行 git reset --hard origin/bugFix ,或者你能夠 git reflog 找到對應提交記錄回滾,可是有點麻煩

4. rebase須要謹慎使用

當你要改寫的commit history尚未被提交到遠倉庫的時候,也就是說,尚未與他人共享以前,commit history是你私人全部的,那麼想怎麼改寫均可以。

而一旦被提交到遠程後,這時若是再改寫history,那麼勢必和他人的history長的就不同了。git push 的時候,git會比較commit history,若是不一致,commit動做會被拒絕,惟一的辦法就是帶上 -f 參數,強制要求commit,這時git會以committer的history覆寫遠程分支,從而完成代碼的提交。雖然代碼提交上去了,可是這樣可能會形成別人工做成果的丟失,因此使用 -f 參數要慎重。

因此,在不用 -f 的前提下,想維持樹的整潔,方法就是:在 git push 以前,先 git fetch,再 git rebase

4. 總結

  1. 不管是經過變基,仍是經過三方合併,整合的最終結果所指向的快照始終是同樣的,只不過提交歷史不一樣罷了。 變基是將一系列提交按照原有次序依次應用到另外一分支上,而合併是把最終結果合在一塊兒
  2. 在你本身的分支(非他人共享)的分支進行rebase是能夠的,可是若是在公共分支rebase修改提交須要謹慎——最好是先 fetch、再 rebase、最後 push

2、git cherry-pick 選擇

cherry-pick 能夠將提交樹上任何地方的提交記錄取過來追加到 HEAD 上(只要不是 HEAD 上游的提交就沒問題)。`
git checkout master; git cherry-pick C2

下圖中左、右兩張圖分別是執行代碼先後的樣子:
是否是有點眼熟:D 沒錯 這個和rebase的效果蠻像的,這兩個命令均可以實現複製提交~

cherry-pick.png

3、git reset VS revert 回滾

git revert HEAD是用一次新的commit來回滾以前的commit, git reset 是直接向上移動分支,刪除一些commit看上去像從未提交同樣。這二者看似達到的效果是同樣的,其實徹底不一樣。
git reset HEAD~1
git revert HEAD

以下所見,圖1是初始狀態(須要撤回 C2 提交),圖2和3 是從圖1分別執行 resetrevert 後的結果:
image.png

  1. reset
    執行後,master 分支移回到了 C1;如今咱們的本地代碼庫根本就不知道有 C2 這個提交了
  2. revert
    執行後,在咱們要撤銷的提交記錄 C2 後面多了一個新提交C2',而C2'引入了更改—— 這些更改是用來撤銷C2這個提交的。也就是說C2'的狀態與C1是相同的。

注意

  • 若是你已經push到線上代碼庫, reset 刪除指定commit之後, 你git push可能致使不少衝突.可是revert 並不會。
  • 若是此回退的分支合併主幹分支時,reset 恢復部分的代碼依然會出如今歷史分支裏,可是revert 方向提交的commit 並不會出如今歷史分支裏。
# 事例
reset後的123 merge了12345 仍是12345
revert後的12345(-3) merge了12345 是12345(-3)

4、HEAD^n 和 HEAD~n 相對引用

HEAD 是一個對當前檢出記錄的符號引用 —— 也就是指向你正在其基礎上進行工做的提交記錄。 HEAD 老是指向當前分支上最近一次提交記錄
(若是想看 HEAD 指向,能夠經過  cat .git/HEAD 查看, 若是 HEAD 指向的是一個引用,還能夠用  git symbolic-ref HEAD 查看它的指向。)

1. 基礎使用

  • 使用 ^ 表示向上移動 1 個提交記錄。
    n表示第n個父提交,不填默認是1(正上方)
  • 使用 ~<num> 向上移動多個提交記錄
    如 ~3

注意:操做符還支持鏈式操,如HEAD^2~3^

2. 延伸用法
移動分支
能夠直接使用 -f 選項讓分支指向另外一個提交。例以下面的命令會將 master 分支強制指向 HEAD 的第 3 級父提交。

git branch -f master HEAD~3

此次主要就總結了這幾種「不經常使用」git命令,但願你們和我均可以多多練習,讓他變成你須要時就能夠自如使用的「經常使用」命令!:D

牆裂推薦一個可視化的git練習網站,很易懂好用~

推薦git系列文章

相關文章
相關標籤/搜索