在較老一代的版本控制系統(tǒng)里,checkout是獲取文件的標(biāo)準(zhǔn)操作。你將獲得一組特定保 存狀態(tài)的文件。
在Git和其他分布式版本控制系統(tǒng)里,克隆是標(biāo)準(zhǔn)的操作。通過(guò)創(chuàng)建整個(gè)倉(cāng)庫(kù)的克隆來(lái) 獲得文件?;蛘哒f(shuō),你實(shí)際上把整個(gè)中心服務(wù)器做了個(gè)鏡像。凡是主倉(cāng)庫(kù)上能做的事, 你都能做。
我可以忍受制作tar包或利用rsync來(lái)作備份和基本同步。但我有時(shí)在我筆記本上編輯, 其他時(shí)間在臺(tái)式機(jī)上,而且這倆之間也許并不交互。
在一個(gè)機(jī)器上初始化一個(gè)Git倉(cāng)庫(kù)并提交你的文件。然后轉(zhuǎn)到另一臺(tái)機(jī)器上:
$ git clone other.computer:/path/to/files
以創(chuàng)建這些文件和Git倉(cāng)庫(kù)的第二個(gè)拷貝。從現(xiàn)在開(kāi)始,
$ git commit -a
$ git pull other.computer:/path/to/files HEAD
將把另一臺(tái)機(jī)器上特定狀態(tài)的文件“拉”到你正工作的機(jī)器上。如果你最近對(duì)同一個(gè)文 件做了有沖突的修改,Git將通知你,而你也應(yīng)該在解決沖突之后再次提交。
為你的文件初始化Git倉(cāng)庫(kù):
$ git init
$ git add .
$ git commit -m "Initial commit"
在中心服務(wù)器,在某個(gè)目錄初始化一個(gè)“裸倉(cāng)庫(kù)”:
$ mkdir proj.git
$ cd proj.git
$ git init --bare
$ touch proj.git/git-daemon-export-ok
如需要的話,啟動(dòng)Git守護(hù)進(jìn)程:
$ git daemon --detach # 它也許已經(jīng)在運(yùn)行了
對(duì)一些Git伺服服務(wù),按照其指導(dǎo)來(lái)初始化空Git倉(cāng)庫(kù)。一般是在網(wǎng)頁(yè)上填一個(gè)表單。
把你的項(xiàng)目“推”到中心服務(wù)器: $ git push central.server/path/to/proj.git HEAD
撿出源碼,可以鍵入:
$ git clone central.server/path/to/proj.git
做了改動(dòng)之后,開(kāi)發(fā)保存變更到本地:
$ git commit -a
更新到最近版本:
$ git pull
所有沖突應(yīng)被處理,然后提交:
$ git commit -a
把本地改動(dòng)撿入到中心倉(cāng)庫(kù):
$ git push
如果主服務(wù)器由于其他開(kāi)發(fā)的活動(dòng),有了新的變更,這個(gè)撿入會(huì)失敗,該開(kāi)發(fā)應(yīng)該把最 新版本拿下來(lái),解決合并沖突,然后重試。
為使用上面pull和push命令,開(kāi)發(fā)必須有SSH訪問(wèn)權(quán)限。不過(guò),通過(guò)鍵入以下命令,任何 人都可以看到源碼:
$ git clone git://central.server/path/to/proj.git
本地git協(xié)議和HTTP類似:并無(wú)安全驗(yàn)證,因此任何人都能拿到項(xiàng)目。因此,默認(rèn)情況 git協(xié)議禁止推操作。
閉源項(xiàng)目不要執(zhí)行touch命令,并確保你從未創(chuàng)建git-daemon-export-ok
文件。資源庫(kù) 不再可以通過(guò)git協(xié)議獲??;只有那些有SSH訪問(wèn)權(quán)限的人才能看到。如果你所有的資源 庫(kù)都是封閉的,那也沒(méi)必要運(yùn)行運(yùn)行g(shù)it守護(hù)了,因?yàn)樗袦贤ǘ甲逽SH。
之所以叫裸倉(cāng)庫(kù)是因?yàn)槠錄](méi)有工作目錄;它只包含正常情況下隱藏在.git
子目錄下 的文件。換句話說(shuō),它維護(hù)項(xiàng)目歷史,而且從不保存任何給定版本的快照。
裸倉(cāng)庫(kù)扮演的角色和中心版本控制系統(tǒng)中中心服務(wù)器的角色類似:你項(xiàng)目的中心。開(kāi) 發(fā)從其中克隆項(xiàng)目,撿入新近改動(dòng)。典型地裸倉(cāng)庫(kù)存在一個(gè)服務(wù)器上,該服務(wù)器除了 分散數(shù)據(jù)外并不做啥。開(kāi)發(fā)活動(dòng)發(fā)生在克隆上,因此中心倉(cāng)庫(kù)沒(méi)有工作目錄也行。
很多Git命令在裸倉(cāng)庫(kù)上失敗,除非指定倉(cāng)庫(kù)路徑到環(huán)境變量GIT_DIR
,或者指定 --bare
選項(xiàng)。
為什么我們介紹了push命令,而不是依賴熟悉的pull命令?首先,在裸倉(cāng)庫(kù)上pull會(huì) 失?。撼悄惚仨殹癴etch”,一個(gè)之后我們要討論的命令。但即使我們?cè)谥行姆?wù)器上 保持一個(gè)正常的倉(cāng)庫(kù),拽些東西進(jìn)去仍然很繁瑣。我們不得不登陸服務(wù)器先,給pull 命令我們要拽自機(jī)器的網(wǎng)絡(luò)地址。防火墻會(huì)阻礙,并且首先如果我們沒(méi)有到服務(wù)器的 shell訪問(wèn)怎么辦呢?
然而,除了這個(gè)案例,我們反對(duì)推進(jìn)倉(cāng)庫(kù),因?yàn)楫?dāng)目標(biāo)有工作目錄時(shí),困惑隨之而來(lái)。
簡(jiǎn)短截說(shuō),學(xué)習(xí)Git的時(shí)候,只在目標(biāo)是裸倉(cāng)庫(kù)的時(shí)候push,否則用pull的方式。
項(xiàng)目走歪了嗎?或者認(rèn)為你可以做得更好?那么在服務(wù)器上:
$ git clone git://main.server/path/to/files
之后告訴每個(gè)相關(guān)的人你服務(wù)器上項(xiàng)目的分支。
在之后的時(shí)間,你可以合并來(lái)自原先項(xiàng)目的改變,使用命令:
$ git pull
會(huì)有很多散布在各處,禁止篡改的冗余存檔嗎? 如果你的項(xiàng)目有很多開(kāi)發(fā),那干脆啥也 別做了。你的每份代碼克隆是一個(gè)有效備份。不僅當(dāng)前狀態(tài),還包括你項(xiàng)目整個(gè)歷史。 感謝哈希加密算法,如果任何人的克隆被損壞,只要他們與其他的交互,這個(gè)克隆就會(huì) 被修好。
如果你的項(xiàng)目并不是那么流行,那就找盡可能多的伺服來(lái)放克隆吧。
真正的偏執(zhí)狂應(yīng)該總是把HEAD最近20字節(jié)的SHA1哈希值寫到安全的地方。應(yīng)該保證安全, 而不是把它藏起來(lái)。比如,把它發(fā)布到報(bào)紙上就不錯(cuò),因?yàn)閷?duì)攻擊者而言,更改每份報(bào) 紙是很難的。
比如你想并行開(kāi)發(fā)多個(gè)功能。那么提交你的項(xiàng)目并運(yùn)行:
$ git clone . /some/new/directory
Git使用硬鏈接和文件共享來(lái)盡可能安全地創(chuàng)建克隆,因此它一眨眼就完成了,因此你現(xiàn) 在可以并行操作兩個(gè)沒(méi)有相互依賴的功能。例如,你可以編輯一個(gè)克隆,同時(shí)編譯另一 個(gè)。感謝?hardlinking, 本地克隆比簡(jiǎn)單 備份省時(shí)省地。
現(xiàn)在你可以同時(shí)工作在兩個(gè)彼此獨(dú)立的特性上。比如,你可以在編譯一個(gè)克隆的時(shí)候編 輯另一個(gè)克隆。任何時(shí)候,你都可以從其它克隆提交并拖拽變更。
$ git pull /the/other/clone HEAD
你正做一個(gè)使用其他版本控制系統(tǒng)的項(xiàng)目, 而你非常思念Git? 那么在你的工作目錄初 始化一個(gè)Git倉(cāng)庫(kù):
$ git init
$ git add .
$ git commit -m "Initial commit"
然后克隆它:
$ git clone . /some/new/directory
并在這個(gè)目錄工作,按你所想在使用Git。過(guò)一會(huì),一旦你想和其他每個(gè)人同步,在這種 情況下,轉(zhuǎn)到原來(lái)的目錄,用其他的版本控制工具同步,并鍵入:
$ git add .
$ git commit -m "Sync with everyone else"
現(xiàn)在轉(zhuǎn)到新目錄運(yùn)行:
$ git commit -a -m "Description of my changes"
$ git pull
把你的變更提交給他人的過(guò)程依賴于其他版本控制系統(tǒng)。這個(gè)新目錄包含你的改動(dòng)的文 件。需要運(yùn)行其他版本控制系統(tǒng)的命令來(lái)上載這些變更到中心倉(cāng)庫(kù)。
Subversion, 或許是最好的中心式版本控制系統(tǒng),為無(wú)數(shù)項(xiàng)目所用。?git svn?命令為 Subversion倉(cāng)庫(kù)自動(dòng)化了上面的操作,并且也可以用作?導(dǎo)出Git項(xiàng)目到Subversion倉(cāng)庫(kù)的替代。
Mercurial是一個(gè)類似的的版本控制系統(tǒng),幾乎可以和Git一起無(wú)縫工作。使用 hg-git
插件,一個(gè)Mercurial用戶可以無(wú)損地往Git倉(cāng)庫(kù)推送,從Git倉(cāng)庫(kù)拖拽。
使用Git獲得hg-git
插件:
$ git clone git://github.com/schacon/hg-git.git
或使用Mercurial:
$ hg clone http://bitbucket.org/durin42/hg-git/
不好意思,我沒(méi)注意Git有類似的插件。因此, 我主張使用Git而不是Mercurial作為主資 源庫(kù),即使你偏愛(ài)Mercurial。使用Mercurial項(xiàng)目,通常一個(gè)自愿者維護(hù)一個(gè)平行的 Git項(xiàng)目以適應(yīng)Git用戶,然而感謝hg-git
插件,一個(gè)Git項(xiàng)目自動(dòng)地適應(yīng)Mercurial用 戶。
盡管該插件可以把一個(gè)Mercurial倉(cāng)庫(kù)轉(zhuǎn)成一個(gè)Git倉(cāng)庫(kù),通過(guò)推到一個(gè)空的倉(cāng)庫(kù), 這個(gè)差事交給hg-fast-export.sh
腳本還是更容易些。來(lái)自:
$ git clone git://repo.or.cz/fast-export.git
要轉(zhuǎn)化,只需在一個(gè)空目錄運(yùn)行:
$ git init
$ hg-fast-export.sh -r /hg/repo
注意該腳本應(yīng)加入你的$PATH
。
我們簡(jiǎn)略提一下Bazaar,它畢竟是緊跟Git和Mercurial之后最流行的自由分布式版本控 制系統(tǒng)。
Bazaar有后來(lái)者的優(yōu)勢(shì),它相對(duì)年輕些;它的設(shè)計(jì)者可以從前人的錯(cuò)誤中學(xué)習(xí),并且躲 過(guò)去翻歷史上犯過(guò)的錯(cuò)誤。另外,它的開(kāi)發(fā)人員對(duì)可移植性以及和與其它版本控制系統(tǒng) 的互操作性也考慮周全。
一個(gè)bzr-git
插件讓Bazaar用戶在一定程度下可以工作在Git倉(cāng)庫(kù)。tailor
程序轉(zhuǎn) 換Bazaar倉(cāng)庫(kù)到Git倉(cāng)庫(kù),并且可以遞增的方式做,要知道bzr-fast-export
只是 在一次性轉(zhuǎn)換性情況下工作良好。
我起先選擇Git是因?yàn)槲衣?tīng)說(shuō)它能管理不可想象地不可管理的Linux內(nèi)核源碼。我從來(lái)沒(méi) 覺(jué)得有離開(kāi)的必要。Git已經(jīng)服侍的很好了,并且我也沒(méi)有被其瑕疵所困擾。因?yàn)槲抑饕?使用Linux,其他平臺(tái)上的問(wèn)題與我無(wú)關(guān)。
還有,我偏愛(ài)C程序和bash腳本,以及諸如Python的可執(zhí)行可腳本:較少依賴,并且我也 沉迷于快速的執(zhí)行時(shí)間。
我考慮過(guò)Git才能如何提高,甚至自己寫類似的工具,但只作為研究練練手。即使完成這 個(gè)項(xiàng)目,我也無(wú)論如何會(huì)繼續(xù)使用Git,因?yàn)槭褂靡粋€(gè)古里古怪的系統(tǒng)所獲甚微。
自然地,你的需求和期望可能不同,并且你可能使用另一個(gè)系統(tǒng)會(huì)好些。盡管如此,使 用Git你都錯(cuò)不太遠(yuǎn)。
更多建議: