Git/git-svn
Subversion 是一個非常流行的版本控制系統,許多 OSS 和專有專案都使用它。 Git 帶有一個優秀的實用程式 git-svn,它允許使用者跟蹤在 subversion 倉庫中維護的專案,以及參與專案。使用者可以生成本地補丁併發送到郵件列表,甚至將更改直接提交回倉庫(當然,前提是他們有提交許可權)。
要開始使用 git 與 subversion 託管的專案進行互動,您必須為您的檔案建立一個本地倉庫,以及配置 git-svn。通常,您會使用類似以下命令的命令
mkdir project
cd project
git-svn init <url to repository root> -T/path/to/trunk
git-svn fetch -r <first rev>:HEAD
通常在使用 subversion 倉庫時,您會得到完整的專案 URL。要確定倉庫根目錄的 URL,您可以執行以下命令
svn info <full project URL>
輸出中將有一行顯示倉庫根目錄。trunk 的路徑只是 URL 中緊隨其後的其餘部分。可以簡單地將完整的專案 URL 提供給 git-svn,但這樣做可以讓您在最終使用 subversion 分支時獲得更大的靈活性。
還要注意 “first rev” 引數。您可以簡單地使用 “1”,因為這保證可以工作,但可能會花費很長時間(特別是如果倉庫位於速度緩慢的網路上)。通常,對於一個成熟的專案,最近的 10-50 個版本就足夠了。同樣,svn info 會告訴您最新的版本號。
如果您使用 git 而不是 svn 與 subversion 倉庫進行互動,那麼很可能是因為您想利用離線提交。如果您牢記一些注意事項,這將非常容易做到。最重要的是,在您計劃最終從某個分支執行 git-svn dcommit 的情況下,切勿使用 “git pull”。合併提交往往會讓 git-svn 感到困惑,而且您能夠在沒有 git pull 的情況下完成大多數需要做的事情。
我執行的最常見的任務是將我正在處理的更改與上游的 subversion 更改合併。這相當於 svn update。以下是完成操作的方法
git stash # stash any changes so you have a clean tree
git-svn fetch # bring down the latest changes
git rebase trunk
git stash apply
如果您的樹是乾淨的,則第一步和最後一步是不必要的。這將 “git rebase trunk” 作為主要操作。如果您不熟悉變基,您應該閱讀 git-rebase 的文件。它的本質是您的本地提交現在位於 svn HEAD 的頂部。
您想要在倉庫檔案中進行一些更改,但不希望傳播這些更改,這種情況經常發生。通常這種情況發生在配置檔案中,但它也可能是一些額外的除錯語句或其他任何內容。提交這些更改的危險在於您將在分支中執行 “git-svn dcommit”,而沒有剔除您的更改。另一方面,如果您未提交更改,您將失去 git 對這些更改的特性,而且您將不得不處理其他分支與這些更改的衝突。這是一個兩難的境地!
解決此問題有兩種方法。哪種方法更有效,與其說是技術問題,不如說是個人喜好問題。第一種方法是為每個想要保留本地更改的分支保留一個 “local” 分支。例如,如果您想在分支 “foo” 中保留本地更改,您將建立一個包含要保留的更改的提交的分支 “foo-local”。然後,您可以使用變基將 “foo” 保留在 “foo-local” 的頂部。例如
git rebase trunk foo-local
git rebase foo-local foo
正如示例程式碼所示,您仍然會在大多數情況下檢出 “foo”,而不是 “foo-local”。如果您決定進行新的更改,並且想要保留在本地,您將再次面臨兩種選擇。您可以檢出 “foo-local” 並進行提交,或者您可以在 “foo” 上進行提交,然後從 foo-local 中挑選提交。然後,您需要使用 git-reset 從 “foo” 中刪除提交。
作為以變基為中心的方法的替代方法,有一種基於合併的方法。您仍然將本地更改保留在單獨的分支上,如前所述。但是,使用這種方法,您不必使用變基將 “foo” 保留在 “foo-local” 的頂部。這是一個優勢,因為 1) 鍵入更多內容,以及 2) 歷史上,如果第一次變基期間出現任何衝突,變基通常會要求您兩次解決同一個衝突。
因此,您不是使用變基,而是建立另一個分支。我將此分支稱為 “build” 分支。您將在想要測試的任何提交處開始構建分支。然後,您可以 “git merge” 本地分支,將所有更改合併到一個樹中。“但是我認為您應該避免合併?”您可能會問。我之所以喜歡將此分支稱為 “build” 分支,是為了避免我從它執行 “git-svn dcommit”。只要您不打算從該分支執行 dcommit,合併的使用是可以接受的。
這種方法實際上可以更進一步,讓您不必每天將主題分支 “foo” 變基到 trunk 的頂部。如果您有多個主題分支,這種頻繁的變基會變成一件苦差事。相反
git checkout build
git reset --hard trunk # Make sure you dont have any important changes
git merge foo foo-local # Octopus merges are fun
現在 build 包含來自 trunk、foo 和 foo-local 的更改!我經常會保留多個本地分支。也許一個分支包含您的本地配置更改,另一個分支包含額外的除錯語句。您還可以使用這種方法在一個樹中同時構建多個主題分支
git merge topic1 topic2 config debug...
不幸的是,章魚合併對解決衝突非常笨拙。如果您遇到任何衝突,您將不得不一次執行一個合併
git merge topic1
git merge topic2
git merge local
...
最終,您將希望將精心製作的主題分支和補丁系列整合到上游。如果您有幸獲得了提交許可權,您可以執行 “git-svn dcommit”。這將獲取當前分支中的每個本地提交,並將它們提交到 subversion。如果您有三個本地提交,在 dcommit 之後,subversion 中將有三個新的提交。
對於不太幸運的人來說,您的補丁可能必須提交到郵件列表或錯誤跟蹤器。為此,您可以使用 git-format-patch。例如,繼續上面的三個本地提交的場景
git format-patch HEAD~3..
結果將在 $PWD 中生成三個檔案,0001-commit-name.patch、0002-commit-name.patch 和 0003-commit-name.patch。然後,您可以隨意將這些補丁傳送或附加到 Bugzilla 中的錯誤。但是,如果您要透過郵件傳送補丁,git 還可以進一步幫助您。有一個專門針對這種情況的 git-send-email 實用程式
git send-email *.patch
該程式會問您一些問題,其中最重要的是將補丁傳送到哪裡,然後將它們傳送出去。小菜一碟!
當然,這一切都假設您的補丁系列按預期工作。如果不是這樣,您應該閱讀有關 “git rebase -i” 的內容。
獲取 Pywikipedia
$ git svn init http://svn.wikimedia.org/svnroot/pywikipedia/trunk/pywikipedia/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r370 = 318fb412e5d1f1136a92d079f3607ac23bde2c34 (refs/remotes/git-svn)
D treelang_all.py
D treelang.py
W: -empty_dir: treelang.py
W: -empty_dir: treelang_all.py
r371 = e8477f292b077f023e4cebad843e0d36d3765db8 (refs/remotes/git-svn)
D parsepopular.py
W: -empty_dir: parsepopular.py
r372 = 8803111b0411243af419868388fc8c7398e8ab9d (refs/remotes/git-svn)
D getlang.py
W: -empty_dir: getlang.py
r373 = ad935dd0472db28379809f150fcf53678630076c (refs/remotes/git-svn)
A splitwarning.py
...
獲取 AWB(AutoWikiBrowser)
$ git svn init svn://svn.code.sf.net/p/autowikibrowser/code/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r15 = 086d4ff454a9ddfac92edb4013ec845f65e14ace (refs/remotes/git-svn)
M AWB/AWB/Main.cs
M AWB/WikiFunctions/WebControl.cs
r16 = 14f49de6b3c984bb8a87900e8be42a6576902a06 (refs/remotes/git-svn)
M AWB/AWB/ExitQuestion.Designer.cs
M AWB/WikiFunctions/GetLists.cs
M AWB/WikiFunctions/Tools.cs
r17 = 8b58f6e5b21c91f0819bea9bc9a8110c2cab540d (refs/remotes/git-svn)
M AWB/AWB/Main.Designer.cs
M AWB/AWB/Main.cs
M AWB/WikiFunctions/GetLists.cs
r18 = 51683925cedb8effb274fadd2417cc9b1f860e3c (refs/remotes/git-svn)
M AWB/AWB/specialFilter.Designer.cs
M AWB/AWB/specialFilter.cs
r19 = 712edb32a20d6d2ab4066acf056f14daa67a9d4b (refs/remotes/git-svn)
M AWB/WikiFunctions/WPEditor.cs
r20 = 3116588b52a8e27e1dc72d25b1981d181d6ba203 (refs/remotes/git-svn)
...
注意,此下載操作可能需要一小時。