Git 與 Subversion

2018-07-10 17:30 更新

Git 與 Subversion

當(dāng)前,大多數(shù)開發(fā)中的開源項(xiàng)目以及大量的商業(yè)項(xiàng)目都使用 Subversion 來(lái)管理源碼。作為最流行的開源版本控制系統(tǒng),Subversion 已經(jīng)存在了接近十年的時(shí)間。它在許多方面與 CVS 十分類似,后者是前者出現(xiàn)之前代碼控制世界的霸主。

Git 最為重要的特性之一是名為 git svn 的 Subversion 雙向橋接工具。該工具把 Git 變成了 Subversion 服務(wù)的客戶端,從而讓你在本地享受到 Git 所有的功能,而后直接向 Subversion 服務(wù)器推送內(nèi)容,仿佛在本地使用了 Subversion 客戶端。也就是說,在其他人忍受古董的同時(shí),你可以在本地享受分支合并,使暫存區(qū)域,衍合以及 單項(xiàng)挑揀等等。這是個(gè)讓 Git 偷偷潛入合作開發(fā)環(huán)境的好東西,在幫助你的開發(fā)同伴們提高效率的同時(shí),它還能幫你勸說團(tuán)隊(duì)讓整個(gè)項(xiàng)目框架轉(zhuǎn)向?qū)?Git 的支持。這個(gè) Subversion 之橋是通向分布式版本控制系統(tǒng)(DVCS, Distributed VCS )世界的神奇隧道。

git svn

Git 中所有 Subversion 橋接命令的基礎(chǔ)是 git svn 。所有的命令都從它開始。相關(guān)的命令數(shù)目不少,你將通過幾個(gè)簡(jiǎn)單的工作流程了解到其中常見的一些。

值得警戒的是,在使用 git svn 的時(shí)候,你實(shí)際是在與 Subversion 交互,Git 比它要高級(jí)復(fù)雜的多。盡管可以在本地隨意的進(jìn)行分支和合并,最好還是通過衍合保持線性的提交歷史,盡量避免類似與遠(yuǎn)程 Git 倉(cāng)庫(kù)動(dòng)態(tài)交互這樣的操作。

避免修改歷史再重新推送的做法,也不要同時(shí)推送到并行的 Git 倉(cāng)庫(kù)來(lái)試圖與其他 Git 用戶合作。Subersion 只能保存單一的線性提交歷史,一不小心就會(huì)被搞糊涂。合作團(tuán)隊(duì)中同時(shí)有人用 SVN 和 Git,一定要確保所有人都使用 SVN 服務(wù)來(lái)協(xié)作——這會(huì)讓生活輕松很多。

初始設(shè)定

為了展示功能,先要一個(gè)具有寫權(quán)限的 SVN 倉(cāng)庫(kù)。如果想嘗試這個(gè)范例,你必須復(fù)制一份其中的測(cè)試倉(cāng)庫(kù)。比較簡(jiǎn)單的做法是使用一個(gè)名為 svnsync 的工具。較新的 Subversion 版本中都帶有該工具,它將數(shù)據(jù)編碼為用于網(wǎng)絡(luò)傳輸?shù)母袷健?/p>

要嘗試本例,先在本地新建一個(gè) Subversion 倉(cāng)庫(kù):

$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn

然后,允許所有用戶修改 revprop —— 簡(jiǎn)單的做法是添加一個(gè)總是以 0 作為返回值的 pre-revprop-change 腳本:

$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change

現(xiàn)在可以調(diào)用 svnsync init 加目標(biāo)倉(cāng)庫(kù),再加源倉(cāng)庫(kù)的格式來(lái)把該項(xiàng)目同步到本地了:

$ svnsync init file:///tmp/test-svn http://progit-example.googlecode.com/svn/

這將建立進(jìn)行同步所需的屬性??梢酝ㄟ^運(yùn)行以下命令來(lái)克隆代碼:

$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Committed revision 2.
Copied properties for revision 2.
Committed revision 3.
...

別看這個(gè)操作只花掉幾分鐘,要是你想把源倉(cāng)庫(kù)復(fù)制到另一個(gè)遠(yuǎn)程倉(cāng)庫(kù),而不是本地倉(cāng)庫(kù),那將花掉接近一個(gè)小時(shí),盡管項(xiàng)目中只有不到 100 次的提交。 Subversion 每次只復(fù)制一次修改,把它推送到另一個(gè)倉(cāng)庫(kù)里,然后周而復(fù)始——驚人的低效,但是我們別無(wú)選擇。

入門

有了可以寫入的 Subversion 倉(cāng)庫(kù)以后,就可以嘗試一下典型的工作流程了。我們從 git svn clone 命令開始,它會(huì)把整個(gè) Subversion 倉(cāng)庫(kù)導(dǎo)入到一個(gè)本地的 Git 倉(cāng)庫(kù)中。提醒一下,這里導(dǎo)入的是一個(gè)貨真價(jià)實(shí)的 Subversion 倉(cāng)庫(kù),所以應(yīng)該把下面的 file:///tmp/test-svn 換成你所用的 Subversion 倉(cāng)庫(kù)的 URL:

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /Users/schacon/projects/testsvnsync/svn/.git/
r1 = b4e387bc68740b5af56c2a5faf4003ae42bd135c (trunk)
      A    m4/acx_pthread.m4
      A    m4/stl_hash.m4
...
r75 = d1957f3b307922124eec6314e15bcda59e3d9610 (trunk)
Found possible branch point: file:///tmp/test-svn/trunk => \
    file:///tmp/test-svn /branches/my-calc-branch, 75
Found branch parent: (my-calc-branch) d1957f3b307922124eec6314e15bcda59e3d9610
Following parent with do_switch
Successfully followed parent
r76 = 8624824ecc0badd73f40ea2f01fce51894189b01 (my-calc-branch)
Checked out HEAD:
 file:///tmp/test-svn/branches/my-calc-branch r76

這相當(dāng)于針對(duì)所提供的 URL 運(yùn)行了兩條命令—— git svn init 加上 git svn fetch ??赡軙?huì)花上一段時(shí)間。我們所用的測(cè)試項(xiàng)目?jī)H僅包含 75 次提交并且它的代碼量不算大,所以只有幾分鐘而已。不過,Git 仍然需要提取每一個(gè)版本,每次一個(gè),再逐個(gè)提交。對(duì)于一個(gè)包含成百上千次提交的項(xiàng)目,花掉的時(shí)間則可能是幾小時(shí)甚至數(shù)天。

-T trunk -b branches -t tags 告訴 Git 該 Subversion 倉(cāng)庫(kù)遵循了基本的分支和標(biāo)簽命名法則。如果你的主干(譯注:trunk,相當(dāng)于非分布式版本控制里的master分支,代表開發(fā)的主線),分支或者標(biāo)簽以不同的方式命名,則應(yīng)做出相應(yīng)改變。由于該法則的常見性,可以使用 -s 來(lái)代替整條命令,它意味著標(biāo)準(zhǔn)布局(s 是 Standard layout 的首字母),也就是前面選項(xiàng)的內(nèi)容。下面的命令有相同的效果:

$ git svn clone file:///tmp/test-svn -s

現(xiàn)在,你有了一個(gè)有效的 Git 倉(cāng)庫(kù),包含著導(dǎo)入的分支和標(biāo)簽:

$ git branch -a
* master
  my-calc-branch
  tags/2.0.2
  tags/release-2.0.1
  tags/release-2.0.2
  tags/release-2.0.2rc1
  trunk

值得注意的是,該工具分配命名空間時(shí)和遠(yuǎn)程引用的方式不盡相同??寺∑胀ǖ?Git 倉(cāng)庫(kù)時(shí),可以以 origin/[branch] 的形式獲取遠(yuǎn)程服務(wù)器上所有可用的分支——分配到遠(yuǎn)程服務(wù)的名稱下。然而 git svn 假定不存在多個(gè)遠(yuǎn)程服務(wù)器,所以把所有指向遠(yuǎn)程服務(wù)的引用不加區(qū)分的保存下來(lái)。可以用 Git 探測(cè)命令 show-ref 來(lái)查看所有引用的全名。

$ git show-ref
1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/heads/master
aee1ecc26318164f355a883f5d99cff0c852d3c4 refs/remotes/my-calc-branch
03d09b0e2aad427e34a6d50ff147128e76c0e0f5 refs/remotes/tags/2.0.2
50d02cc0adc9da4319eeba0900430ba219b9c376 refs/remotes/tags/release-2.0.1
4caaa711a50c77879a91b8b90380060f672745cb refs/remotes/tags/release-2.0.2
1c4cb508144c513ff1214c3488abe66dcb92916f refs/remotes/tags/release-2.0.2rc1
1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/remotes/trunk

而普通的 Git 倉(cāng)庫(kù)應(yīng)該是這個(gè)模樣:

$ git show-ref
83e38c7a0af325a9722f2fdc56b10188806d83a1 refs/heads/master
3e15e38c198baac84223acfc6224bb8b99ff2281 refs/remotes/gitserver/master
0a30dd3b0c795b80212ae723640d4e5d48cabdff refs/remotes/origin/master
25812380387fdd55f916652be4881c6f11600d6f refs/remotes/origin/testing

這里有兩個(gè)遠(yuǎn)程服務(wù)器:一個(gè)名為 gitserver ,具有一個(gè) master分支;另一個(gè)叫 origin,具有 master 和 testing 兩個(gè)分支。

注意本例中通過 git svn 導(dǎo)入的遠(yuǎn)程引用,(Subversion 的)標(biāo)簽是當(dāng)作遠(yuǎn)程分支添加的,而不是真正的 Git 標(biāo)簽。導(dǎo)入的 Subversion 倉(cāng)庫(kù)仿佛是有一個(gè)帶有不同分支的 tags 遠(yuǎn)程服務(wù)器。

提交到 Subversion

有了可以開展工作的(本地)倉(cāng)庫(kù)以后,你可以開始對(duì)該項(xiàng)目做出貢獻(xiàn)并向上游倉(cāng)庫(kù)提交內(nèi)容了,Git 這時(shí)相當(dāng)于一個(gè) SVN 客戶端。假如編輯了一個(gè)文件并進(jìn)行提交,那么這次提交僅存在于本地的 Git 而非 Subversion 服務(wù)器上。

$ git commit -am 'Adding git-svn instructions to the README'
[master 97031e5] Adding git-svn instructions to the README
 1 files changed, 1 insertions(+), 1 deletions(-)

接下來(lái),可以將作出的修改推送到上游。值得注意的是,Subversion 的使用流程也因此改變了——你可以在離線狀態(tài)下進(jìn)行多次提交然后一次性的推送到 Subversion 的服務(wù)器上。向 Subversion 服務(wù)器推送的命令是 git svn dcommit

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
       M      README.txt
Committed r79
       M      README.txt
r79 = 938b1a547c2cc92033b74d32030e86468294a5c8 (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

所有在原 Subversion 數(shù)據(jù)基礎(chǔ)上提交的 commit 會(huì)一一提交到 Subversion,然后你本地 Git 的 commit 將被重寫,加入一個(gè)特別標(biāo)識(shí)。這一步很重要,因?yàn)樗馕吨?commit 的 SHA-1 指都會(huì)發(fā)生變化。這也是同時(shí)使用 Git 和 Subversion 兩種服務(wù)作為遠(yuǎn)程服務(wù)不是個(gè)好主意的原因之一。檢視以下最后一個(gè) commit,你會(huì)找到新添加的 git-svn-id (譯注:即本段開頭所說的特別標(biāo)識(shí)):

$ git log -1
commit 938b1a547c2cc92033b74d32030e86468294a5c8
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date:   Sat May 2 22:06:44 2009 +0000

    Adding git-svn instructions to the README

    git-svn-id: file:///tmp/test-svn/trunk@79 4c93b258-373f-11de-be05-5f7a86268029

注意看,原本以 97031e5 開頭的 SHA-1 校驗(yàn)值在提交完成以后變成了 938b1a5 。如果既要向 Git 遠(yuǎn)程服務(wù)器推送內(nèi)容,又要推送到 Subversion 遠(yuǎn)程服務(wù)器,則必須先向 Subversion 推送(dcommit),因?yàn)樵摬僮鲿?huì)改變所提交的數(shù)據(jù)內(nèi)容。

拉取最新進(jìn)展

如果要與其他開發(fā)者協(xié)作,總有那么一天你推送完畢之后,其他人發(fā)現(xiàn)他們推送自己修改的時(shí)候(與你推送的內(nèi)容)產(chǎn)生沖突。這些修改在你合并之前將一直被拒絕。在 git svn 里這種情況形似:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
Merge conflict during commit: Your file or directory 'README.txt' is probably \
out-of-date: resource out of date; try updating at /Users/schacon/libexec/git-\
core/git-svn line 482

為了解決該問題,可以運(yùn)行 git svn rebase ,它會(huì)拉取服務(wù)器上所有最新的改變,再次基礎(chǔ)上衍合你的修改:

$ git svn rebase
       M      README.txt
r80 = ff829ab914e8775c7c025d741beb3d523ee30bc4 (trunk)
First, rewinding head to replay your work on top of it...
Applying: first user change

現(xiàn)在,你做出的修改都發(fā)生在服務(wù)器內(nèi)容之后,所以可以順利的運(yùn)行 dcommit :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
       M      README.txt
Committed r81
       M      README.txt
r81 = 456cbe6337abe49154db70106d1836bc1332deed (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

需要牢記的一點(diǎn)是,Git 要求我們?cè)谕扑椭跋群喜⑸嫌蝹}(cāng)庫(kù)中最新的內(nèi)容,而 git svn 只要求存在沖突的時(shí)候才這樣做。假如有人向一個(gè)文件推送了一些修改,這時(shí)你要向另一個(gè)文件推送一些修改,那么 dcommit 將正常工作:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
       M      configure.ac
Committed r84
       M      autogen.sh
r83 = 8aa54a74d452f82eee10076ab2584c1fc424853b (trunk)
       M      configure.ac
r84 = cdbac939211ccb18aa744e581e46563af5d962d0 (trunk)
W: d2f23b80f67aaaa1f6f5aaef48fce3263ac71a92 and refs/remotes/trunk differ, \
  using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 \
  015e4c98c482f0fa71e4d5434338014530b37fa6 M   autogen.sh
First, rewinding head to replay your work on top of it...
Nothing to do.

這一點(diǎn)需要牢記,因?yàn)樗慕Y(jié)果是推送之后項(xiàng)目處于一個(gè)不完整存在與任何主機(jī)上的狀態(tài)。如果做出的修改無(wú)法兼容但沒有產(chǎn)生沖突,則可能造成一些很難確診的難題。這和使用 Git 服務(wù)器是不同的——在 Git 世界里,發(fā)布之前,你可以在客戶端系統(tǒng)里完整的測(cè)試項(xiàng)目的狀態(tài),而在 SVN 永遠(yuǎn)都沒法確保提交前后項(xiàng)目的狀態(tài)完全一樣。

即使還沒打算進(jìn)行提交,你也應(yīng)該用這個(gè)命令從 Subversion 服務(wù)器拉取最新修改。sit svn fetch 能獲取最新的數(shù)據(jù),不過 git svn rebase 才會(huì)在獲取之后在本地進(jìn)行更新 。

$ git svn rebase
       M      generate_descriptor_proto.sh
r82 = bd16df9173e424c6f52c337ab6efa7f7643282f1 (trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/trunk.

不時(shí)地運(yùn)行一下 git svn rebase 可以確保你的代碼沒有過時(shí)。不過,運(yùn)行該命令時(shí)需要確保工作目錄的整潔。如果在本地做了修改,則必須在運(yùn)行 git svn rebase 之前或暫存工作,或暫時(shí)提交內(nèi)容——否則,該命令會(huì)發(fā)現(xiàn)衍合的結(jié)果包含著沖突因而終止。

Git 分支問題

習(xí)慣了 Git 的工作流程以后,你可能會(huì)創(chuàng)建一些特性分支,完成相關(guān)的開發(fā)工作,然后合并他們。如果要用 git svn 向 Subversion 推送內(nèi)容,那么最好是每次用衍合來(lái)并入一個(gè)單一分支,而不是直接合并。使用衍合的原因是 Subversion 只有一個(gè)線性的歷史而不像 Git 那樣處理合并,所以 Git svn 在把快照轉(zhuǎn)換為 Subversion 的 commit 時(shí)只能包含第一個(gè)祖先。

假設(shè)分支歷史如下:創(chuàng)建一個(gè) experiment 分支,進(jìn)行兩次提交,然后合并到 master 。在 dcommit 的時(shí)候會(huì)得到如下輸出:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
       M      CHANGES.txt
Committed r85
       M      CHANGES.txt
r85 = 4bfebeec434d156c36f2bcd18f4e3d97dc3269a2 (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk
COPYING.txt: locally modified
INSTALL.txt: locally modified
       M      COPYING.txt
       M      INSTALL.txt
Committed r86
       M      INSTALL.txt
       M      COPYING.txt
r86 = 2647f6b86ccfcaad4ec58c520e369ec81f7c283c (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

在一個(gè)包含了合并歷史的分支上使用 dcommit 可以成功運(yùn)行,不過在 Git 項(xiàng)目的歷史中,它沒有重寫你在 experiment 分支中的兩個(gè) commit ——另一方面,這些改變卻出現(xiàn)在了 SVN 版本中同一個(gè)合并 commit 中。

在別人克隆該項(xiàng)目的時(shí)候,只能看到這個(gè)合并 commit 包含了所有發(fā)生過的修改;他們無(wú)法獲知修改的作者和時(shí)間等提交信息。

Subversion 分支

Subversion 的分支和 Git 中的不盡相同;避免過多的使用可能是最好方案。不過,用 git svn 創(chuàng)建和提交不同的 Subversion 分支仍是可行的。

創(chuàng)建新的 SVN 分支

要在 Subversion 中建立一個(gè)新分支,需要運(yùn)行 git svn branch [分支名] :

$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r87 to file:///tmp/test-svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk => \
  file:///tmp/test-svn/branches/opera, 87
Found branch parent: (opera) 1f6bfe471083cbca06ac8d4176f7ad4de0d62e5f
Following parent with do_switch
Successfully followed parent
r89 = 9b6fe0b90c5c9adf9165f700897518dbc54a7cbf (opera)

這相當(dāng)于在 Subversion 中的 svn copy trunk branches/opera 命令,并會(huì)對(duì) Subversion 服務(wù)器進(jìn)行相關(guān)操作。值得注意的是它沒有檢出和轉(zhuǎn)換到那個(gè)分支;如果現(xiàn)在進(jìn)行提交,將提交到服務(wù)器上的 trunk, 而非 opera。

切換當(dāng)前分支

Git 通過搜尋提交歷史中 Subversion 分支的頭部來(lái)決定 dcommit 的目的地——而它應(yīng)該只有一個(gè),那就是當(dāng)前分支歷史中最近一次包含 git-svn-id 的提交。

如果需要同時(shí)在多個(gè)分支上提交,可以通過導(dǎo)入 Subversion 上某個(gè)其他分支的 commit 來(lái)建立以該分支為 dcommit 目的地的本地分支。比如你想擁有一個(gè)并行維護(hù)的 opera 分支,可以運(yùn)行

$ git branch opera remotes/opera

然后,如果要把 opera 分支并入 trunk (本地的 master 分支),可以使用普通的 git merge。不過最好提供一條描述提交的信息(通過 -m),否則這次合并的記錄是 Merge branch opera ,而不是任何有用的東西。

記住,雖然使用了 git merge 來(lái)進(jìn)行這次操作,并且合并過程可能比使用 Subversion 簡(jiǎn)單一些(因?yàn)?Git 會(huì)自動(dòng)找到適合的合并基礎(chǔ)),這并不是一次普通的 Git 合并提交。最終它將被推送回 commit 無(wú)法包含多個(gè)祖先的 Subversion 服務(wù)器上;因而在推送之后,它將變成一個(gè)包含了所有在其他分支上做出的改變的單一 commit。把一個(gè)分支合并到另一個(gè)分支以后,你沒法像在 Git 中那樣輕易的回到那個(gè)分支上繼續(xù)工作。提交時(shí)運(yùn)行的 dcommit 命令擦除了全部有關(guān)哪個(gè)分支被并入的信息,因而以后的合并基礎(chǔ)計(jì)算將是不正確的—— dcommit 讓 git merge 的結(jié)果變得類似于 git merge --squash。不幸的是,我們沒有什么好辦法來(lái)避免該情況—— Subversion 無(wú)法儲(chǔ)存這個(gè)信息,所以在使用它作為服務(wù)器的時(shí)候你將永遠(yuǎn)為這個(gè)缺陷所困。為了不出現(xiàn)這種問題,在把本地分支(本例中的 opera)并入 trunk 以后應(yīng)該立即將其刪除。

對(duì)應(yīng) Subversion 的命令

git svn 工具集合了若干個(gè)與 Subversion 類似的功能,對(duì)應(yīng)的命令可以簡(jiǎn)化向 Git 的轉(zhuǎn)化過程。下面這些命令能實(shí)現(xiàn) Subversion 的這些功能。

SVN 風(fēng)格的歷史

習(xí)慣了 Subversion 的人可能想以 SVN 的風(fēng)格顯示歷史,運(yùn)行 git svn log 可以讓提交歷史顯示為 SVN 格式:

$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009) | 2 lines

autogen change

------------------------------------------------------------------------
r86 | schacon | 2009-05-02 16:00:21 -0700 (Sat, 02 May 2009) | 2 lines

Merge branch 'experiment'

------------------------------------------------------------------------
r85 | schacon | 2009-05-02 16:00:09 -0700 (Sat, 02 May 2009) | 2 lines

updated the changelog

關(guān)于 git svn log ,有兩點(diǎn)需要注意。首先,它可以離線工作,不像 svn log 命令,需要向 Subversion 服務(wù)器索取數(shù)據(jù)。其次,它僅僅顯示已經(jīng)提交到 Subversion 服務(wù)器上的 commit。在本地尚未 dcommit 的 Git 數(shù)據(jù)不會(huì)出現(xiàn)在這里;其他人向 Subversion 服務(wù)器新提交的數(shù)據(jù)也不會(huì)顯示。等于說是顯示了最近已知 Subversion 服務(wù)器上的狀態(tài)。

SVN 日志

類似 git svn log 對(duì) git log 的模擬,svn annotate 的等效命令是 git svn blame [文件名]。其輸出如下:

$ git svn blame README.txt
 2   temporal Protocol Buffers - Google's data interchange format
 2   temporal Copyright 2008 Google Inc.
 2   temporal http://code.google.com/apis/protocolbuffers/
 2   temporal
22   temporal C++ Installation - Unix
22   temporal =======================
 2   temporal
79    schacon Committing in git-svn.
78    schacon
 2   temporal To build and install the C++ Protocol Buffer runtime and the Protocol
 2   temporal Buffer compiler (protoc) execute the following:
 2   temporal

同樣,它不顯示本地的 Git 提交以及 Subversion 上后來(lái)更新的內(nèi)容。

SVN 服務(wù)器信息

還可以使用 git svn info 來(lái)獲取與運(yùn)行 svn info 類似的信息:

$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

它與 blame 和 log 的相同點(diǎn)在于離線運(yùn)行以及只更新到最后一次與 Subversion 服務(wù)器通信的狀態(tài)。

略 Subversion 之所略

假如克隆了一個(gè)包含了 svn:ignore 屬性的 Subversion 倉(cāng)庫(kù),就有必要建立對(duì)應(yīng)的 .gitignore 文件來(lái)防止意外提交一些不應(yīng)該提交的文件。git svn 有兩個(gè)有益于改善該問題的命令。第一個(gè)是 git svn create-ignore,它自動(dòng)建立對(duì)應(yīng)的 .gitignore 文件,以便下次提交的時(shí)候可以包含它。

第二個(gè)命令是 git svn show-ignore,它把需要放進(jìn) .gitignore 文件中的內(nèi)容打印到標(biāo)準(zhǔn)輸出,方便我們把輸出重定向到項(xiàng)目的黑名單文件:

$ git svn show-ignore > .git/info/exclude

這樣一來(lái),避免了 .gitignore 對(duì)項(xiàng)目的干擾。如果你是一個(gè) Subversion 團(tuán)隊(duì)里唯一的 Git 用戶,而其他隊(duì)友不喜歡項(xiàng)目包含 .gitignore,該方法是你的不二之選。

Git-Svn 總結(jié)

git svn 工具集在當(dāng)前不得不使用 Subversion 服務(wù)器或者開發(fā)環(huán)境要求使用 Subversion 服務(wù)器的時(shí)候格外有用。不妨把它看成一個(gè)跛腳的 Git,然而,你還是有可能在轉(zhuǎn)換過程中碰到一些困惑你和合作者們的迷題。為了避免麻煩,試著遵守如下守則:

  • 保持一個(gè)不包含由 git merge 生成的 commit 的線性提交歷史。將在主線分支外進(jìn)行的開發(fā)通通衍合回主線;避免直接合并。
  • 不要單獨(dú)建立和使用一個(gè) Git 服務(wù)來(lái)搞合作??梢詾榱思铀傩麻_發(fā)者的克隆進(jìn)程建立一個(gè),但是不要向它提供任何不包含 git-svn-id 條目的內(nèi)容。甚至可以添加一個(gè) pre-receive 掛鉤來(lái)在每一個(gè)提交信息中查找 git-svn-id 并拒絕提交那些不包含它的 commit。

如果遵循這些守則,在 Subversion 上工作還可以接受。然而,如果能遷徙到真正的 Git 服務(wù)器,則能為團(tuán)隊(duì)帶來(lái)更多好處。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)