到現(xiàn)在,你應(yīng)該有能力查閱?git help?頁(yè),并理解幾乎所有東西。然而,查明解決特 定問題需要的確切命令可能是乏味的?;蛟S我可以省你點(diǎn)功夫:以下是我過去曾經(jīng)需要 的一些食譜。
就我的項(xiàng)目而言,Git完全跟蹤了我想打包并發(fā)布給用戶的文件。創(chuàng)建一個(gè)源碼包,我運(yùn) 行:
$ git archive --format=tar --prefix=proj-1.2.3/ HEAD
對(duì)特定項(xiàng)目而言,告訴Git你增加,刪除和重命名了一些文件很麻煩。而鍵入如下命令會(huì)容易的多:
$ git add .
$ git add -u
Git將查找當(dāng)前目錄的文件并自己算出具體的情況。除了用第二個(gè)add命令,如果你也打 算這時(shí)提交,可以運(yùn)行git commit -a
。關(guān)于如何指定應(yīng)被忽略的文件,參見?git help ignore?。
你也可以用一行命令完成以上任務(wù):
$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
這里?-z?和?-0?選項(xiàng)可以消除包含特殊字符的文件名引起的不良副作用。注意這個(gè) 命令也添加應(yīng)被忽略的文件,這時(shí)你可能需要加上?-x
?或?-X
?選項(xiàng)。
是不是忽視提交太久了?癡迷地編碼,直到現(xiàn)在才想起有源碼控制工具這回事?提交一 系列不相關(guān)的變更,因?yàn)槟鞘悄愕娘L(fēng)格?
別擔(dān)心,運(yùn)行:
$ git add -p
為你做的每次修改,Git將展示給你變動(dòng)的代碼,并詢問該變動(dòng)是否應(yīng)是下一次提交的一 部分?;卮稹皔”或者“n”。也有其他選項(xiàng),比如延遲決定;鍵入“?”來(lái)學(xué)習(xí)更多。
一旦你滿意,鍵入
$ git commit
來(lái)精確地提交你所選擇的變更(階段變更)。確信你沒加上?-a?選項(xiàng),否則Git將提交 所有修改。
如果你修改了許多地方的許多文件怎么辦?一個(gè)一個(gè)地查看變更令人沮喪,心態(tài)麻木。 這種情況下,使用?git add -i?, 它的界面不是很直觀,但更靈活。敲幾個(gè)鍵,你可 以一次決定階段或非階段性提交幾個(gè)文件,或查看并只選擇特定文件的變更。作為另一 種選擇,你還可以運(yùn)行?git commit --interactive?,這個(gè)命令會(huì)在你操作完后自動(dòng) 進(jìn)行提交。
當(dāng)目前為止,我們已經(jīng)忽略Git著名的'索引‘概念,但現(xiàn)在我們必須面對(duì)它,以解釋上 面發(fā)生的。索引是一個(gè)臨時(shí)中轉(zhuǎn)區(qū)。Git很少在你的項(xiàng)目和它的歷史之間直接倒騰數(shù)據(jù)。 通常,Git先寫數(shù)據(jù)到索引,然后拷貝索引中的數(shù)據(jù)到最終目的地。
例如,?commit -a?實(shí)際上是一個(gè)兩步過程。第一步把每個(gè)追蹤文件當(dāng)前狀態(tài)的快照放 到索引中。第二步永久記錄索引中的快照。 沒有?-a?的提交只執(zhí)行第二步,并且只在 運(yùn)行不知何故改變索引的命令才有意義,比如?git add?。
通常我們可以忽略索引并假裝從歷史中直接讀并直接寫。在這個(gè)情況下,我們希望更好 地控制,因此我們操作索引。我們放我們變更的一些的快照到索引中,而不是所有的, 然后永久地記錄這個(gè)小心操縱的快照。
HEAD好似一個(gè)游標(biāo),通常指向最新提交,隨最新提交向前移動(dòng)。一些Git命令讓你來(lái)移動(dòng) 它。 例如:
$ git reset HEAD~3
將立即向回移動(dòng)HEAD三個(gè)提交。這樣所有Git命令都表現(xiàn)得好似你沒有做那最后三個(gè)提交, 然而你的文件保持在現(xiàn)在的狀態(tài)。具體應(yīng)用參見幫助頁(yè)。
但如何回到將來(lái)呢?過去的提交對(duì)將來(lái)一無(wú)所知。
如果你有原先Head的SHA1值,那么:
$ git reset 1b6d
但假設(shè)你從來(lái)沒有記下呢?別擔(dān)心,像這些命令,Git保存原先的Head為一個(gè)叫 ORIG_HEAD的標(biāo)記,你可以安全體面的返回:
$ git reset ORIG_HEAD
或許ORIG_HEAD不夠?;蛟S你剛認(rèn)識(shí)到你犯了個(gè)歷史性的錯(cuò)誤,你需要回到一個(gè)早已忘記 分支上一個(gè)遠(yuǎn)古的提交。
默認(rèn),Git保存一個(gè)提交至少兩星期,即使你命令Git摧毀該提交所在的分支。難點(diǎn)是找 到相應(yīng)的哈希值。你可以查看在.git/objects里所有的哈希值并嘗試找到你期望的。但 有一個(gè)更容易的辦法。
Git把算出的提交哈希值記錄在“.git/logs”。這個(gè)子目錄引用包括所有分支上所有活 動(dòng)的歷史,同時(shí)文件HEAD顯示它曾經(jīng)有過的所有哈希值。后者可用來(lái)發(fā)現(xiàn)分支上一些不 小心丟掉提交的哈希值。
The reflog command provides a friendly interface to these log files. Try
命令reflog為訪問這些日志文件提供友好的接口,試試
$ git reflog
而不是從reflog拷貝粘貼哈希值,試一下:
$ git checkout "@{10 minutes ago}"
或者撿出后五次訪問過的提交,通過:
$ git checkout "@{5}"
更多內(nèi)容參見?git help rev-parse?的‘`Specifying Revisions’'部分。
你或許期望去為已刪除的提交設(shè)置一個(gè)更長(zhǎng)的保存周期。例如:
$ git config gc.pruneexpire "30 days"
意思是一個(gè)被刪除的提交會(huì)在刪除30天后,且運(yùn)行?git gc?以后,被永久丟棄。
你或許還想關(guān)掉?git gc?的自動(dòng)運(yùn)行:
$ git config gc.auto 0
在這種情況下提交將只在你手工運(yùn)行?git gc?的情況下才永久刪除。
依照真正的UNIX風(fēng)格設(shè)計(jì),Git允許其易于用作其他程序的底層組件,比如圖形界面, Web界面,可選擇的命令行界面,補(bǔ)丁管理工具,導(dǎo)入和轉(zhuǎn)換工具等等。實(shí)際上,一些 Git命令它們自己就是站在巨人肩膀上的腳本。通過一點(diǎn)修補(bǔ),你可以定制Git適應(yīng)你的 偏好。
一個(gè)簡(jiǎn)單的技巧是,用Git內(nèi)建alias命令來(lái)縮短你最常使用命令:
$ git config --global alias.co checkout
$ git config --global --get-regexp alias # 顯示當(dāng)前別名
alias.co checkout
$ git co foo # 和“git checkout foo”一樣
另一個(gè)技巧,在提示符或窗口標(biāo)題上打印當(dāng)前分支。調(diào)用:
$ git symbolic-ref HEAD
顯示當(dāng)前分支名。在實(shí)際應(yīng)用中,你可能最想去掉“refs/heads/”并忽略錯(cuò)誤:
$ git symbolic-ref HEAD 2> /dev/null | cut -b 12-
子目錄?contrib
?是一個(gè)基于Git工具的寶庫(kù)。它們中的一些時(shí)時(shí)會(huì)被提升為官方命令。 在Debian和Ubuntu,這個(gè)目錄位于?/usr/share/doc/git-core/contrib
?。
一個(gè)受歡迎的居民是?workdir/git-new-workdir
?。通過聰明的符號(hào)鏈接,這個(gè)腳本創(chuàng) 建一個(gè)新的工作目錄,其歷史與原來(lái)的倉(cāng)庫(kù)共享:
$ git-new-workdir an/existing/repo new/directory
這個(gè)新的目錄和其中的文件可被視為一個(gè)克隆,除了既然歷史是共享的,兩者的樹自動(dòng) 保持同步。不必合并,推入或拉出。
這些天,Git使得用戶意外摧毀數(shù)據(jù)變得更困難。但如若你知道你在做什么,你可以突破 為通用命令所設(shè)的防衛(wèi)保障。
Checkout:未提交的變更會(huì)導(dǎo)致?lián)斐鍪?。銷毀你的變更,并無(wú)論如何都checkout一 個(gè)指定的提交,使用強(qiáng)制標(biāo)記:
$ git checkout -f HEAD^
另外,如果你為撿出指定特別路徑,那就沒有安全檢查了。提供的路徑將被不加提示地 覆蓋。如你使用這種方式的檢出,要小心。
Reset: 如有未提交變更重置也會(huì)失敗。強(qiáng)制其通過,運(yùn)行:
$ git reset --hard 1b6d
Branch: 引起變更丟失的分支刪除會(huì)失敗。強(qiáng)制刪除,鍵入:
$ git branch -D dead_branch # instead of -d
類似,通過移動(dòng)試圖覆蓋分支,如果隨之而來(lái)有數(shù)據(jù)丟失,也會(huì)失敗。強(qiáng)制移動(dòng)分支,鍵入:
$ git branch -M source target # 而不是 -m
不像checkout和重置,這兩個(gè)命令延遲數(shù)據(jù)銷毀。這個(gè)變更仍然存儲(chǔ)在.git的子目錄里, 并且可以通過恢復(fù).git/logs里的相應(yīng)哈希值獲?。▍⒁娚厦?上面“HEAD獵捕”)。默 認(rèn)情況下,這些數(shù)據(jù)會(huì)保存至少兩星期。
Clean: 一些Git命令拒絕執(zhí)行,因?yàn)樗鼈儞?dān)心會(huì)重裝未納入管理的文件。如果你確信 所有未納入管理的文件都是消耗,那就無(wú)情地刪除它們,使用:
$ git clean -f -d
下次,那個(gè)討厭的命令就會(huì)工作!
愚蠢的錯(cuò)誤污染我的倉(cāng)庫(kù)。最可怕的是由于忘記?git add?而引起的文件丟失。較小 的罪過是行末追加空格并引起合并沖突:盡管危害少,我希望浙西永遠(yuǎn)不要出現(xiàn)在公開 記錄里。
不過我購(gòu)買了傻瓜保險(xiǎn),通過使用一個(gè)_鉤子_來(lái)提醒我這些問題:
$ cd .git/hooks
$ cp pre-commit.sample pre-commit # 對(duì)舊版本Git,先運(yùn)行chmod +x
現(xiàn)在Git放棄提交,如果檢測(cè)到無(wú)用的空格或未解決的合并沖突。
對(duì)本文檔,我最終添加以下到?pre-commit?鉤子的前面,來(lái)防止缺魂兒的事:
if git ls-files -o | grep '\.txt$'; then
echo FAIL! Untracked .txt files.
exit 1
fi
幾個(gè)git操作支持鉤子;參見?git help hooks?。我們?cè)缦燃せ盍俗鳛槔拥?post-update?鉤子,當(dāng)討論基于HTTP的Git的時(shí)候。無(wú)論head何時(shí)移動(dòng),這個(gè)鉤子都會(huì) 運(yùn)行。例子腳本post-update更新Git在基于Git并不知曉的傳輸協(xié)議,諸如HTTP,通訊時(shí) 所需的文件。
更多建議: