13個Git小技巧獻(xiàn)給Git的13歲

關(guān)注公眾號:“程序員成長軟技能” ,日拱一卒,功不唐捐!
????????13個Git小技巧,讓你擁有更有用更強(qiáng)大的代碼版本控制經(jīng)驗(yàn)!
????????Git,一個分布式版本控制系統(tǒng),它已經(jīng)成為了開源界源碼版本控制的默認(rèn)工具,在2018年4月7號它13歲了。使用Git最令人沮喪的事情是,你不知道到底需要了解多少才能有效的使用它。但這也可能是使用Git感覺最棒的事情,因?yàn)闆]有什么比發(fā)現(xiàn)一個新的技巧來簡化或改善你的工作流程更令人快樂了。
????????為了紀(jì)念Git的13歲生日,這里提供13個技巧,讓你擁有更有用更強(qiáng)大的Git使用經(jīng)驗(yàn),從一些你可能會忽視的基礎(chǔ)擴(kuò)展到一些真正的高級用戶技巧!

1、你的 ~/.gitconfig 文件

????????當(dāng)你第一次用Git命令來提交修改到倉庫時,你可能會收到如下提示:

*** Please tell me who you are.
Run
  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"
to set your account's default identity.

????????你可能還沒有意識到那些命令正在修改~/.gitconfig 文件的內(nèi)容,這個文件就是Git版本庫全局配置選項(xiàng)的文件。通過你的~/.gitconfig文件你可以做很多事情,包括定義命令的別名,永久的打開(或關(guān)閉)一些特定的選項(xiàng),還可以修改Git如何工作的方式(例如:git diff使用哪個diff算法,或者默認(rèn)使用什么類型的的合并策略)。你甚至可以根據(jù)版本庫的路徑基于條件的包含其他配置!可以使用“man git-config”命令查看Git所有細(xì)節(jié)。

2、你的版本庫的.git/config文件

????????在之前的技巧中,你可能會想知道在git config 命令中的--global標(biāo)識是做什么的。它告訴Git是去更新“全局”配置,也就是在~/.gitconfig文件中的配置項(xiàng)。當(dāng)然,擁有一個全局的配置意味著會有一個本地配置,而且足夠肯定的是,如果你省略--global選項(xiàng),git config 命令會只更新這個版本庫自己的配置項(xiàng),這個配置項(xiàng)存儲在.git/config文件中。在.git/config 中設(shè)置的選項(xiàng)會覆蓋在~/.gitconfig文件中的對應(yīng)選項(xiàng)的值。所以,如果你需要在一個特定的版本庫中使用一個與之前不同的郵箱地址,你可以運(yùn)行g(shù)it config user.email "also_you@example.com"。然后,你在這個版本庫中的任何提交都會使用你通過命令配置的這個郵箱地址。如果你使用同一臺電腦開展開源項(xiàng)目的工作和平時工作,并且你希望在開源項(xiàng)目中使用個人郵箱,而在平時工作時依舊使用在全局Git配置中配置的工作郵箱,這個功能是非常有用的。
????????你可以在~/.gitconfig 中設(shè)置幾乎任何的東西,也都可以在.git/config中來對這個版本庫做特定的設(shè)置。在下面的這些技巧中,當(dāng)我提到在你的~/.gitconfig文件中添加任何東西時,你也可以為某個版本庫在其.git/config中做特定添加。

3、別名

????????別名是你可以在你的~/.gitconfig 文件里做的另外一件事。它的原理就像shell命令行里的別名一樣--設(shè)置一個新的命令名稱來調(diào)用一個或者多個其他的命令,這些命令通常包括一些特定的選項(xiàng)或標(biāo)識。別名對于那些經(jīng)常被使用的又長又復(fù)雜的命令是非常有效的。
????????你可以使用git config命令來定義別名--例如,執(zhí)行g(shù)it config --global --add alias.st status 命令后,會使得執(zhí)行g(shù)it st與執(zhí)行g(shù)it status做同樣的事情。但是,我發(fā)現(xiàn)定義別名的時候,經(jīng)常是直接在~/.gitconfig文件里編輯會更加容易。
????????如果你選擇這么去做,你會發(fā)現(xiàn)~/.gitconfig文件是一個INI文件。INI是一種帶有特定區(qū)段的基礎(chǔ)鍵值對文件格式。當(dāng)去添加一個別名時,你將改變[alias] 區(qū)段。例如:同樣是去定義git st別名,在文件中添加下面的代碼:

[alias]
st = status

(如果已經(jīng)有了[alias]這個區(qū)段,只是要將上邊第二行內(nèi)容添加到區(qū)段里。)

4、 shell命令中的別名

????????別名不僅可以用來運(yùn)行Git子命令,你也可以定義運(yùn)行其他shell命令的別名。這是一個很好的方法來處理一個重復(fù)的、不常見的、復(fù)雜的任務(wù):一旦你第一次弄明白了怎么去寫這個命令,那就使用一個別名保存它。例如,我有個版本庫是我fork了一個開源項(xiàng)目,而且在本地做了一些修改,這些修改不用提交給這個項(xiàng)目。我想在項(xiàng)目的持續(xù)的開發(fā)的過程中能保持最新的版本,同時保留我的本地修改。為了完成這個想法,我需要定期地從upstream倉庫中合并這些修改到我的fork,我定義一個叫做“upstream-merge” 別名來完成這個操作。定義如下:

upstream-merge = !"git fetch origin -v && git fetch upstream -v && git merge upstream/master && git push"

????????定義別名最前面的這個“!”是告訴Git通過shell來運(yùn)行這個命令。這個例子涉及到執(zhí)行多個git命令,但是使用這種方式定義別名可以運(yùn)行任何shell命令。? (注意:如果你想復(fù)制我的upstream-merge別名,你需要確保有一個命名為upstream的Git remote指向你fork的上游倉庫。你可以通過“git remote add upstream <URL to repo>”來添加一個。)

5、可視化提交圖

????????如果你從事的是一個有很多活躍分支的項(xiàng)目,有時候去掌握所有發(fā)生的工作以及它們間的相關(guān)性是比較困難的。很多GUI工具允許你使用被稱作“提交圖”的命令獲得一張圖呈現(xiàn)不同的分支以及提交。例如,以下是我使用GitLab提交圖展示我的倉庫可視化的一個片段。

John Anderson, CC BY

????????如果你是熱衷于命令行的用戶,或者覺得切換工具會分散注意力,很樂意通過命令行獲取類似“提交圖”功能的視圖。這就是git log命令--graph參數(shù)的由來:
John Anderson, CC BY

????????這是使用下面命令獲得同一個倉庫可視化視圖的同一區(qū)段:

it log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'
 --abbrev-commit --date=relative

????????其中--graph 選項(xiàng)將圖表添加到日志的左側(cè),--abbrev-commit 縮短commit的SHAs值,--date=relative 用相對的術(shù)語來表示日期,--pretty 處理所有自定義的輸出格式。我將此映射向 git lg 別名,它是我最常運(yùn)行的10個命令之一。

6、優(yōu)雅的強(qiáng)制推送(force-push)

????????盡管你努力去避免,但有時還是需要去執(zhí)行g(shù)it push --force去覆蓋遠(yuǎn)程版本庫的歷史記錄。你可能是收到了一些反饋,導(dǎo)致你去執(zhí)行交互式的rebase,或者你只是搞砸了,想隱藏證據(jù)。
????????在其他人對遠(yuǎn)程倉庫的同一個分支上做了改動后,使用強(qiáng)制推送會有風(fēng)險(xiǎn)。當(dāng)你使用force-push重寫提交歷史,之前的提交就會丟失。這是 git push --force-with-lease 出現(xiàn)的原因--如果遠(yuǎn)程分支已更新,它不會允許你執(zhí)行強(qiáng)制推送,這將確保你不會弄丟其他人的工作。

7、 git add -N

????????你是否使用過git commit -a在一個命令中將所有修改暫存并提交,在你執(zhí)行push推送后才發(fā)現(xiàn)commit -a忽略了新添加的文件?解決這個問題你可以用git add -N(“通知”)來告訴Git,在第一次實(shí)際提交前,你想把新添加的文件包含在提交中。

8、git add -p

????????使用GIt最好的實(shí)踐是確保每一次提交僅包括單一的邏輯變化--無論是修復(fù)一個bug還是添加一個新功能。然而,在工作中,有時你會在一次提交中包含多個有意義的變化。此時,你怎么把他們分開,使得每次提交只包含適當(dāng)?shù)男薷哪??可以使用git add --patch來搞定!
????????這個標(biāo)識將會使git add命令檢查你的本地工作副本,并且每次都會詢問你是否要要暫存、提交,跳過或者推遲決定(以及一些其他有用的選項(xiàng),你可以通過在執(zhí)行這個命令后選擇“?”查看)。git add -p是一個神奇的工具來生產(chǎn)結(jié)構(gòu)良好的提交。

9、 git checkout -p

????????與git add -p類似,git checkout命令可以使用--patch 或 -p 選項(xiàng),這會使Git在本地工作副本中展示每個“大塊”的修改,并且允許丟棄對應(yīng)改動--簡單的說就是恢復(fù)本地工作副本到你改變之前的狀態(tài)。
????????在某些情況下這非常有用,例如,在你跟蹤定位某個bug時引入了一堆條數(shù)日志語句。在修復(fù)這個bug后,你可以先使用git checkout -p刪除所有新添加的調(diào)試日志,然后使用git add -p去添加修復(fù)過bug的部分。沒有什么比組合一個優(yōu)美的、結(jié)構(gòu)良好的提交更令人滿意的了。

10、Rebase with command execution

????????一些項(xiàng)目會有這樣的規(guī)則,版本庫中的每個提交都必須處于可工作狀態(tài)--也就是說,每次提交的內(nèi)容,應(yīng)該是可編譯的,或者測試套件不會執(zhí)行失敗。當(dāng)你在一個分支上工作了一段時間,出于一些原因,你需要去執(zhí)行一次rebase,此時你需要處理之前提交的所有commit,避免引入break。
????????幸運(yùn)的是,git rebase已經(jīng)支持了-x或--exec選項(xiàng)。git rebase -x <cmd>將在執(zhí)行rebase時處理每個提交時執(zhí)行命令(cmd)。假如你在一個項(xiàng)目中使用npm run tests執(zhí)行測試套件,那么git rebase -x npm run tests 可以在執(zhí)行rebase期間,每次處理commit時執(zhí)行測試套件。這使你可以查看測試套件在變基后的任何提交中是否有失敗情況,因此你可以確保測試套件在每次提交時都仍能通過。

11、 Time-based revision references

????????很多Git子命令都接受一個修正參數(shù)來決定命令作用于倉庫的哪個部分,可能是某特定commit的SHA1值,一個分支名,或者一個類似HEAD(指向當(dāng)前檢出分支最近一次的commit)的符號名。除了這些簡單的形式以外,你還可以附加一個具體的日期或時間,表示“這個時間的引用”。
????????當(dāng)你在處理一個新引進(jìn)的bug,并自言自語“昨天還能正常工作,有了什么變化?”時,這個功能將會變得十分有用。你只需執(zhí)行g(shù)it diff HEAD@{yesterday},就能看到從{yesterday}以來的所有變化,而不再需要從git log的輸出中查找變化。這個命令也可以使用時間段(例如 git diff HEAD@{'2 months ago'})或者一個確切的日期(例如 git diff HEAD@{'2010-01-01 12:00:00'})。
你還可以將這些基于日期的修正參數(shù)用于其他任意支持修正參數(shù)的Git子命令。在man gitrevisions的說明頁中有所有使用方式的詳細(xì)說明。

12、The all-seeing reflog

????????你有沒有在rebase時放棄過某個commit,然后發(fā)現(xiàn)在這次commit里還有些想保留東西?你可能會覺得這些東西是永久的丟失了,只能重新創(chuàng)建他們。其實(shí)不然,如果你提交到了本地工作空間,提交就會進(jìn)入到引用日志 (reflog), ,你仍然可以訪問到它們。
????????執(zhí)行g(shù)it reflog可以查看本地工作空間當(dāng)前branch所有的活動,并能看到每次commit的SHA1。一旦你找到了你rebase時丟棄的commit,你可以執(zhí)行 git checkout <SHA1> 檢出該次commit,復(fù)制你想要的信息,然后執(zhí)行git checkout HEAD 返回該branch最新提交。

13、Cleaning up after yourself

????????如果你在長時間周期的項(xiàng)目中使用branching-based工作流方式,除非你對合并后的分支清理是比較挑剔的,否則你會有很多分支。這將會導(dǎo)致查找一個感興趣的分支比較困難,并且你無法看全分支“森林“。更糟糕的是,如果你有大量的活躍分支,去判斷分支是否已經(jīng)合并(以及是否可以安全刪除),將會比較繁瑣。
????????幸運(yùn)的是,Git僅僅使用git branch --merged就可以獲得已合并當(dāng)前分支的分支列表,或者去確認(rèn)已合并到其他分支的分支。默認(rèn)的,這個命令將列出本地工作空間的分支情況,但是如果在命令中包括--remote 或者 -r,它將會列出遠(yuǎn)程庫的合并的分支。
????????重要提示:如果你計(jì)劃參考git branch --merged的輸出去刪除已合并的分支,你必須知道,輸出結(jié)果里將會包括當(dāng)前分支。在執(zhí)行任何具有破壞性的操作時,記得排除當(dāng)前分支(或者,如果你忘記了,可以參考#12學(xué)習(xí)如何使用relog幫助你超會該分支)。

翻譯:https://opensource.com/article/18/4/git-tips

關(guān)注公眾號:“程序員成長軟技能” ,日拱一卒,功不唐捐!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容