合併外部工作
通常的情況下,合併其他的人的工作的情況會比合併自己的分支的情況要多,這在 git 中是非常容易的事情,和你執行 git-merge 命令沒有什麼區別。事實上,遠端合併的無非就是“抓取(fetch)一個遠端的版本庫中的工作到一個臨時的標籤中”,然後再使用 git-merge 命令。
可以通過下面的命令來抓取遠端版本庫:
$ git-fetch <remote-repository>
根據不同的遠端版本庫所使用的通訊協定的路徑來替代上面的 remoted-repository 就可以了。
Rsync
rsync://remote.machine/patch/to/repo.git/
SSH
remote.machine:/path/to/repo.git
or
ssh://remote.machine/patch/to/repo.git/
這是可以上傳和下載的雙向傳輸協議,當然,你要有通過 ssh 協議登錄遠端機器的許可權。它可以找出兩端的機器提交過的物件集之中相互缺少了那些物件,從而得到需要傳輸的最小物件集。這是最高效地交換兩個版本庫之間的物件的方式(在 git 相容的所有傳輸協議當中)。
下面是個取得 SSH 遠端版本庫的命令例子:
$ git-fetch robin@192.168.1.168:/path/to/gittutorcn.git (1)
(1) 這裡 robin 是登錄的用戶名,192.168.1.168 是保存著主版本庫的機器的 IP 位址。
Local directory
/path/to/repo.git/
本地目錄的情況和 SSH 情況是一樣的。
git Native
git://remote.machine/path/to/repo.git/
git 自然協議是設計來用於匿名下載的,它的工作方式類似於 SSH 協定的交換方式。
HTTP(S)
http://remote.machine/path/to/repo.git/
到這裡可能有些朋友已經想到,實際上,我們可以通過 Rsync, SSH 之類的雙向傳輸方式來建立類似 CVS,SVN 這樣的中心版本庫模式的開發組織形式。
通過電子郵件交換工作
讀過上一節之後,有的朋友可能要問,如果版本庫是通過單向的下載協議發佈的,如 HTTP,我們就無法將工作上傳到公共的版本庫中。別人也不能訪問我的機器來抓取我的工作,那怎麼辦呢?
不必擔心,我們還有 email !別忘了 git 本來就是為了管理 Linux 的核心開發而設計的。所以,它非常適合像 Linux Kernel 這樣的開發組織形式高度分散,嚴重依賴 email 來進行交流的項目。
下面模擬你參加到《Git 中文教學》的編寫工作中來,看看我們可以怎麼通過 email 進行工作交流。你可以通過下面的命令下載這個項目的版本庫。
$ git-clone http://www.bitsun.com/git/gittutorcn.git
之後,你會在目前的目錄下得到一個叫 gittutorcn 的目錄,這就是你的專案的工作目錄了。預設地,它會有兩個分支: master 和 origin,你可以直接在 master 下展開工作,也可以建立你自己的工作分支,但是千萬不要修改 origin 分支,切記!因為它是公共版本庫的鏡像,如果你修改了它,那麼就不能生成正確的對公共版本庫的 patch 檔了。
Note | 如果你的確修改過 origin 分支的內容,那麼在生成 patch 檔之前,請用 git-reset --hard 命令將它逆轉到最原始的,沒經過任何修改的狀態。 |
你可以直接在 master 下開展工作,也可以建立你自己的工作分支。當你對專案做了一定的工作,並提交到庫中。我們用 git-show-branch 命令先看下庫的狀態。
* [master] your buddy's contribution
! [origin] degining of git-format-patch example
--
* [master] your buddy's contribution
*+ [origin] degining of git-format-patch example
上面就假設你已經提交了一個叫 "your buddy's contribution" 的工作。現在我們來看看怎麼通過 email 來交流工作了。
$ git-fetch origin (1)
$ git-rebase origin (2)
$ git-format-patch origin (3)
(1)更新 origin 分支,防止 origin 分支不是最新的公共版本,產生錯誤的補丁檔;
(2)將你在 master 上提交的工作遷移到新的源版本庫的狀態的基礎上;
(3)生成補丁檔;
上面的幾個命令,會在目前的目錄下生成一個大概名為 0001-your-buddy-s-contribution.txt 補丁檔, 建議你用文本工具查看一下這個檔的具體形式,然後將這個檔以附件的形式發送到專案維護者的郵箱: vortune@gmail.com
當項目的維護者收到你的郵件後,只需要用 git-am 命令,就可以將你的工作合併到專案中來。
$ git-checkout -b buddy-incomming
$ git-am /path/to/0001-your-buddy-s-contribution.txt
用 Git 協同工作
假設 Alice 在一部機器上自己的個人目錄中建立了一個專案 /home/alice/project, Bob 想在同一部機器自己的個人目錄中為這個專案做點什麼。
Bob 首先這樣開始:
$ git-clone /home/alice/project myrepo
這樣就建立了一個保存著 Alice 的版本庫的鏡像的新目錄 "myrepo"。這個鏡像保存著原始專案的起點和它的發展歷程。
接著 Bob 對項目做了些更改並提交了這些更改:
(編輯一些文件)
$ git-commit -a
(如果需要的話再重複這個步驟)
當他搞定之後,他告訴 Alice 將他的東西從 /home/bob/myrepo 中引入,她只需要這樣:
$ cd /home/alice/project
$ git pull /home/bob/myrepo
這樣就將 Bob 的版本庫中的 "master" 分支的變化引入了。 Alice 也可以通過在 pull 命令的後面加入參數的方式來引入其他的分支。
在導入了 Bob 的工作之後,用 "git-whatchanged" 命令可以查看有什麼信的提交物件。如果這段時間裡以來,Alice 也對項目做過自己的修改,當 Bob 的修改被合併進來的時候,那麼她需要手動修復所有的合併衝突。
謹慎的 Alice 在導入 Bob 的工作之前,希望先檢查一下。那麼她可以先將 Bob 的工作導入到一個新建立的臨時分支中,以方便研究 Bob 的工作:
$ git fetch /home/bob/myrepo master:bob-incoming
這個命令將 Bob 的 master 分支的導入到名為 bob-incoming 的分支中(不同於 git-pull 命令,git-fetch 命令只是取得 Bob 的開發工作的拷貝,而不是合併經來)。接著:
$ git whatchanged -p master..bob-incoming
這會列出 Bob 自取得 Alice 的 master 分支之後開始工作的所有變化。檢查過這些工作,並做過必須的調整之後, Alice 就可以將變化導入到她的 master 分支中:
$ git-checkout master
$git-pull . bob-incoming
最後的命令就是將 "bob-incoming" 分支的東西導入到 Alice 自己的版本庫中的,稍後,Bob 就可以通過下面的命令同步 Alice 的最新變化。
$ git-pull
注意不需為這個命令加入 Alice 的版本庫的路徑,因為當 Bob 克隆 Alice 的版本庫的時候, git 已經將這個路徑保存到 .git/remote/origin 檔中,它將會是所以的導入操作的預設路徑。
Bob 可能已經注意到他並沒有在他的版本庫中建立過分支(但是分支已經存在了):
$ git branch
* master
origin
"origin" 分支,它是執行 "git-clone" 的時候自動建立的,他是 Alice 的 master 分支的原始鏡像, Bob 應該永遠不要向這個分支提交任何東西。
如果 Bob 以後決定在另外一部主機上開展工作,那麼他仍然需要通過 SSH 協定從新克隆和導入( Alice 的版本庫):
$ git-clone alice.org:/home/alice/project/ myrepo
我們可以使用 git 自然協議,或者是 rsync, http 等協議的任何一種,詳情請參考 git-pull。
Git 同樣可以建立類似 CVS 那樣的開發模式,也就是所有開發者都向中心版本庫提交工作的方式,詳情參考 git_push 和 git for CVS users 。
為版本庫打包
在前面,我們已經看到在 .git/objects/??/ 目錄中保存著我們建立的每一個 git 物件。這樣的方式對於自動和安全地建立物件很有效,但是對於網路傳輸則不方便。 git 物件一旦建立了,就不能被改變,但有一個方法可以優化物件的存儲,就是將他們“打包到一起”。
$ git repack
上面的命令讓你做到這點,如果你一直是做著我們的例子過來的,你現在大約會在 .git/objects/??/ 目錄下積累了17個對象。 git-repack 會告訴你有幾個對象被打包了,並且將他們保存在 .git/objects/pack 目錄當中。
Note | 你將會看到兩個文件,pack-*.pack and pack-*.idx 在 .git/objects/pack 目錄。他們的關係是很密切的,如果你手動將他們拷貝到別的版本庫中的話,你要決定將他們一起拷貝。前者是保存著所有被打包的資料的檔,後者是隨機訪問的索引。 |
如果你是個偏執狂,就執行一下 git-verity-pack 命令來檢查一下有缺陷的包吧,不過,其實你無須太多擔心,我們的程式非常出色 ;-).
一旦你已經對那些物件打包了,那麼那些已經被打過包的原始的物件,就沒有必要保留了。
$ git prune-packed
會幫你清楚他們。
如果你好奇的話,你可以在執行 git-prune-repacked 命令之前和之後,都執行一下 find .git/objects -type f,這樣你就能看到有多少沒有打包的物件,以及節省了多少磁碟空間。
Note | git pull git-pull 對於 HTTP 傳輸來說,一個打包過的版本庫會將一定數量的相關聯的物件放進一個有關聯性的打包中。如果你設想多次從 HTTP 公共版本庫中導入資料,你也許要頻繁地 reapck & prune,要麼就乾脆從不這樣做。 |
如果你此時再次執行 git-repack,它就會說 "Nothing to pack"。要是你繼續開發,並且積累了一定數量的變遷,再執行 git-repack 將會建立一個新的包,它會包含你自上次對庫打包以來建立的物件。我們建議你儘快在初始化提交之後打包一下你的版本庫(除非你現在的項目是個塗鴉式的草稿項目),並且在專案經歷過一段很活躍的時期時,再執行 git-repack 一下。
當一個版本庫通過 git-push 和 git-pull 命令來同步源版本庫中打包過的對像的時候,通常保存到目標版本庫中的是解包了的物件,除非你使用的是 rsync(遠端同步協定)協定的傳輸方式。正是這種容許你在兩頭的版本庫中有不同的打包策略的方式,他意味著你也許在過一段時間之後,需要在兩頭的版本庫中都重新封包一下。
發佈你的工作
我們可以通過一個遠端的版本庫來利用他人的工作,但是,你如何準備一個自己的版本庫來供其他人下載呢?你在自己的工作目錄下進行工作,這樣你的版本庫就被作為.git的一個子目錄放在你的工作樹下。你可以讓其他人來遠端的訪問你的版本庫,但是實際上這不是通常的做法。推薦的做法是建立一個公共的版本庫,讓它可供其他人訪問,並且,當你在你的工作目錄下做了很好的改動時,你可以更新到公共的版本庫中。這通常稱為pushing。
Note | 公共版本庫是可以被映射的,kernel.org上的git公共版本庫也是這樣管理的。 |
從你的本地的(私有的)版本庫中發佈改動到你的遠端的(公共的)版本庫中需要遠端機器上的寫許可權。你需要一個SSH的帳號來執行一個簡單的命令,git-receive-pack。首先,你需要在遠端機器上建立一個空的版本庫來存放你的公共版本庫。這個空版本庫以後將通過pushing來保持更新。顯然,這個版本庫之需要在開始的時候建立一次。
Note | git push使用一對命令,git-send-pack在本地機上執行,git-receive-pack在遠端機上執行。這兩個命令通過SSH連接來進行通訊。 |
你本地的版本庫的git目錄通常是.git,但是你的公共版本庫通常還要加上你的項目名,即.git。讓我們來為my-git建立這樣一個版本庫。首先,登入遠端的機器,建立一個空目錄(如果你選擇HTTP作為發佈方法,這個空目錄需要建在web server的根目錄下面):
$ mkdir my-git.git
然後執行git init-db命令將這個目錄加入git版本庫中,這裡,因為這個版本庫的名字不是通常的.git,我們需要稍微改動一下命令:
$ GIT_DIR=my-git.git git-init-db
有很多種傳輸方式可以發佈公共版本庫。這裡,要確認這個目錄可以通過你選擇的傳輸方式來被其他人訪問。你也需要確認你有git-receive-pack這個程式在$PATH這個路徑下。
Note | 當你直接執行程式的時候,很多sshd的安裝版並沒有將你的shell作為登陸的shell;這就是說,如果你登陸的shell是bash 的話,被讀到的是.bashrc而不是.bash_profile。確認.bashrc設置好了$PATH路徑,這樣你才可以執行git-receive-pack命令。 |
Note | 如果你打算通過HTTP來發佈這個版本庫,這是你就應該執行命令chmod +x my-git.git/hooks/post-update。這確認了每次你導入資料到這個版本庫中,git-update-server-info能夠被執行。 |
現在你的“公共的版本庫”可以接受你的任何改動了。回到你的本地機上,執行命令:
$ git push :/path/to/my-git.git master
該命令將你的公共版本庫和你當前的版本庫中指定名稱的分支頭部同步(這裡是master)。舉一個實際的例子,你可以這樣來更新公共的git版本庫。Kernel.org的鏡像網路也這樣來同步其他公共的可訪問的機器:
$ git push master.kernel.org:/pub/scm/git/git.git/
留言列表