/ git-svn

git-svn 工作流

Mac 下好用的 SVN 客户端只有 Versions、Cornerstone 两款,但都是付费软件,使用体验也都一般。最近 Version 试用期限已到,于是换用 SourceTree 来做版本控制。

SourceTree 原生支持 Git 与 Mercury,然而内置的 git-svn 使得这款软件也可以用来管理 SVN 版本库。SourceTree 在本地使用 Git 对 SVN 库做版本控制,需要与远程 SVN 库交互,拉取或推送代码时会自动调用 git-svn 命令,既可以在日常开发中发挥 git 拉分支带来的便利,又可以方便地与远程 SVN 库保持同步。

典型的 Git 工作流包括下面几个步骤:

  1. clone 版本库到本地
  2. 创建分支,在分支上进行开发
  3. 合并分支,解决冲突
  4. 推送本地 commit 到远程版本库

使用 git-svn 做为版本控制工具,工作流和使用 git 基本一致,只是第1步和第4步稍有区别(要和远程 svn 版本库打交道)。

1. 将远程版本库 clone 到本地

> cd 某目录
> git svn clone -r xxxxx 远程地址

切换到某个目录下,使用 git svn clone 命令将版本库 clone 到该目录下。如果版本历史较多,可以使用 -r xxxxx 参数指定从某个 revision 之后开始 clone,减少拉取版本库的时间。

SourceTree 的 GUI 中带有 clone 版本库的功能,但如果 SVN 库地址以 http:// 开头,SourceTree 似乎无法正确识别。因此需要通过上面的命令进行版本库 clone ,再将本地 repo 添加到 SourceTree 中。

2. 创建分支,提交修改

Git workflow 最鲜明的特点是大量使用分支(branch)。既然使用了 Git,不妨充分发挥它强大的分支功能。

2.1 创建分支

> git branch work

使用 branch 命令拉一个工作分支,日常的开发工作都在这个分支中进行,需要合并代码时再合并到 master 分支当中,减少代码合并次数。

2.2 提交修改

对代码进行一些改动,在 SourceTree 中选择需要提交的文件添加到 staged files(Git 的待提交区)中,点 commit 按钮完成提交。

SourceTree commit

当然,也可以通过一行命令快速提交所有改动:

$ git commit -a -m ""

3. 合并分支

在创建了 work 分支之后,日常开发都在 work 分支上进行(即一般情况下 commit 到 work 分支)。当开发完成时,需要将 work 分支中的改动合并到 master 分支,以便提交到版本库。

分支合并有两种方式,merge 和 rebase两种方式的区别见下图:
merge vs rebase

merge 之后保留了被 merge 分支的历史状态,而 rebase 则是将两个分支拼成同一个分支,版本历史中不再单独显示被合并的分支。

在 git-svn 环境下,推荐使用 rebase 方式。因为尝试 merge 时,SourceTree 会弹出一则十分吓人的消息:

Merging in a Subversion repository Not Recommended

在 SourceTree 的分支名上右键,选择 "Merge [branch] into [branch]" 就可以实现分支合并。虽然菜单项显示的是“Merge”,后台实际上采用的是 rebase。

SourceTree merge branch

实际开发过程中,可能会碰到 work 分支有 commit,同时远程版本库也有更新的情况。这时,建议先切回 master 分支,将远程版本库 pull 下来,再将更新过的 master 分支合并到 work 分支,在 work 分支上解决可能出现的冲突。冲突解决完毕后,再将 work 分支合并回 master 分支。这样可以保证 master 分支不出问题。

解决冲突可以通过第三方 diff/merge 工具,也可以直接在 SourceTree 窗口中进行。当本地 repo 中有冲突时,可以在 working copy 区域看到所有冲突的文件,可以在右键菜单中选择 "resolve using Theirs" 或者 "resolve using Mine" 来快速解决 conflict。

使用 SourceTree 解决冲突时,还需要注意一个细节。 当处理完所有的冲突之后,直接在 Terminal 中运行 git rebase --continue 会提示需要先执行 git add ,而依次 git add 所有发生了冲突的代码文件是一件很麻烦的事。SourceTree 可以在我们解决完冲突后自动继续 rebase,这一操作必须通过 Action->Continue Rebase 菜单来执行。

SourceTree continue rebase

4. 推送到远程 SVN 版本库

work 分支中的更改合并到 master 分支后,可以使用 push 将本地的修改推送到远程 SVN 版本库。

Push to SVN

值得注意的是,在 OS X 10.10 下 SourceTree 自带的 SVN 命令无法正常工作,需要按照文章结尾的第2条参考链接中的方法解决。简单地说解决方法是创建下面两个软链接:

$ sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.18/darwin-thread-multi-2level/SVN /System/Library/Perl/Extras/5.18/SVN

$ sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.18/darwin-thread-multi-2level/auto/SVN/ /System/Library/Perl/Extras/5.18/auto/SVN

update: 上面的方法在 OS X 10.11 上会失效,因为 OS X 10.11 采用了新的安全机制。解决方法可以参考另外一则问答,具体操作是进入 Recovery Mode,然后打开 Terminal,执行下面的命令:

$ csrutil disable

参考

  1. git-svn 官方文档
  2. Solved: OS X Yosemite git svn broken
  3. git与SVN协同的工作流程
  4. git中merge和rebase的区别
  5. Using Source Tree, rebase with conflict, rebase doesn't work after conflict resolved
  6. 可能是最好的Git教程:Pro Git