關(guān)注公眾號:“程序員成長軟技能” 职祷,日拱一卒盟榴,功不唐捐!
????????13個Git小技巧脏嚷,讓你擁有更有用更強(qiáng)大的代碼版本控制經(jīng)驗!
????????Git骆撇,一個分布式版本控制系統(tǒng),它已經(jīng)成為了開源界源碼版本控制的默認(rèn)工具然眼,在2018年4月7號它13歲了艾船。使用Git最令人沮喪的事情是,你不知道到底需要了解多少才能有效的使用它高每。但這也可能是使用Git感覺最棒的事情屿岂,因為沒有什么比發(fā)現(xiàn)一個新的技巧來簡化或改善你的工作流程更令人快樂了。
????????為了紀(jì)念Git的13歲生日鲸匿,這里提供13個技巧爷怀,讓你擁有更有用更強(qiáng)大的Git使用經(jīng)驗,從一些你可能會忽視的基礎(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版本庫全局配置選項的文件吁朦。通過你的~/.gitconfig文件你可以做很多事情,包括定義命令的別名渡贾,永久的打開(或關(guān)閉)一些特定的選項逗宜,還可以修改Git如何工作的方式(例如:git diff使用哪個diff算法,或者默認(rèn)使用什么類型的的合并策略)空骚。你甚至可以根據(jù)版本庫的路徑基于條件的包含其他配置纺讲!可以使用“man git-config”命令查看Git所有細(xì)節(jié)。
2囤屹、你的版本庫的.git/config文件
????????在之前的技巧中熬甚,你可能會想知道在git config 命令中的--global標(biāo)識是做什么的。它告訴Git是去更新“全局”配置肋坚,也就是在~/.gitconfig文件中的配置項乡括。當(dāng)然,擁有一個全局的配置意味著會有一個本地配置智厌,而且足夠肯定的是粟判,如果你省略--global選項,git config 命令會只更新這個版本庫自己的配置項峦剔,這個配置項存儲在.git/config文件中。在.git/config 中設(shè)置的選項會覆蓋在~/.gitconfig文件中的對應(yīng)選項的值角钩。所以吝沫,如果你需要在一個特定的版本庫中使用一個與之前不同的郵箱地址呻澜,你可以運(yùn)行g(shù)it config user.email "also_you@example.com"。然后惨险,你在這個版本庫中的任何提交都會使用你通過命令配置的這個郵箱地址羹幸。如果你使用同一臺電腦開展開源項目的工作和平時工作,并且你希望在開源項目中使用個人郵箱辫愉,而在平時工作時依舊使用在全局Git配置中配置的工作郵箱栅受,這個功能是非常有用的。
????????你可以在~/.gitconfig 中設(shè)置幾乎任何的東西恭朗,也都可以在.git/config中來對這個版本庫做特定的設(shè)置屏镊。在下面的這些技巧中,當(dāng)我提到在你的~/.gitconfig文件中添加任何東西時痰腮,你也可以為某個版本庫在其.git/config中做特定添加而芥。
3、別名
????????別名是你可以在你的~/.gitconfig 文件里做的另外一件事膀值。它的原理就像shell命令行里的別名一樣--設(shè)置一個新的命令名稱來調(diào)用一個或者多個其他的命令棍丐,這些命令通常包括一些特定的選項或標(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了一個開源項目访忿,而且在本地做了一些修改,這些修改不用提交給這個項目斯稳。我想在項目的持續(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赏枚、可視化提交圖
????????如果你從事的是一個有很多活躍分支的項目亡驰,有時候去掌握所有發(fā)生的工作以及它們間的相關(guān)性是比較困難的。很多GUI工具允許你使用被稱作“提交圖”的命令獲得一張圖呈現(xiàn)不同的分支以及提交饿幅。例如凡辱,以下是我使用GitLab提交圖展示我的倉庫可視化的一個片段。
????????如果你是熱衷于命令行的用戶栗恩,或者覺得切換工具會分散注意力透乾,很樂意通過命令行獲取類似“提交圖”功能的視圖。這就是git log命令--graph參數(shù)的由來:
????????這是使用下面命令獲得同一個倉庫可視化視圖的同一區(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 選項將圖表添加到日志的左側(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)險。當(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,在第一次實際提交前赌渣,你想把新添加的文件包含在提交中魏铅。
8、git add -p
????????使用GIt最好的實踐是確保每一次提交僅包括單一的邏輯變化--無論是修復(fù)一個bug還是添加一個新功能坚芜。然而览芳,在工作中,有時你會在一次提交中包含多個有意義的變化鸿竖。此時沧竟,你怎么把他們分開,使得每次提交只包含適當(dāng)?shù)男薷哪馗坑牵靠梢允褂胓it add --patch來搞定悟泵!
????????這個標(biāo)識將會使git add命令檢查你的本地工作副本,并且每次都會詢問你是否要要暫存闪水、提交糕非,跳過或者推遲決定(以及一些其他有用的選項,你可以通過在執(zhí)行這個命令后選擇“球榆?”查看)朽肥。git add -p是一個神奇的工具來生產(chǎn)結(jié)構(gòu)良好的提交。
9持钉、 git checkout -p
????????與git add -p類似衡招,git checkout命令可以使用--patch 或 -p 選項,這會使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
????????一些項目會有這樣的規(guī)則桑孩,版本庫中的每個提交都必須處于可工作狀態(tài)--也就是說,每次提交的內(nèi)容框冀,應(yīng)該是可編譯的流椒,或者測試套件不會執(zhí)行失敗。當(dāng)你在一個分支上工作了一段時間明也,出于一些原因宣虾,你需要去執(zhí)行一次rebase,此時你需要處理之前提交的所有commit温数,避免引入break绣硝。
????????幸運(yùn)的是,git rebase已經(jīng)支持了-x或--exec選項撑刺。git rebase -x <cmd>將在執(zhí)行rebase時處理每個提交時執(zhí)行命令(cmd)鹉胖。假如你在一個項目中使用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)建他們。其實不然袁辈,如果你提交到了本地工作空間菜谣,提交就會進(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
????????如果你在長時間周期的項目中使用branching-based工作流方式滋觉,除非你對合并后的分支清理是比較挑剔的签夭,否則你會有很多分支。這將會導(dǎo)致查找一個感興趣的分支比較困難椎侠,并且你無法看全分支“森林“第租。更糟糕的是,如果你有大量的活躍分支我纪,去判斷分支是否已經(jīng)合并(以及是否可以安全刪除)慎宾,將會比較繁瑣。
????????幸運(yùn)的是浅悉,Git僅僅使用git branch --merged就可以獲得已合并當(dāng)前分支的分支列表趟据,或者去確認(rèn)已合并到其他分支的分支。默認(rèn)的术健,這個命令將列出本地工作空間的分支情況汹碱,但是如果在命令中包括--remote
或者 -r
,它將會列出遠(yuǎn)程庫的合并的分支荞估。
????????重要提示:如果你計劃參考git branch --merged的輸出去刪除已合并的分支咳促,你必須知道,輸出結(jié)果里將會包括當(dāng)前分支勘伺。在執(zhí)行任何具有破壞性的操作時跪腹,記得排除當(dāng)前分支(或者,如果你忘記了娇昙,可以參考#12學(xué)習(xí)如何使用relog幫助你超會該分支)尺迂。
翻譯:https://opensource.com/article/18/4/git-tips
關(guān)注公眾號:“程序員成長軟技能” ,日拱一卒,功不唐捐噪裕!