使用 git-svn 整合 git 與 svn

git 是目前最紅的分散式 VCS 之一,我很喜歡用 git 因為他預設就有許多方便的特性如:

而 git 不僅僅是 git,他分成高階的命令如 pull/commit 等,還有低階的命令可以直接操作 ref/object,因此有一些 VCS 就是建立在 git 的檔案系統上,運作起來跟 git 截然不同。

git-svn 是一個可以把 svn 當 git 用的工具,就算專案還在用 svn 也可以享受到 git 的便利。以下簡介一下 git-svn 的使用流程。

首先創造一個實驗用的 svn repository:

    bob % cd /tmp/test
    bob % svnadmin create hello
    bob % svn co file:///tmp/test/hello hello-svn
    bob % cd hello-svn
    bob % svn mkdir branches tags trunk
    bob % svn ci -m'Initial dir setup'

現在我們有一個傳統的 svn repository 了,加點東西進去吧:

    bob % cd trunk
    bob % echo "printf("hello\n");" > hello.c
    bob % svn add hello.c
    bob % svn ci -m'My first program :D'
    bob % cd ..
    bob % svn cp trunk tags/v0.1
    bob % svn ci -m'tag v0.1'

這時候 Bob 已經建好他的程式 v0.1 版,Alice 知道了他的計劃也想加入,於是她用 git-svn 來取出 repository

    alice % git svn clone --stdlayout file:///tmp/test/hello hello-git
    Initialized empty Git repository in /tmp/test/hello-git/.git/
    r1 = 80a0fc18653e8bc7d3784567b1b7024b20fd8c11 (trunk)
        A	hello.c
    r2 = 4a80acebb6a41c208f3427498225f829950ee39e (trunk)
    Found possible branch point: file:///tmp/test/hello/trunk => file:///tmp/test/hello/tags/v0.1, 1
    Found branch parent: (tags/v0.1) 80a0fc18653e8bc7d3784567b1b7024b20fd8c11
    Following parent with do_switch
        A	hello.c
    Successfully followed parent
    r3 = 24ca9410e9ca78ffa3bffa1c9ef574068d128935 (tags/v0.1)
    Checked out HEAD:
      file:///tmp/test/hello/tags/v0.1 r3
    alice % git reset --hard remotes/trunk

因為是使用 stdlayout,所以 tag/branch 等會自動對應到 remote branch

    alice % cd hello-git
    alice % git branch -r
      tags/v0.1
      trunk

Alice 發現 Bob 原本的程式無法 compile,因此開始修改,改完之後用 git add -p 挑選要 commit 的部份,然後把剩下的部份 stash 起來,最後用 git svn dcommit 提交給 Bob 的 svn repository

    alice % edit hello.c
    alice % git add -p
    alice % git commit -m'Fix everything'
    alice % git stash
    alice % git svn dcommit

隔了幾天,Alice 發現 Bob 有更新,因此開始做同步。同時,因為她有一個 local branch,所以在更新完 master 之後,還需要把 fancy branch 跟 master rebase。

    alice % git svn fetch
        M	hello.c
    r6 = c43134a98f43dc6507deaa7495bfcd2c906aaa30 (trunk)
    alice % git svn rebase
    First, rewinding head to replay your work on top of it...
    Fast-forwarded master to refs/remotes/trunk.
    alice % git checkout fancy
    alice % git rebase master
    First, rewinding head to replay your work on top of it...
    Applying: Inital fancy output branch

以上就是使用 git-svn 時會用到的大部分指令,其餘的就跟操作一般 git 一樣。

各命令的詳細說明可以參考 git-svn(1)