我最初在一個(gè)私人項(xiàng)目上使用Git,那里我是唯一的開發(fā)。在與Git分布式本性有關(guān)的命 令中,我只用到了?pull?和 clone,用以在不同地方保持同一個(gè)項(xiàng)目。
后來我想用Git發(fā)布我的代碼,并且包括其他貢獻(xiàn)者的變更。我不得不學(xué)習(xí)如何管理有來 自世界各地的多個(gè)開發(fā)的項(xiàng)目,幸運(yùn)的是,這是Git的長處,也可以說是其存在的理由。
每個(gè)提交都有一個(gè)作者姓名和電子信箱,這顯示在?git log?里。默認(rèn), Git使用系統(tǒng) 設(shè)定來填充這些域。要顯示地設(shè)定,鍵入:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
去掉global選項(xiàng)設(shè)定只對(duì)當(dāng)前倉庫生效。
假設(shè)你有ssh訪問權(quán)限,以訪問一個(gè)網(wǎng)頁服務(wù)器,但上面并沒有安裝Git。盡管比著它的 原生協(xié)議效率低,Git也是可以通過HTTP來進(jìn)行通信的。
那么在你的帳戶下,下載,編譯并安裝Git。在你的網(wǎng)頁目錄里創(chuàng)建一個(gè)Git倉庫:
$ GIT_DIR=proj.git git init
$ cd proj.git
$ git --bare update-server-info
$ cp hooks/post-update.sample hooks/post-update
對(duì)較老版本的Git,只拷貝還不夠,你應(yīng)運(yùn)行:
$ chmod a+x hooks/post-update
現(xiàn)在你可以通過SSH從隨便哪個(gè)克隆發(fā)布你的最新版本:
$ git push web.server:/path/to/proj.git master
那隨便誰都可以通過如下命令得到你的項(xiàng)目:
$ git clone http://web.server/proj.git
想無需服務(wù)器,甚至無需網(wǎng)絡(luò)連接的時(shí)候同步倉庫?需要在緊急時(shí)期湊合一下?我們 已經(jīng)看過git fast-export?和?git fast-import?可以轉(zhuǎn)換資源 庫到一個(gè)單一文件以及轉(zhuǎn)回來。 我們可以來來會(huì)會(huì)傳送這些文件以傳輸git倉庫, 通過任何媒介,但一個(gè)更有效率的工具是?git bundle?。
發(fā)送者創(chuàng)建一個(gè)“文件包”:
$ git bundle create somefile HEAD
然后傳輸這個(gè)文件包,?somefile
?,給某個(gè)其他參與者:電子郵件,優(yōu)盤,一個(gè)?xxd?打印品和一個(gè)OCR掃描儀,通過電話讀字節(jié),狼煙,等等。接收者通過鍵入如下命 令從文件包獲取提交:
$ git pull somefile
接收者甚至可以在一個(gè)空倉庫做這個(gè)。不考慮大小,?somefile
?可以包含整個(gè)原先 git倉庫。
在較大的項(xiàng)目里,可以通過只打包其他倉庫缺少的變更消除浪費(fèi)。例如,假設(shè)提交 ‘`1b6d…’'是兩個(gè)參與者共享的最近提交:
$ git bundle create somefile HEAD ^1b6d
如果做的頻繁,人可能容易忘記剛發(fā)了哪個(gè)提交。幫助頁面建議使用標(biāo)簽解決這個(gè)問題。 即,在你發(fā)了一個(gè)文件包后,鍵入:
$ git tag -f lastbundle HEAD
并創(chuàng)建較新文件包,使用:
$ git bundle create newbundle HEAD ^lastbundle
補(bǔ)丁是變更的文本形式,易于計(jì)算機(jī)理解,人也類似。補(bǔ)丁可以通吃。你可以給開發(fā)電 郵一個(gè)補(bǔ)丁,不用管他們用的什么版本控制系統(tǒng)。只要你的觀眾可以讀電子郵件,他們 就能看到你的修改。類似,在你這邊,你只需要一個(gè)電子郵件帳號(hào):不必搭建一個(gè)在線 的Git倉庫。
回想一下第一章:
$ git diff 1b6d > my.patch
輸出是一個(gè)補(bǔ)丁,可以粘貼到電子郵件里用以討論。在一個(gè)Git倉庫,鍵入:
$ git apply < my.patch
來打這個(gè)補(bǔ)丁。
在更正式些的設(shè)置里,當(dāng)作者名字以及或許簽名應(yīng)該記錄下的時(shí)候,為過去某一刻生成 補(bǔ)丁,鍵入:
$ git format-patch 1b6d
結(jié)果文件可以給?git-send-email?發(fā)送,或者手工發(fā)送。你也可以指定一個(gè)提交范圍:
$ git format-patch 1b6d..HEAD^^
在接收一端,保存郵件到一個(gè)文件,然后鍵入:
$ git am < email.txt
這就打了補(bǔ)丁并創(chuàng)建了一個(gè)提交,包含諸如作者之類的信息。
使用瀏覽器郵件客戶端,在保存補(bǔ)丁為文件之前,你可能需要建一個(gè)按鈕,看看郵件內(nèi) 容原來的原始形式。
對(duì)基于mbox的郵件客戶端有些微不同,但如果你在使用的話,你可能是那種能輕易找出 答案的那種人,不用讀教程。
克隆一個(gè)倉庫后,運(yùn)行?git push?或?git pull?講自動(dòng)推到或從原先URL拉。Git 如何做這個(gè)呢?秘密在和克隆一起創(chuàng)建的配置選項(xiàng)。讓我們看一下:
$ git config --list
選項(xiàng)?remote.origin.url
?控制URL源;“origin” 是給源倉庫的昵稱。和 “master” 分支的慣例一樣,我們可以改變或刪除這個(gè)昵稱,但通常沒有理由這么做。
如果原先倉庫移走,我們可以更新URL,通過:
$ git config remote.origin.url git://new.url/proj.git
選項(xiàng)?branch.master.merge
?指定?git pull?里的默認(rèn)遠(yuǎn)端分支。在初始克隆的時(shí)候, 它被設(shè)為原倉庫的當(dāng)前分支,因此即使原倉庫之后挪到一個(gè)不同的分支,后來的 pull也將忠實(shí)地跟著原來的分支。
這個(gè)選項(xiàng)只使用我們初次克隆的倉庫,它的值記錄在選項(xiàng)?branch.master.remote
?。如果我們從其他倉庫拉入,我們必須顯示指定我們想要哪個(gè)分支:
$ git pull git://example.com/other.git master
以上也解釋了為什么我們較早一些push和pull的例子沒有參數(shù)。
當(dāng)你克隆一個(gè)倉庫,你也克隆了它的所有分支。你或許沒有注意到因?yàn)镚it將它們隱藏 起來了:你必須明確地要求。這使得遠(yuǎn)端倉庫里的分支不至于干擾你的分支,也使 Git對(duì)初學(xué)者稍稍容易些。
列出遠(yuǎn)端分支,使用:
$ git branch -r
你應(yīng)該看到類似:
origin/HEAD
origin/master
origin/experimental
這顯示了遠(yuǎn)端倉庫的分支和HEAD,可以用在常用的Git命令里。例如,假設(shè)你已經(jīng)做了 很多提交,并希望和最后取到的版本比較一下。你可以搜索適當(dāng)?shù)腟HA1哈希值,但使用 下面命令更容易些:
$ git diff origin/HEAD
或你可以看看‘`experimental’'分支都有啥:
$ git log origin/experimental
假設(shè)另兩個(gè)開發(fā)在同一個(gè)項(xiàng)目上工作,我們希望保持兩個(gè)標(biāo)簽。我們可以同事跟多個(gè)倉庫:
$ git remote add other git://example.com/some_repo.git
$ git pull other some_branch
現(xiàn)在我們已經(jīng)從第二個(gè)倉庫合并到一個(gè)分支,并且我們已容易訪問所有倉庫的所有 分支。
$ git diff origin/experimental^ other/some_branch~5
但如果為了不影響自己的工作,我們只想比較他們的變更怎么辦呢?換句話說,我們想 檢查一下他們的分支,又不使他們的變更入侵我們的工作目錄。那不是運(yùn)行pull命令, 而是運(yùn)行:
$ git fetch # Fetch from origin, the default.
$ git fetch other # Fetch from the second programmer.
這只是獲取歷史。盡管工作目錄維持不變,我們可以參考任何倉庫的任何分支,使用 一個(gè)Git命令,因?yàn)槲覀儸F(xiàn)在有一個(gè)本地拷貝。
回想一下,在幕后,一個(gè)pull是簡單地一個(gè)?fetch?然后?merge?。通常,我們?pull?因?yàn)槲覀兿朐讷@取后合并最近提交;這個(gè)情況是一個(gè)值得注意的例外。
關(guān)于如何去除遠(yuǎn)端倉庫,如何忽略特定分支等更多,參見?git help remote?。
對(duì)我手頭的項(xiàng)目,我喜歡貢獻(xiàn)者去準(zhǔn)備倉庫,這樣我可以從其中拉。一些Git伺服讓你 點(diǎn)一個(gè)按鈕,擁有自己的分叉項(xiàng)目。
在我獲取一個(gè)樹之后,我運(yùn)行Git命令去瀏覽并檢查這些變更,理想情況下這些變更組織 良好,描述良好。我合并這些變更,也或許做些編輯。直到滿意,我才把變更推入主資 源庫。
盡管我不經(jīng)常收到貢獻(xiàn),我相信這個(gè)方法擴(kuò)展性良好。參見?這篇 來自Linus Torvalds的博客
呆在Git的世界里比補(bǔ)丁文件稍更方便,因?yàn)椴挥梦覍⒀a(bǔ)丁轉(zhuǎn)換到Git提交。更進(jìn)一步, Git處理諸如作者姓名和信箱地址的細(xì)節(jié),還有時(shí)間和日期,以及要求作者描述他們的提 交。
更多建議: