你們仍未掌握那天所學的 git 知識

原文鏈接:你們仍未掌握那天所學的 git 知識

作者:YongHao_Hu

工作中必備 git 技能詳解

絕大多數人對於 git的認識只停留在git status, git add, git push, git pull, 好一點會知道git merge, 那就是全部了。

不信?

試試你能回答出以下問題不:

  • git push origin master命令中,origin 代表的是什麼,整個命令是什麼意思,origin 可以修改不
  • git fetch origin; git rebase origin master 這些命令知道嗎?跟 merge 有什麼區別?
  • git如何合併兩個補丁,對第三個補丁進行修改?(這個很重要,因為你不會才導致 git commit 的信息沒有意義,commit 不夠小和多)

又或者,你試過合併commit 嗎?commit message 寫的不好時如何修改?如何改變 commit 的順序?

如果以上有不清楚的話,那麼我希望以下的文章對你有幫助。

你所不知道的 github 初始化

初始創建一個 github 倉庫時,github 會給一些命令你去創建 git本地項目,git init就不用說了,git remote add origin git@github.com:YongHaoWu/test.git 你知道這裡的 origin 是什麼嗎?

是的,就僅僅是一個名字,對git@github.com:YongHaoWu/test.git 這個 ssh 地址的命名,你可以把origin命名為 gakki —— ` git remote add gakki git@github.com:YongHaoWu/test.git, 以後就可以用git push gakki master`了。

另外,你還可以 add好幾個名字,比如:你在 github 跟coding 同樣都有倉庫放代碼的情況。

git push -u origin master , 這裡就是把 master(默認 git 分支)推送到 origin, -u也就是--set-upstream, 代表的是更新默認推送的地方,這裡就是默認以後git pull和git push時,都是推送和拉自 origin 。

令 commit 更漂亮

對於 git 工作流,我認為commit 數要多而有意義,branch 也要多而有意義——也就是,一個小功能就要開一個分支,一個分支里要有一些有意義的 commit。 好處就是衝突會很少,review 代碼速度加快,commit 都是有意義的,而且利於回退。

要做到這些,離不開掌握git rebase

永遠使用 rebase

git rebasennReapply commits from one branch on top of another branch.nCommonly used to "move" an entire branch to another base, creating copies of the commits in the new location.n

相信你可以理解以上的英文:把 A 分支rebase 到 B 分支,也就是把 A 的 commit 與 B 的合併,並且保留 B 獨特的 commit。

還是很抽象,對吧?

看一個例子:git pull gakki feat-add-listener 這裡就是把 gakki 倉庫拉到 feat-add-listerner 分支。實際上,所做的東西等價於:

git fetch gakki //把 gakki 倉庫的東西都拉下來本地ngit rebase gakki/master feat-add-lister //把 gakki 的 master 分支 rebase 到 feat-add-listern

因為 pull 的時候, 當出現衝突而你解決掉後,會有多餘的merge信息(commit message),所以我是推薦在自己的分支開發時,永遠使用 fetch,rebase(不會出現多餘信息,處理衝突更加自由)

合併你的 commits

Author: YongHao Hu <hyh@vincross.com>nDate: Fri Dec 23 17:55:49 2016 +0800nn install skill: Fix skill pkg relative path.nncommit 37f37e46a2570c0989a46f39169bba510ebdabd8nAuthor: YongHao Hu <hyh@vincross.com>nDate: Fri Dec 23 10:51:09 2016 +0800nn mind: Add comments for understanding.nncommit 4eb9b9743d2bdc301a0e97f73d652f67adc82b32nAuthor: YongHao Hu <hyh@vincross.com>nDate: Thu Dec 22 15:00:02 2016 +0800nn skill-third-party: Add default include library.n

假設你又以上三個 commit,如何合併,修改呢? git rebase -i HEAD~4 對前四個補丁就行修改,就會進入以下界面:

pick 0194373 skill-third-party: Change PKG_CONFIG_PATH and LD_LIBRARY_PATH.npick 4eb9b97 skill-third-party: Add default include library.npick 37f37e4 mind: Add comments for understanding.npick 84c413a install skill: Fix skill pkg relative path.nn# Rebase 986e234..84c413a onto 986e234 (4 commands)n#n# Commands:n# p, pick = use commitn# r, reword = use commit, but edit the commit messagen# e, edit = use commit, but stop for amendingn# s, squash = use commit, but meld into previous commitn# f, fixup = like "squash", but discard this commits log messagen# x, exec = run command (the rest of the line) using shelln# d, drop = remove commitn#n# These lines can be re-ordered; they are executed from top to bottom.n#n# If you remove a line here THAT COMMIT WILL BE LOST.n#n# However, if you remove everything, the rebase will be aborted.n#n# Note that empty commits are commented outn

有以下常用操作:

  • 默認pick, 不做更改
  • reword:改 commit message
  • squash:當前補丁跟上一個補丁合併
  • fixup: 跟 squash 作用一樣,但是會丟棄當前 commit 信息,使用上一個的;squash 則是可以讓你重新寫

需要修改時,把上面四個補丁最前面的 pick 改成對應操作(如 reword,fixup),然後保存退出即可。

不用擔心的回退

回退大家應該都知道git reset --hard commitID, 把整個 git 回退到這個 commitID 里;

其實除了--hard, 還有 soft.

hard是把改動全部都丟棄,而soft則柔軟一些,僅僅是把所做的 commit 丟掉,而改動都保留在本地——通常用來修改,再重新 commit 一遍。

做了胡亂的更改,導致 git log都不正常,找不回那個 commit 了怎麼辦?

不用擔心, 還有 git reflog — Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository.

用它可以看到你對當前項目所做過的所有 git 操作,所有 git 操作的 id 號——意味著你可以回退到任意的時刻。

所以,只要你沒有把改動沒有做 commit 就丟失,又或者用git push -f把 github 倉庫覆蓋了,你就可以恢復任意時刻的東西。

git stash 暫存更改

時刻要注意,當前修改沒有 commit 的時候,不能 checkout 切換分支。

此時不想 commit,便需要 git stash 暫存更改;顧名思義,stash 使用 stack(棧)實現,所以可以 git stash存多次,然後切換分支後, git stash pop 撤出來

比 grep 更好用的 git grep

相比於 grep -R keyword ./ , 我是更喜歡用 git grep keyword, 差不多是一樣的,不過git grep只是會找當前的 目錄中git 有 track(跟蹤)的文件【也就是變動時,git status 會檢測到變化的文件】

超級進階:分割commit

commit 03bb9a14f5ea00d51d2edc14587b37b1ab9ccf5dnAuthor: YongHao Hu christopherwuy@gmail.comnDate: Fri Jul 10 17:23:02 2015 +0800nnmsvcp110: Add tr2_sys__Unlink implementation and test.nncommit 24137cd93c783ced61ca152cb4384287e6859ba4nAuthor: YongHao Hu christopherwuy@gmail.comnDate: Tue Jul 7 11:04:25 2015 +0800nnmsvcp110: Add tr2_sys__Symlink implementation and test.nncommit 51702048d9ecd1dc3887a63c057761a8547ce5f6nAuthor: YongHao Hu christopherwuy@gmail.comnDate: Thu Jul 2 23:23:51 2015 +0800nnmsvcp110: Add tr2_sys__Link implementation and test.n

假設我們想要分割 msvcp110: Add tr2_sys__Unlink implementation and test. 這個 commit,可以直接使用 git rebase -i HEAD~7(數字隨意,反正在 Unlink 這個 commit 前就可以了),選擇 Unlink 這個 commit, 改成 edit。 一般情況下,就是這樣修改 commit 的,修改後再 git rebase –continue.

但是,我們需要的是分割補丁: 選擇 git rebase HEAD^, 撤銷這次 commit,再把想改動的文件 git add, 再 git commit, 這樣就可以分割很多補丁。

最後,git rebase –continue 就可以了。

閱讀原文


推薦閱讀:

從0開始學習 GitHub 系列之「Git 進階」
Working with Git | 集中式工作流
如何理解git的快照?
起底Git系列——精通Git的捷徑
Git commits歷史是如何做到如此清爽的?

TAG:Git | GitHub | GIT项目 |