標籤:

25個Git用法技巧

Andy Jeffries 給 Git 中級用戶總結分享的 25 個小貼士。你不需要去做大量搜索,或許這些小貼士對你就很有幫助的。

我從開始使用git到現在已經差不多18個月了,以為自己已經很懂git了。直到我看到github上 Scott Chacon在 LVS, a supplier/developer of betting/gaming software 上的教學,第一天就受益匪淺。

作為一個很享受git的人,我想要分享從各種社區學到的實用經驗,讓大家不需要花費過多的功夫就能找到答案。

基本技巧1.安裝後的第一步

安裝git後,第一件事你需要設置你的名字和郵箱,因為每次提交都需要這些信息。

$ git config --global user.name "Some One"$ git config --global user.email "someone@gmail.com"

2.是基於指針的

git上的所有東西都是儲存在文件里的,當你創建一次提交時,它會創建一個包含你的提交信息和相關數據(名字,郵箱,日期/時間、上一次提交等等)的文件並連接一個樹文件,而這個樹文件包含了對象列表或者其他樹。這上面的對象或者blob文件就是這次提交的實際內容(你可以認為這也是一個文件,儘管並沒有儲存在對象里而是儲存在樹中)。所有的文件都以經過SHA-1計算後的文件名(譯者註:經過SHA-1計算後的數,即git中的版本號)儲存在上面。

從這裡可以看出,分支和標籤都是包含一個指向這次提交的sha-1數(版本號)簡單的文件,這樣使用引用會變得更快和更靈活,創建一個新的分支是就像創建文件一樣簡單,SHA – 1數(版本號)也會引用你這個分支的提交。當然,如果你使用GIT命令行工具(或者GUI)你將無法接觸這些。但真的很簡單。

你可能聽說過HEAD引用,這是一個指向你當前提交的內容的SHA-1 數(版本號)的指針。如果你正在解決合併衝突,使用HEAD不會對你的特定分支有任何改動只會指向你當前的分支。

所有分支的指針都保存在 .git/refs/heads,HEAD指針保存在.git/HEAD,標籤則保存在 .git/refs/tags,有時間就去看看吧。

3. 兩個母體(Parent),當然!

當我們在日誌文件中查看合併提交信息,你會看到兩個母體,第一個母體是正在進行的分支,第二個是你要合併的分支。

4.合併衝突

現在,我發現有合併衝突並解決了它,這是一件在我們編輯文件時很正常的事。將 <<<<, ====, >>>> 這些標記移除後,並保存你想要保存的代碼。有些時候在代碼被直接替代之前,能看到衝突是件挺不錯的事。比如在兩個衝突的分支變動之前,可以用這樣的命令方式:

$ git diff --mergediff --cc dummy.rb index 5175dde,0c65895..4a00477 --- a/dummy.rb+++ b/dummy.rb@@@ -1,5 -1,5 +1,5 @@@ class MyFoo def say- puts "Bonjour" - puts "Hello world"++ puts "Annyong Haseyo" end endIf the file is binary, diffing files isn』t so easy… What you』ll normally want to do is to try each version of the binary file and decide which one to use (or manually copy portions over in the binary file』s editor). To pull a copy of the file from a particular branch (say you』re merging master and feature132):

如果是二進位文件(binary),區別這些文件並不容易。通常你會查看每個二進位文件的版本,再決定使用哪個(或者在二進位文件編輯器中手動複製),並將其推送至特定的分支。(比如你要合併master和feature132)

$ git checkout master flash/foo.fla # or...$ git checkout feature132 flash/foo.fla$ # Then...$ git add flash/foo.flaAnother way is to cat the file from git – you can do this to another filename then copy the correct file over (when you』ve decided which it is) to the normal filename:

另一個方法就是在git中cat文件,你可以將其命名為另一個文件名,然後將你決定的那個文件改為正確的文件名:

$ git show master:flash/foo.fla > master-foo.fla$ git show feature132:flash/foo.fla > feature132-foo.fla$ # Check out master-foo.fla and feature132-foo.fla$ # Let"s say we decide that feature132"s is correct$ rm flash/foo.fla$ mv feature132-foo.fla flash/foo.fla$ rm master-foo.fla$ git add flash/foo.fla

更新:感謝carls在原博評論中提醒我,可以使用 「git checkout —ours flash/foo.fla」 和「git checkout —theirs flash/foo.fla」 在不用考慮你需要合併的分支來檢查指定版本,就我個人而言,我喜歡更明確的方法,但這也是一個選擇…

記住,解決完合併衝突後要添加文件。(我之前就犯過這樣的錯誤)

服務,分支和標註5. 遠程服務

Git有一個非常強大的特性,就是可以有多個遠程服務端(以及你運行的一個本地倉庫)。你不需要總是進行訪問,你可以有多個服務端並能從其中一個(合併工作)讀取再寫入另一個。添加一個遠程服務端很簡單:

$ git remote add john git@github.com:johnsomeone/someproject.gitIf you want to see information about your remote servers you can do:

如果你想查看遠程服務端的信息你可以:

# shows URLs of each remote server$ git remote -v # gives more details about each$ git remote show name You can always see the differences between a local branch and a remote branch:

你總是能看到本地分支和遠程分支不同的地方:

$ git diff master..john/masterYou can also see the changes on HEAD that aren』t on that remote branch:

你同樣也能看到遠程分支上沒有的HEAD指針的改動:

$ git log remote/branch..# Note: no final refspec after ..

6. Tagging 標籤

在Git中有兩種類型的標註:輕量級標註和注釋型標註。

記住第二個是Git的指針基礎,兩者區別很簡單,輕量級標註是簡單命名提交的指針,你可以將其指向另一個提交。注釋型標註是一個有信息和歷史並指向標註對象的名字指針,它有著自己的信息,如果需要的話,可以進行GPG標記。

創建兩種類型的標籤很簡單(其中一個命令行有改動)

$ git tag to-be-tested$ git tag -a v1.1.0 # Prompts for a tag message

7. Creating Branches 創建分支

在git中創建分支是件非常簡單的事情(非常快並只需要不到100byte的文件大小)。創建新分支並切換到該分支,通常是下面這樣的:

$ git branch feature132$ git checkout feature132

當然,如果你想切換到該分支,最直接的方式是使用這樣一條命令:

$ git checkout -b feature132

如果你想要重新命名本地分支,也很簡單:

$ git checkout -b twitter-experiment feature132$ git branch -d feature132

更新:或者你(Brian Palmer在原博的評論中指出的)可以使用 -m來切換到「git branch」(就像Mike指出,如果你只需要一個特定的分支,就可以重命名當前分支)

$ git branch -m twitter-experiment$ git branch -m feature132 twitter-experiment

8.合併分支

以後你可能回想合併你的變動,有兩種方式可以做到這一點:

$ git checkout master$ git merge feature83 # Or...$ git rebase feature83

merge和rebase的區別是,merge會嘗試解決改動並創建的新的提交來融合他們。rebase則是將從你最後一次從另一個分支分離之後的改動併入,並直接沿用另一個分支的head指針。儘管如此,在你往遠端伺服器上推送分支之前,不要使用rebase。這會讓你混亂。

如果你不能確定哪個分支(哪些需要合併,哪些需要移除)。這裡有兩個git分支切換方式來幫助你:

# Shows branches that are all merged in to your current branch$ git branch --merged# Shows branches that are not merged in to your current branch$ git branch --no-merged

9.遠程分支

如果你想將本地分支放置遠程服務端,你可以用這條命令進行推送:

$ git push origin twitter-experiment:refs/heads/twitter-experiment# Where origin is our server name and twitter-experiment is the branch

如果你想要從服務端刪除分支:

$ git push origin :twitter-experiment

如果你想要查看遠程分支的狀態:

$ git remote show origin

這將列出那些曾經存在而現在不存在的遠程分支,這將幫助你輕易地刪除你本地多餘的分支。

$ git remote prune

最後,如果本地追蹤遠程分支,常用方式是:

$ git branch --track myfeature origin/myfeature$ git checkout myfeature

儘管這樣,Git的新版本將啟動自動追蹤,如果你使用-b來checkout:

$ git checkout -b myfeature origin/myfeature

Storing Content in Stashes, Index and File System 在stash儲存內容、索引和文件系統10. Stashing

在Git中你可以將當前的工作區的內容保存到Git棧中並從最近的一次提交中讀取相關內容。以下是個簡單的例子:

$ git stash# Do something...$ git stash pop

很多人推薦使用git stash apply來代替pop。這樣子恢復後儲存的stash內容並不會刪除,而『pop』恢復的同時把儲存的stash內容也刪了 ,使用git stash apply 就可以移除任何棧中最新的內容。

<code data-language="javascript">$ git stash drop</code>

git可以自動創建基於當前提交信息的指令,如果你更喜歡使用通用的信息(相當於不會對前一次提交做任何改動)

<code data-language="javascript">$ git stash save "My stash message"</code>

如果你想使用某個stash(不一定是最後一個),你可以這樣將其列表顯示出來然後使用:

<code data-language="javascript">$ git stash list stash@{0}: On master: Changed to German stash@{1}: On master: Language is now Italian$ git stash apply stash@{1}</code>

11.添加交互

在svn中,如果你文件有了改動之後,然後會提交所有改動的文件,在 Git中為了能更好的提交特定的文件或者某個補丁,你需要在交互模式提交選擇提交的文件的內容。

$ git add -istaged unstaged path*** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: helpWhat now&gt;

這是基於菜單的互動式提示符。您可以使用命令前的數字或進入高亮字母(如果你有高亮輸入)模式。常用形式是,輸入你想執行的操作前的數字。(你可以像1或1 – 4或2、4、7的格式來執行命令)。

如果你想進入補丁模式(在交互模式中輸入p或5),同樣也可以這樣操作:

$ git add -p diff --git a/dummy.rb b/dummy.rb index 4a00477..f856fb0 100644 --- a/dummy.rb+++ b/dummy.rb@@ -1,5 +1,5 @@ class MyFoo def say- puts "Annyong Haseyo"+ puts "Guten Tag" end endStage this hunk [y,n,q,a,d,/,e,?]?

如你所見,你將在選擇添加改動的那部分文件的底部獲得一些選項。此外,使用「?」會說明這個選項。

12. 文件系統中的儲存/檢索

有些項目(比如Git自己的項目)需要直接在Git的文件系統中添加額外的並不想被檢查的文件。

讓我們開始在Git中保存隨機文件

$ echo "Foo" | git hash-object -w --stdin51fc03a9bb365fae74fd2bf66517b30bf48020cb

比如資料庫中的對象,如果你不想讓一些對象被垃圾回收,最簡單的方式是給它加標籤:

$ git tag myfile 51fc03a9bb365fae74fd2bf66517b30bf48020cb

在這裡我們設置myfile的標籤,當我們需要檢索該文件時可以這樣:

$ git cat-file blob myfile

這對開發者可能需要的但是並不想每次都去檢查的有用文件(密碼,gpg鍵等等)很管用(特別是在生產過程中)。

Logging and What Changed? 記錄日誌和什麼改變了?13. 查看日誌

在不使用「git log」的情況下,你不能查看你長期的最近提交內容,但是,仍然有一些更便於你使用的方法,比如,你可以這樣查看單次提交變動的內容:

$ git log -p

或者你只看文件變動的摘要:

$ git log --stat

這個很贊的別名,可以讓你在一行命令下簡化提交,並展示不錯的圖形化分支。

$ git config --global alias.lol "log --pretty=oneline --abbrev-commit --graph --decorate"$ git lol* 4d2409a (master) Oops, meant that to be in Korean* 169b845 Hello world

14.在日誌中查找

如果你想根據指定的作者查找:

$ git log --author=Andy

更新:感謝 Johannes的評論,解除了我的一些困惑,

或者你可以搜索你提交信息的內容:

$ git log --grep="Something in the message"

這些強大的指令被稱為pickaxe指令,來檢查被移除或添加特定塊的內容(比如,當他們第一次出現或者被移除),添加任何一行內容都會告訴你(但是並不包括那行內容剛剛被改動)

$ git log -S "TODO: Check for admin status"

如果你改動一個特定的文件會怎麼樣?如:lib/foo.rb

$ git log lib/foo.rb

如果你有feature/132 和ferature/145這兩個分支,並想查看這些不在master上的分支內容。( ^ 符號是意味著非)

$ git log feature/132 feature/145 ^master

你同樣可以使用ActiveSupport風格的日期來縮短時間範圍:

$ git log --since=2.months.ago --until=1.day.ago

默認會使用OR來合併查詢,但你也可改用AND(如果你有不止一個條件)

$ git log --since=2.months.ago --until=1.day.ago --author=andy -S "something" --all-match

15.選擇試圖/改動的之前的版本。

根據你知道的信息,可以按照以下方式來找到之前的版本:

$ git show 12a86bc38 # By revision$ git show v1.0.1 # By tag$ git show feature132 # By branch name$ git show 12a86bc38^ # Parent of a commit$ git show 12a86bc38~2 # Grandparent of a commit$ git show feature132@{yesterday} # Time relative$ git show feature132@{2.hours.ago} # Time relative

注意:不像前一部分所說,在最後的插入符號意味著提交的父類,在前面的插入符號意味著不在這個分支上。

16. 選擇一個方式

最簡單的方式:

$ git log origin/master..new# [old]..[new] - everything you haven"t pushed yet

你也可以省略[new],這樣將默認使用當前的HEAD指針。

Rewinding Time & Fixing Mistakes 回滾和修復錯誤17.重置更改

如果你沒有提交你可以簡單的撤銷改動:

$ git reset HEAD lib/foo.rb

通常我們使用」unstage「這樣的別名來代替:

$ git config --global alias.unstage "reset HEAD"$ git unstage lib/foo.rb

如果你已經提交了,有兩種情況:如果是最後一次提交你僅僅需要amend:

$ git commit --amend

這將不執行最後一次提交,恢復你原來的內容,提交信息將默認為你下次提交的信息。

如果你已經提交過不止一次了並且想完全回到之前那個記錄,你可以重置分支回到指定的時間。

$ git checkout feature132$ git reset --hard HEAD~2

如果你想將分支回滾但想要SHA1數(版本號)不一樣(也許你可以將分支的HEAD指向另一個分支,或者之後的提交),你可以通過如下方式:

$ git checkout FOO$ git reset --hard SHA

實際上還有個更快的方式(這樣並不會改變你的文件複製內容,並回歸到第一次FOO的狀態並指向SHA)

$ git update-ref refs/heads/FOO SHA

18. 提交至錯誤的分支

好吧,假定你提交到master上了,但是你想提交的是名為experimental的主題分支上,如果想移除這個改動,你可以在當前創建一個分支並將head指針回滾再檢查新的分支

$ git branch experimental # Creates a pointer to the current master state$ git reset --hard master~3 # Moves the master branch pointer back to 3 revisions ago$ git checkout experimental

如果你在分支的分支的分支進行了改動將會很麻煩,那麼你需要做的就是在其他處進行分支rebase改動

$ git branch newtopic STARTPOINT$ git rebase oldtopic --onto newtopic

19. rebase的交互

這是個很不錯的功能,我曾看過演示但一直以來並沒有真正搞懂,現在我知道了,非常簡單。假如你進行了三次提交,但是你想重新編輯它們(或者結合它們)。

$ git rebase -i master~3

然後你讓你的編輯器打開一些指令,你需要做的就是修改指令來選擇/squash/編輯(或刪除)/提交和保存/退出,編輯完使用git rebase —continue 來通過你的每一個指令。

如果你選擇編輯一個,它將離開你的提交狀態,所以你需要使用git commit -amend來編輯它。

注意:不要在rebase的時候提交——只能添加了之後再使用—continue, —skip 或—abort.

20. 清除

如果你在分支中提交了一些內容(也許是一些SVN上老的資源文件)並想從歷史記錄中完全移除,可以這樣:

$ git filter-branch --tree-filter "rm -f *.class" HEAD

如果你已經將其推送至origin,並提交了一些垃圾內容,你同樣可以推送之前在本地系統這樣做:

$ git filter-branch --tree-filter "rm -f *.class" origin/master..HEAD

Miscellaneous Tips 各種各樣的技巧21.你看過的前面的引用

如果你知道你之前看到的SHA-1數(版本號),並需要進行一些重置/回滾,可以使用reflog命令查詢最近查看的sha – 1數(版本號):

$ git reflog$ git log -g # Same as above, but shows in "log" format

22. 分支命名

一個有趣的小技巧,不要忘記分支名不僅僅限於a-z和0-9,在名字中使用/和.用於命名偽命名空間和版本控制,也是個不錯的主意,例如:

$ # Generate a changelog of Release 132$ git shortlog release/132 ^release/131$ # Tag this as v1.0.1$ git tag v1.0.1 release/132

23. 找到Dunnit

找出誰在一個文件中改變了一行代碼,簡單的命令是:

$ git blame FILE

有時候是上一個文件發生了變動(如果你合併兩個文件,或者你已經轉移到一個函數),這樣你就可以使用:

$ # shows which file names the content came from$ git blame -C FILE

有時候需要通過點擊來追蹤來回的變動,這裡有一個不錯的內置gui:

$ git gui blame FILE

24. 資料庫維護

通常Git並不需要過多的維護,它幾乎可以自己搞定,儘管如此你也可以查看資料庫使用的統計:

$ git count-objects -v

如果數值過高你可以選擇將你的克隆垃圾回收。這不會影響你推送內容或其他人,但它可以讓你的命令運行的更快,並使用更少的空間:

$ git gc

它也可以在運行時進行一致性檢驗:

$ git fsck --full

你可以在後面添加-auto 參數(如果你在伺服器跑定時任務時),這在統計數據時是必須的。

當檢查的結果是「dangling」或「unreachable」這樣的是正常的,這通常是回滾和rebase的結果。 得到「missing」 或 「sha1 mismatch」 這樣的結果是不好的…你需要得到專業的幫助!

25. 恢復失去的分支

如果你意外的刪除一個分支,可以重新創建它:

$ git branch experimental SHA1_OF_HASH

你可以使用git reflog查看你最近訪問過的SHA1數(版本號)

另一個方式就是使用 git fsck —lost-found ,懸空對象(dangling commit )是就是失去HEAD指針的提交,(刪除的分支只是失去了HEAD指針成為懸空對象)

Done!完成!

這篇是我寫過最長的博文,希望大家能從此文中獲益,如果你有所收益或是有任何問題都可以在評論中告訴我!


推薦閱讀:

餐飲服務57個技巧
引用 【引用】攝影知識及技巧(一)請跟我學!
八字命理後天補救法——補「火」的技巧
職場背調有訣竅,作為HR不能不知道
胖人穿衣有技巧 ,學會這幾種搭配瘦成閃電!

TAG:技巧 |