Git 中有一个神奇的功能,他可以让你用 Git 来管理 SVN。两个之间互不冲突,对于喜欢使用 Git 的同志,这是一个非常不错的选择。自从有了它妈妈再也不用担心 SVN 不好用了。

缘起

公司的项目是使用 svn 来管理的,而我更偏向使用 git ,但是公司使用的是 svn 我也没办法。 最开始在 macOS 上使用命令行来操作 svn ,但是好久没用了,命令也基本都忘了。找了半天也没有满意的客户端软件,直到别人推荐 Cornerstone ,用了一段时间还不错。但是后面用着还是发现了许多问题,用着不舒服。也就是这个不舒服,让我想换回命令行使用,于是我在Dash中输入 svn 查找相关命令,却搜索出了 git svn 这个东西。最开始我以为这是一个把 svn 项目转为 git 的工具,于是看了一下说明,如获至宝。原来这货可以可以作为 svn 的客户端工具,并且可以向 svn 提交代码,这比转换的功能牛逼多了。真是好激动!!!

主要功能

svn 项目以 git 方式 clone 到本地

首先要有 svn 的仓库,没有的话就搭建一个(不然怎么玩)。

1
git svn clone svn://127.0.0.1 test -T trunk -b branches -t tags

如果你在 Linux 下输入这条命令,会报以下错误,在 macOS 上面没碰到

1
2
3
4
5
6
7
$ git svn
git: 'svn' is not a git command. See 'git --help'.

The most similar commands are
fsck
mv
show

一开始我以为我安装的版本太旧了不支持 git svn ,于是升级到最新。升级之后我再次尝试,得到的结果还是一样,历史总是惊人的相似。 开始查资料,这次比较幸运,一查就中。提示中说了 git svn 不是 git 的命令,给了几个相似的命令也不是。解决方法就是安装 git svn

1
sudo apt install git-svn

再次执行 clone 输入账号和密码就可以正常使用了, svn 上的东西就会被 clone 到本地的 test 目录下。这时候就可以把 git 当成 svn 客户端来使用。

其实 git svn clonegit svn initgit svn fetch 两个命令的组合。 -T trunk -b branches -t tags 其中 -T-b-t 分别对应 svn 中的主干、分支、和标签名称。这些通常是标准的(没有修改过),由于使用很频繁,这整句可以使用 -s 来代替。

1
git svn clone svn://127.0.0.1 test -s

把文件加入版本控制

clonesvn 的项目之后,就可以使用 git 命令来管理 svn 项目。

1
2
touch README.md
git add README.md

提交代码

git 是一个分布式版本控制系统,这和 svn 是不一样的。 svn 在没有网络的情况下是没法提交代码的,而使用了 git svn 后就可以享受到分布式版本控制的好处,可以在本地进行提交变更。向本地提交变更和 git 原来的使用方式一样,使用 git commit 就行了。

1
git commit -m "add README.md"

这里需要注意一点,这里的提交是指提交到本地,没有更新到服务器,如果这时候磁盘损坏,你这次的更新是找不回来的。

svn 拉取更新

工作中通常是几个小伙伴一起开发项目,除了自己会向 svn 服务器提交代码,别人也会向服务器提交代码,我们需要把别人向服务器提交的代码同步下来,以获取最新的代码。经常同步代码是一个很好的习惯,可以减少冲突。 从服务器拉取最新的更新使用 git svn rebase ,它会拉取服务器上最新的改变,在此基础上 rebase(衍合) 你的修改。

1
git svn rebase

git svn rebase 虽好用,但是还不能适应所有场景。比如:你本地更改了某个文件,没有提交这个更新,此时你想从 svn 上更新,这时候使用 git svn rebase 是不行的。因为 git svn rebase 需要保证工作目录是干净的,你改动了就已经不干净了。所以在拉取更新之前最好做一次临时提交(commit)或者暂存(stash),不然引起冲突时命令会停止。

除了使用 git svn rebase 来同步上游更新外还可以手动从上游更新到本地

1
2
git svn fetch
git merge git-svn

使用 git svn fetch 来拉取 svn 上的内容到本地,它不会 merge 到当前分支,通常需要我们手动去合并。而使用 git svn rebase 不需要我们手动合并。

svn 推送更新

工作中可能会有许多小伙伴一起维护一个项目,使用 git 我们可以先把变更提交到本地,然后把己修改的代码推送到 svn 服务器,这时候就要用到 git svn dcommit 来向 svn 提交代码。

1
git svn dcommit

这里需要注意一点, git 在往服务器推送之前,需要更新到上游最新提交,不然是无法合并的,而 git svn 只需要有冲突的时候才需要这样做。当有人更新了一个 A 的文件并推送到了服务器,这时候你更新了 B 文件,使用 git svn dcommit 是可以正常工作的。这和 svn 的做法是类似的,如果是 git 的话,你先要同步上游更新,然后才能向服务器推送更新。

假如在 git 下使用 commit 向本地提交了多次,这时候使用 git svn dcommit 会把本地提交的多次更新,依次向 svn 服务器推送。也就说你使用 git commit 向本地提交了多次更新,在使用 git svn dcommit 之后 svn 里的 log 就会有多次更新。

解决冲突问题

在多个人协同工作的过程中难免会碰到冲突,无法自动合并,这时候就需要我们手动解决。在 git 中解决 svn 的冲突和解决 git 中一样,没有多大的区别。我们把 svn 当成 git 用就好了,一般冲突会发生在 rebase 上。我们手动修改冲突的文件后用 git add . 然后 git rebase --continue 就可以解决。

其它一些功能

ignore

项目中有些文件我们不想加入到版本控制系统中,比如:在 macOS 下面的文件系统、项目中编译生成的文件、IDE 的配置。这些每个人的都不一样,纳入到版本控制中会污染整个项目,别人更新了你的配置还会对别人造成不必要的麻烦。所以这些文件是不应该被加入到版本控制中的,如果我们手动去管理,这会变得非常麻烦,管理这些需要花太多精力,一个好的工程师应不应该话太多时间在这上面。 幸好 svngit 都提供了 ignore 来把一些不需要加入版本控制的文件给管理起来。在使用中 gitignore 会比 svn 的好用, git 只需要在 .gitignore 中写一些规则就可以了, svn 就麻烦了许多。 使用 git 管理 svnignore 也是很简单的。

1
git svn create-ignore

它会自动创建 .gitignore 文件,并把 svn 中的 ignore 拷贝到 git 中。

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

log

git 中我们查看 log,可以使用 git log 来查看。对于熟悉 svn 的同学可能习惯了 svn 的显示风格,可以使用 git svn log 显示 svn 风格的 log。在 svn 中查看 log 是需要连上网络不能离线的,但是用 git svn log 是可以在没有网络的情况下查看 log 的,这一点似乎增强了 svn 的功能。

svn 服务器信息

svn 提供了 svn info 来查看服务器信息,用 git 管理之后可以使用 git svn info 来查看。

参考

Git