== 克隆周邊 ==

在較老一代的版本控制系統裡，checkout是獲取檔案的標準操作。你將獲得一組特定保
存狀態的檔案。

在Git和其他分散式版本控制系統裡，克隆是標準的操作。通過創建整個倉庫的克隆來
獲得檔案。或者說，你實際上把整個中心伺服器做了個鏡像。凡是主倉庫上能做的事，
你都能做。

=== 計算機間同步 ===

我可以忍受製作tar包或利用rsync來作備份和基本同步。但我有時在我筆記本上編輯，
其他時間在台式機上，而且這倆之間也許並不交互。

在一個機器上初始化一個Git倉庫並提交你的檔案。然後轉到另一台機器上：

 $ git clone other.computer:/path/to/files

以創建這些檔案和Git倉庫的第二個拷貝。從現在開始，

 $ git commit -a
 $ git pull other.computer:/path/to/files HEAD

將把另一台機器上特定狀態的檔案“拉”到你正工作的機器上。如果你最近對同一個文
件做了有衝突的修改，Git將通知你，而你也應該在解決衝突之後再次提交。

=== 典型源碼控制 ===

為你的檔案初始化Git倉庫：

 $ git init
 $ git add .
 $ git commit -m "Initial commit"

在中心伺服器，在某個目錄初始化一個“裸倉庫”：

 $ mkdir proj.git
 $ cd proj.git
 $ git init --bare
 $ touch proj.git/git-daemon-export-ok

如需要的話，啟動Git守護進程：

 $ git daemon --detach  # 它也許已經在運行了

對一些Git伺服服務，按照其指導來初始化空Git倉庫。一般是在網頁上填一個表單。

把你的項目“推”到中心伺服器：
 $ git push central.server/path/to/proj.git HEAD

撿出源碼，可以鍵入：

 $ git clone central.server/path/to/proj.git

做了改動之後，開發保存變更到本地：

 $ git commit -a

更新到最近版本：

 $ git pull

所有衝突應被處理，然後提交：

 $ git commit -a

把本地改動撿入到中心倉庫：

 $ git push

如果主伺服器由於其他開發的活動，有了新的變更，這個撿入會失敗，該開發應該把最
新版本拿下來，解決合併衝突，然後重試。

為使用上面pull和push命令，開發必須有SSH訪問權限。不過，通過鍵入以下命令，任何
人都可以看到源碼：

 $ git clone git://central.server/path/to/proj.git

本地git協議和HTTP類似：並無安全驗證，因此任何人都能拿到項目。因此，預設情況
git協議禁止推操作。

=== 封閉源碼 ===

閉源項目不要執行touch命令，並確保你從未創建`git-daemon-export-ok`檔案。資源庫
不再可以通過git協議獲取；只有那些有SSH訪問權限的人才能看到。如果你所有的資源
庫都是封閉的，那也沒必要運行運行git守護了，因為所有溝通都走SSH。

=== 裸倉庫 ===

之所以叫裸倉庫是因為其沒有工作目錄；它只包含正常情況下隱藏在`.git`子目錄下
的檔案。換句話說，它維護項目歷史，而且從不保存任何給定版本的快照。

裸倉庫扮演的角色和中心版本控制系統中中心伺服器的角色類似：你項目的中心。開
發從其中克隆項目，撿入新近改動。典型地裸倉庫存在一個伺服器上，該伺服器除了
分散數據外並不做啥。開發活動發生在克隆上，因此中心倉庫沒有工作目錄也行。


很多Git命令在裸倉庫上失敗，除非指定倉庫路徑到環境變數`GIT_DIR`，或者指定
`--bare`選項。

=== 推還是拽 ===

為什麼我們介紹了push命令，而不是依賴熟悉的pull命令？首先，在裸倉庫上pull會
失敗：除非你必須“fetch”，一個之後我們要討論的命令。但即使我們在中心伺服器上
保持一個正常的倉庫，拽些東西進去仍然很繁瑣。我們不得不登陸伺服器先，給pull
命令我們要拽自機器的網絡地址。防火牆會阻礙，並且首先如果我們沒有到伺服器的
shell訪問怎麼辦呢？

然而，除了這個案例，我們反對推進倉庫，因為當目標有工作目錄時，困惑隨之而來。

簡短截說，學習Git的時候，只在目標是裸倉庫的時候push，否則用pull的方式。

=== 項目分叉 ===

項目走歪了嗎？或者認為你可以做得更好？那麼在伺服器上：

 $ git clone git://main.server/path/to/files

之後告訴每個相關的人你伺服器上項目的分支。

在之後的時間，你可以合併來自原先項目的改變，使用命令：

 $ git pull

=== 終極備份 ===

會有很多散佈在各處，禁止篡改的冗餘存檔嗎? 如果你的項目有很多開發，那乾脆啥也
別做了。你的每份代碼克隆是一個有效備份。不僅當前狀態，還包括你項目整個歷史。
感謝哈希加密算法，如果任何人的克隆被損壞，只要他們與其他的交互，這個克隆就會
被修好。

如果你的項目並不是那麼流行，那就找儘可能多的伺服來放克隆吧。

真正的偏執狂應該總是把HEAD最近20位元組的SHA1哈希值寫到安全的地方。應該保證安全，
而不是把它藏起來。比如，把它發佈到報紙上就不錯，因為對攻擊者而言，更改每份報
紙是很難的。

=== 輕快多任務 ===

比如你想並行開發多個功能。那麼提交你的項目並運行：

 $ git clone . /some/new/directory

Git使用硬連結和檔案共享來儘可能安全地創建克隆，因此它一眨眼就完成了，因此你現
在可以並行操作兩個沒有相互依賴的功能。例如，你可以編輯一個克隆，同時編譯另一
個。感謝 http://en.wikipedia.org/wiki/Hard_link[hardlinking], 本地克隆比簡單
備份省時省地。

現在你可以同時工作在兩個彼此獨立的特性上。比如，你可以在編譯一個克隆的時候編
輯另一個克隆。任何時候，你都可以從其它克隆提交並拖拽變更。

 $ git pull /the/other/clone HEAD

=== 游擊版本控制 ===

你正做一個使用其他版本控制系統的項目， 而你非常思念Git？ 那麼在你的工作目錄初
始化一個Git倉庫：

 $ git init
 $ git add .
 $ git commit -m "Initial commit"

然後克隆它：

 $ git clone . /some/new/directory

並在這個目錄工作，按你所想在使用Git。過一會，一旦你想和其他每個人同步，在這種
情況下，轉到原來的目錄，用其他的版本控制工具同步，並鍵入：

 $ git add .
 $ git commit -m "Sync with everyone else"

現在轉到新目錄運行：

 $ git commit -a -m "Description of my changes"
 $ git pull

把你的變更提交給他人的過程依賴于其他版本控制系統。這個新目錄包含你的改動的文
件。需要運行其他版本控制系統的命令來上載這些變更到中心倉庫。

Subversion, 或許是最好的中心式版本控制系統，為無數項目所用。 *git svn* 命令為
Subversion倉庫自動化了上面的操作，並且也可以用作
http://google-opensource.blogspot.com/2008/05/export-git-project-to-google-code.html[
導出Git項目到Subversion倉庫] 的替代。

=== Mercurial ===

Mercurial是一個類似的的版本控制系統，几乎可以和Git一起無縫工作。使用
`hg-git`插件，一個Mercurial用戶可以無損地往Git倉庫推送，從Git倉庫拖拽。

使用Git獲得`hg-git`插件：

 $ git clone git://github.com/schacon/hg-git.git

或使用Mercurial:

 $ hg clone http://bitbucket.org/durin42/hg-git/

不好意思，我沒注意Git有類似的插件。因此, 我主張使用Git而不是Mercurial作為主資
源庫，即使你偏愛Mercurial。使用Mercurial項目，通常一個自願者維護一個平行的
Git項目以適應Git用戶，然而感謝`hg-git`插件，一個Git項目自動地適應Mercurial用
戶。

儘管該插件可以把一個Mercurial倉庫轉成一個Git倉庫，通過推到一個空的倉庫，
這個差事交給`hg-fast-export.sh`腳本還是更容易些。來自：

 $ git clone git://repo.or.cz/fast-export.git

要轉化，只需在一個空目錄運行：

 $ git init
 $ hg-fast-export.sh -r /hg/repo

注意該腳本應加入你的`$PATH`。

=== Bazaar ===

我們簡略提一下Bazaar，它畢竟是緊跟Git和Mercurial之後最流行的自由分散式版本控
制系統。

Bazaar有後來者的優勢，它相對年輕些；它的設計者可以從前人的錯誤中學習，並且躲
過去翻歷史上犯過的錯誤。另外，它的開發人員對可移植性以及和與其它版本控制系統
的互操作性也考慮周全。

一個`bzr-git`插件讓Bazaar用戶在一定程度下可以工作在Git倉庫。`tailor`程序轉
換Bazaar倉庫到Git倉庫，並且可以遞增的方式做，要知道`bzr-fast-export`只是
在一次性轉換性情況下工作良好。

=== 我偏愛Git的原因 ===

我起先選擇Git是因為我聽說它能管理不可想象地不可管理的Linux內核源碼。我從來沒
覺得有離開的必要。Git已經服侍的很好了，並且我也沒有被其瑕疵所困擾。因為我主要
使用Linux，其他平台上的問題與我無關。

還有，我偏愛C程序和bash腳本，以及諸如Python的可執行可腳本：較少依賴，並且我也
沉迷于快速的執行時間。

我考慮過Git才能如何提高，甚至自己寫類似的工具，但只作為研究練練手。即使完成這
個項目，我也無論如何會繼續使用Git，因為使用一個古裡古怪的系統所獲甚微。

自然地，你的需求和期望可能不同，並且你可能使用另一個系統會好些。儘管如此，使
用Git你都錯不太遠。
