­

Git進階:你不知道的git stash 和 git worktree

  • 2019 年 10 月 11 日
  • 筆記

git中比較有用的兩個命令, git stash 和 git worktree, 你值得了解一下

1. Git和SVN的別樣比較

部門從SVN簽到了Git, 總算跟上了潮流的腳後跟. 其實從技術的角度來說, SVN沒有那麼爛. 但是從當今的角度來說, Git已經代表潮流, SVN已經沒落並將持續沒落下去, 繼續把寶貴的時間投入到SVN這種註定沒落的技術上, 實在是得不償失.

不信? 看下google trends:

全球2004年至今趨勢圖(藍線git, 紅線SVN):

圖片

中國2004年至今趨勢圖(藍線git, 紅線SVN):

圖片

SVN已經註定被放入歷史的記憶箱, 就像曾經的perl和pascal, 不會消失, 但會漸漸淡化, 直到成為老一輩程序員心中的記憶和口中的談資.

2. git stash 本地保存

SVN有個缺點, 代碼不方便本地保存, 我一般都是通過文件夾右鍵zip來保存本地修改. 相比之下, Git的本地保存功能很強大, 十分喜歡.

關於本地保存的優點, 講個故事:

有個同事, 曾經coding兩天在周五開發出一版UI, 拿給設計看, 設計不滿意, 就換了一種設計風格, 讓同事再實現一次. 同事周六周日加班了兩天, 把新的設計實現了, 拿給設計看, 結果設計說:」好像, 好像上一版更好看, 還是用上一版吧」. But, 同事的上一版代碼沒有保存, 只能憑着記憶把上一版代碼重新擼出來, 不知浪費多少時間和腦細胞.

SVN的保存都是push到中央代碼庫, 保存很重, 同事覺得沒完成的東西不應該push保存. 所以… 

相比之下, Git的保存就很輕, 可以先commit提交到本地保存, 或者stash保存. 等到開發完成後, 再push到遠端. 甚至, push到遠端的, 你還可以通過push -f覆蓋掉遠端的代碼(只建議強制push自己的庫, push -f master會死人的). 修改本地提交記錄和遠程提交記錄也不在話下, 比如git commit --amend修改最近一次提交記錄, git rebase -i "commit id"^ & git push -f修改本地提交記錄並強制推送到遠程.

git的本地保存中, 我覺得最好用的是git stash.

1.  當你在項目的一部分上已經工作一段時間後, 所有東西都進入了混亂的狀態, 而這時你想要切換到另一個分支做一點別的事情. 問題是, 你不想僅僅因為過會兒回到這一點而為做了一半的工作創建一次提交. 這時, 你可以選擇stash.

  1. 當你git pull代碼時, 提示代碼衝突, 拉下來可能會覆蓋本地代碼. 這時, 你可以先stash代碼, pull代碼後, 恢復stash的內容. 就算合併失敗, 還可以hard reset, 因為代碼在stash中還有一份, 不虛.

git stash 命令如下, 但是推薦使用sourcetree界面操作stash, 因為查看修改處比較方便, 而且不用記git又臭又長的命令.

_git stash_ list <options>    _git stash_ show <stash>    _git stash_ drop -q|--quiet    _git stash_ ( pop | apply ) --index <stash>    _git stash_ branch <branchname> <stash>    _git stash_ [push -p|--patch-k|--no-keep-index] -q|--quiet                    -u|--include-untracked -m|--message <message>                    --]    _git stash_ clear    _git stash_ create <message>    _git stash_ store -m|--message <message> <commit>

SourceTree UI操作stash:

SourceTree貼心的展示了stash分支和stash信息,超贊?,當你stash五次以上,會愛死這個功能。

圖片

點擊某次stash即可查看這個stash存的內容, 右鍵應用或者刪除stash.

圖片

3. git worktree checkout多個分支

最初使用時, Git的checkout使用體驗很不如SVN. 在SVN下, 習慣在branch下新建一個分支, 拉下來進行開發, 開發完成後把代碼push上去. 這樣不同的開發分支A和B是在不同的文件夾下的, 不會相互影響. 但是在Git下, checkout的分支還是在同一個目錄, 這樣就很不方便代碼管理.

比如featureA在開發中, featureB開發完成在測試中. 你正在featureA上開發, 測試忽然提了一個bug, 你需要checkout到featureB去修復. 修復後checkout回featureA, 但是你發現gradle需要同步, java需要重新編譯, 你需要10分鐘甚至更久才能恢復到你原來的代碼狀態. 這樣的bug來幾次, 你就要瘋了, 然後覺得git clone代碼, 放在不同的文件夾下是個挺好的主意. 需要checkout時, 就去不同的文件夾checkout, 相互不影響挺好.

幸好, git提供了worktree命令, 就是為了解決這種需要checkout多個分支的情況.

git worktree命令如下:

_git worktree add_ -f --checkout -b <new-branch> <path> <commit-ish>    _git worktree list_ --porcelain    _git worktree lock_ --reason <string> <worktree>    _git worktree move_ <worktree> <new-path>    _git worktree prune_ -n --expire <expire>    _git worktree remove_ -f <worktree>    _git worktree unlock_ <worktree>

一個例子:

使用 git worktree add ../locat_dir brach_name檢出分支到指定文件夾.

這樣在local_dir里的修改, 在主git庫里是沒有反應的, 也就不用擔心一個分支的修改影響另外一個分支. 不用擔心, 這個檢出的分支仍然是git託管的, 你可以正常的commit/push/pull/merge/rebase, 並且這個分支的stash是顯示在git主庫里的.

圖片

學會了git stash和git worktree後, 你的Git功力大漲不少.

不信? 你看下面的cheatsheet都沒有這兩個命令:

圖片