1. 程式人生 > >GIT版本控制 — GIT與SVN的相互轉換 (三)

GIT版本控制 — GIT與SVN的相互轉換 (三)

git-svn

git-svn用於Git和SVN的轉換,可以把Git倉庫遷移成SVN倉庫,反之亦可。

詳細介紹可見[1],或者命令列輸入git-svn。

Bidirectional operation between a Subversion repository and git.

git svn can track a standard Subversion repository, following the common "trunk/branches/tags" layout,

with the --stdlayout option. It can also follow branches and tags in any layout with the -T/ -t/ -b options.

Once tracking a Subversion repository, the git repository can be updated from Subversion by thefetch

command and Subversion updated from git by the dcommit command.

Git遷移到SVN

把Git遷移到SVN?沒錯,還真有這種需求,雖然較少:)

Git has a feature to work with SVN repositories, git-svn, but that's intended to check out

existing code from SVN and work on it, not publishing an existing Git tree into a SVN repository.

(1) 依賴包

需要安裝subversion-perl、perl-TermReadKey。

Git中帶有git-svn,需要確定它的路徑可在PATH中找到。

(2) 建立svn專案

在svn伺服器中新建svn專案proj。

# svnadmin create proj

(3) svn專案的本地初次提交

(4) 提交Git proj專案到SVN proj

進入Git proj專案。

    標準佈局的意思就是:

    trunk分支為:proj/trunk,可以用-T另外指定

    branches分支為:proj/branches,可用-b另外指定

    tags分支為:proj/tags,可用-t另外指定

# git-svn fetch // 獲取SVN proj的更新

    r1 = 79563196f21ce4699a04fa4ae24d0ca916bf3acf (refs/remotes/trunk)

    trunk分支代表SVN proj的trunk分支

# git-svn dcommit // 提交Git proj的更新

    注意!這個時候會報錯:

    Unable to determine upstream SVN information from HEAD history.

    Perhaps the repository is empty. at /usr/local/git/libexec/git-core/git-svn line 852.

因為現在Git proj的commits不知道要放到SVN proj的哪個版本之後,即Git proj的這些提交要

放在SVN哪個版本之後(顯然是放到SVN的初始提交之後,但是Git proj就是不知道,因為設計者

並不考慮把Git proj轉為SVN proj的情況:)

以下是詳細描述:

This fails since the git svn command can't figure out which commits to push: there's no link

between our original Git repository and the Subversion heads.

To fix this, we can use a Git graft to link them. We'll tell Git the commit which created the SVN

folder in which we want to store the project is the parent commit of the first commit in our Git

repository.

解決方法

# git show-ref trunk // 顯示SVN proj trunk分支的HEAD,即r1

   79563196f21ce4699a04fa4ae24d0ca916bf3acf refs/remotes/trunk

# git log --pretty=oneline master | tail -n 1 // 顯示Git proj 的第一個commit

    561c439a15f807b8d62551a0c64f939c15489899 initial import

# echo "561c439a15f807b8d62551a0c64f939c15489899 79563196f21ce4699a04fa4ae24d0ca916bf3acf" >> .git/info/grafts

    把Git proj從561c43開始的提交,新增到SVN proj在795631之後的提交。

# git-svn dcommit // 提交Git proj的更新到SVN proj中

    這個時候就把Git proj完整的轉化成SVN proj,後者完全符合SVN的規範了。

(5) 把git分支提交到svn的分支

如果原來的git倉庫不僅有master,還有其它分支,那麼怎麼把git的分支提交為svn的分支呢?

這個時候就要用到git rebase了。

過程如下:

在遠端svn倉庫中建立一個新分支。

# svn cp URL/trunk URL/branches/remote-branch

更新本端Git倉庫。

# git-svn fetch

切換到本端的分支。

# git checkout local-branch

建立一個用於臨時用的分支,其實和local-branch是一樣的。

# git checkout -b temp-local-branch

關鍵點來了,把本端分支的所有修改,合併到遠端分支。

# git rebase remotes/remote-branch

完成上一步以後,遠端分支已經含有本端分支的所有commit。

接著可以把修改提交到svn倉庫了。

# git svn dcommit

最後把本端的臨時分支刪除。

# git branch -D temp-local-branch

此時再檢視svn倉庫,就會發現branch/remote-branch已經是原來的git分支了。

不過svn分支的日誌順序,相較於原來git分支的可能會有所不同,這是由rebase引起的,正常現象。

(6) 從git分支更新svn分支

修改.git/config,新增遠端分支:

[svn-remote "branch"]

url = URL/proj/branches/branch

fetch = :refs/remotes/branch

繫結本地分支和遠端分支:

[branch "local-branch"]

remote = .

merge = refs/remotes/branch

修改了本地分支local-branch後,可以直接提交到遠端svn的branch分支了。

# git-svn dcommit

SVN遷移到Git

相比之前介紹的Git遷移到SVN,SVN遷移到Git才是主流趨勢,也更加容易,因為這是git-svn的主要目的。

同樣用git-svn來完成遷移:

git-svn primarily can be used to checkout a Subversion repository to a local Git repo and then

push your changes back to the original Subversion repository.

克隆SVN倉庫,可以使用-T trunk、-b branches、-t tags來指定對應分支,-s表示採用標準佈局。

# git-svn clone -s URL/proj proj

相當於執行了git-svn init和git-svn fetch。

把SVN倉庫的更新同步到Git。

# git-svn rebase

建立.gitignore檔案。

# git-svn create-ignore

將Git的更新提交到SVN倉庫。

# git-svn dcommit

Author

zhangskd @ csdn blog

Reference