内容简介:如今,虽然其实git很早就《小试git-svn》一文仅是通过文字性描述简要说明了git操作svn repo的基本命令和功能,并未结合实际例子,也缺少直观的图片展示,并且未涉及branch和tag的操作。这里打算再写一篇关于使用git操作svn仓库的文章,相比于前者,我期望该文能更为系统并结合demo图文并茂的把使用git操作svn仓库这个事情讲的更形象和透彻一些。
如今,虽然 Git 已经大行其道,但是仍有很多IT公司和组织依旧在使用集中式的版本控制系统 subversion ,尤其是一些传统软件公司,他们倾向于集中式的联网开发。如果你是一个Git fans,并且你要是遇到代码仓库依旧是使用subversion进行版本控制的情况,你又该如何施展呢?
其实git很早就 支持与subversion repo的互操作 了,2011年我就曾写过一篇《小试git-svn》的博文,也正是那一年,我第一次使用git操作subversion仓库。
《小试git-svn》一文仅是通过文字性描述简要说明了git操作svn repo的基本命令和功能,并未结合实际例子,也缺少直观的图片展示,并且未涉及branch和tag的操作。这里打算再写一篇关于使用git操作svn仓库的文章,相比于前者,我期望该文能更为系统并结合demo图文并茂的把使用git操作svn仓库这个事情讲的更形象和透彻一些。
一. 使用git操作svn repo的基本工作流
使用git操作svn repo的多数场景是已经存在一个svn repo,git fans想用git命令与之交互。下图展示了使用git操作这样的svn repo的基本工作流:
下面我们就用一个demo来详细地说明一下这个基本工作流。
1. 建立一个svn demo库
自己搭建一个svn server还是比较费力的,我们选择一个在线的svn代码托管SaaS服务:svnbucket.com。我们在svnbucket.com上注册账号并创建一个svn repo: test-git-svn ,该repo采用标准的项目布局(trunk/branches/tags):
接下来我们就开始git操作svn repo的过程!
2. 通过git首次获取svn仓库
git是分布式版本管理工具,无论是git repo还是svn repo,如果要用git操作,那么首先需要获取到repo的所有数据。git提供了svn子命令来操作远程的svn repo库,我们看一下首次获取svn repo信息的过程:
$git svn clone svn://svnbucket.com/bigwhite/test-git-svn/ Initialized empty Git repository in /Users/tony/Test/git-svn-test/test-git-svn/.git/ W: +empty_dir: branches W: +empty_dir: tags W: +empty_dir: trunk r1 = 8cfdc2f6059ff06f53c83d64518dcba146722c04 (refs/remotes/git-svn) Checked out HEAD: svn://svnbucket.com/bigwhite/test-git-svn r1 creating empty directory: branches creating empty directory: tags creating empty directory: trunk $tree ./test-git-svn ./test-git-svn ├── branches ├── tags └── trunk 3 directories, 0 files $cd test-git-svn $git branch -a * master remotes/git-svn
可以看到:我们通过git svn clone(注意:不是git clone)将远程server上的svn repo下载到了本地,后续我们就可以在本地host上快乐地使用git管理本地的代码了。
3. 从svn repo中同步最新的代码变更
接下来,远程的svn仓库经常会发生了变更,某开发人员向svn仓库提交了一些initial code,比如在trunk下建立git-svn-demo目录,并创建go.mod和main.go:
//在svn repo中的trunk/git-svn-demo目录下: $cat main.go package main import "fmt" func main() { fmt.Println("git-svn-demo initial version") } $cat go.mod module github.com/bigwhite/git-svn-demo
如果我们本地使用svn工具,我们只需在联网的情况下通过svn update命令即可将远程svn repo的最新改动同步到本地working copy中。但在git下,我们不能像git repo同步那样使用git pull来同步,而是需要使用git svn rebase来获取svn repo中的最新更新,并rebase我们的工作目录(working copy):
$git svn rebase A trunk/git-svn-demo/go.mod A trunk/git-svn-demo/main.go r2 = f826b74bfff2799deaafbca81354c38e0862509c (refs/remotes/git-svn) First, rewinding head to replay your work on top of it... Fast-forwarded master to refs/remotes/git-svn. $tree . . ├── branches ├── tags └── trunk └── git-svn-demo ├── go.mod └── main.go 4 directories, 2 files
git svn rebase子命令会根据svn上的revision创建对应的commit,这一命令几乎等效于”svn update”,同样也可能会存在远程svn repo中的代码与git repo冲突的可能性,解决冲突的方法在《小试git-svn》中已经做了描述,这里就不赘述了。
4. 将代码更新推送到远程svn repo
在这种模式下,本地开发已经完全变成了基于git的开发模式,开发者可以自由地发挥git的各种优势了,再也不用担心本地代码没有版本控制而出现各种“误删除”、“意外覆盖”的情况了。开发测试并提交(只需普通git commit)到local git repo后,最终还是要将这些commit推送到远程的svn repo中。这里我们不能用push,而要用git svn dcommit:
// 本地git repo中更新后的main.go $cat main.go package main import "fmt" func main() { fmt.Println("git-svn-demo: git-svn dcommit v0") }
先提交到git本地的仓库:
$git commit -m"[git svn]: first commit" . [master be36a7f] [git svn]: first commit 1 file changed, 1 insertion(+), 1 deletion(-)
然后再“推送”到远程的svn 仓库:
$git svn dcommit Committing to svn://svnbucket.com/bigwhite/test-git-svn ... M trunk/git-svn-demo/main.go Committed r3 M trunk/git-svn-demo/main.go r3 = e35efbe999cd035b2d5d67886c9a786ef86c681e (refs/remotes/git-svn) No changes between be36a7f1164b73a994f28ee3b0e0bb711b5ba2ff and refs/remotes/git-svn Resetting to the latest refs/remotes/git-svn
dcommit会将git repo当前branch与远程svn repo中的差异的git commit都提交到svn repo,并为每个git commit生成一个对应的svn revision。这和”git push”很类似。
我们再来本地做两次git commit:
$git commit -m"[git svn]: commit #2" . $git commit -m"[git svn]: commit #3" .
dcommit到svn repo:
$git svn dcommit Committing to svn://svnbucket.com/bigwhite/test-git-svn ... M trunk/git-svn-demo/main.go Committed r4 M trunk/git-svn-demo/main.go r4 = c997db60e3d82c97ce8da23b308d611005740844 (refs/remotes/git-svn) M trunk/git-svn-demo/main.go Committed r5 M trunk/git-svn-demo/main.go r5 = 3b6215a3e5ae0659743e1e8063f842448c19147c (refs/remotes/git-svn) No changes between ee0df22b9f41882518a7c7b975c38924a9422395 and refs/remotes/git-svn Resetting to the latest refs/remotes/git-svn
我们看到git svn为每个commit生成一个对应的svn revision(svn版本号),这里是r4、r5。
二. 利用git branch的优势
和svn建立branch的“重量级”操作(文件copy)相比,git的branch创建和切换可谓“超轻量级”。因此在日常使用git中,多数开发者都会充分发挥git branch的优势,通过在不同branch上的操作、分支的merge等来减少对master的并发修改带来冲突的影响。
我们经常使用feature branch或bugfix branch。以feature branch为例,在feature branch上一般会有多个commit。但在merge到master分支时,我们可以选择多种merge策略,或是fast forward,或是多个commit自动合并为一个commit,又或git merge支持–squash策略(即只merge代码到本地Working copy,不commit到git repo,后续可作为一个commit手工提交到git repo)。
我个人在用git操作svn repo库时,在git本地开发中,更倾向于使用git merge –squash的方法,因为在feature branch上,我更喜欢频繁的小变更的提交,导致commit很多。如果这些commit都dcommit到svn库,可能让svn commit history项目过多,有些commit甚至没有比较完善的意义。
我们在上面的demo上演示一下这个过程。
在本地建立新分支:feature-branch-1:
$git checkout -b feature-branch-1 Switched to a new branch 'feature-branch-1'
在feature-branch-1做两次修改并commit:
$git commit -m"add foo" . [feature-branch-1 d12ca00] add foo 1 file changed, 4 insertions(+) $git commit -m"add bar" . [feature-branch-1 160e5ed] add bar 1 file changed, 4 insertions(+)
回到master分支,merge feature分支的修改,并合并为本地的一次commit:
$git checkout master Switched to branch 'master' $git merge feature-branch-1 --squash Updating 3b6215a..160e5ed Fast-forward Squash commit -- not updating HEAD trunk/git-svn-demo/main.go | 8 ++++++++ 1 file changed, 8 insertions(+) $git commit -m"[git svn]: add foo and bar function" . [master fe8f153] add foo and bar function 1 file changed, 8 insertions(+)
接下来,将这次合并的commit同步到svn repo上:
$git svn dcommit Committing to svn://svnbucket.com/bigwhite/test-git-svn ... M trunk/git-svn-demo/main.go Committed r6 M trunk/git-svn-demo/main.go r6 = 37bbfbdb99cb7331057a05b72dc55b3faf55b645 (refs/remotes/git-svn) No changes between fe8f153cac62e027ca068fdd55c2bdaa8751aaf8 and refs/remotes/git-svn Resetting to the latest refs/remotes/git-svn
三. 通过git为svn库建立branch和打tag
通过git为svn repo建立branch和tag这类操作其实并没有体现出git的优势,因此日常开发人员一般会用svn命令直接操作svn repo,而不是用git svn子命令。但这里我们仍然要介绍一下通过git为svn repo建立branch和tag的方法。
我们先来看看创建branch:
$git svn branch feature-branch-1-from-git Multiple branch paths defined for Subversion repository. You must specify where you want to create the branch with the --destination argument.
我们看到git svn branch命令出错:让我们指定–destination参数,那我们就再来一遍:
$git svn branch feature-branch-1-from-git --destination=branches Unknown branch destination branches
依旧报错!似乎git不认识“branches”这个存放branch的目录!要想解决这个问题,我们需要对.git/config中的配置做些变更,添加最后两行:
$cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [svn-remote "svn"] url = svn://svnbucket.com/bigwhite/test-git-svn fetch = :refs/remotes/git-svn branches = branches/*:refs/remotes/* tags = tags/*:refs/remotes/*
原先的.git/config中并没有设置branhes和tags的入口。我们再来试一下建立branch:
git svn --username=bigwhite branch feature-branch-1-from-git Copying svn://svnbucket.com/bigwhite/test-git-svn at r8 to svn://svnbucket.com/bigwhite/test-git-svn/branches/feature-branch-1-from-git... Authorization failed: Unable to connect to a repository at URL 'svn://svnbucket.com/bigwhite/test-git-svn': Can't get password at /usr/local/Cellar/git/2.12.2/libexec/git-core/git-svn line 1200.
仍然报错!不过这个错误应该是 git(我使用的是2.12.2版本)的一个bug ,我们用try-run方式运行的结果却是一切ok的:
$git svn --username=bigwhite -n branch feature-branch-1-from-git Copying svn://svnbucket.com/bigwhite/test-git-svn at r8 to svn://svnbucket.com/bigwhite/test-git-svn/branches/feature-branch-1-from-git...
打tag的方式与建立 branch的方式类似:
$git svn tag v1.0.0 -n -m "[git svn]: tag v1.0.0" --destination=tags Copying svn://svnbucket.com/bigwhite/test-git-svn at r5 to svn://svnbucket.com/bigwhite/test-git-svn/tags/v1.0.0...
四. 小结
git svn子命令是git fans操作svn repo的利器。由于git svn clone svn_repo后的repo就是一个标准的本地git repo,因此我们还可以为该git repo建立remote upstream repo,这样就可以在local git repo、remote git repo以及remote svn repo三者之间进行代码变更的同步了,当然这种场景操作还是蛮复杂的,也相对少见。
个人建议,无论个人还是组织,即便使用svn中心repo,在本地也尽量用git来进行源码版本管理,并通过git svn与中心svn repo互操作。
我的网课“ Kubernetes实战:高可用集群搭建、配置、运维与应用 ”在慕课网上线了,感谢小伙伴们学习支持!
我爱发短信 :企业级短信平台定制开发专家 https://51smspush.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。
著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个 链接地址 :https://m.do.co/c/bff6eed92687 开启你的DO主机之路。
我的联系方式:
微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite
微信赞赏:
商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。
© 2019,bigwhite. 版权所有.
以上所述就是小编给大家介绍的《使用git操作svn仓库》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 数据仓库(一):认识数据仓库
- 将 svn 仓库迁移到 git 仓库
- 仓库ERP软件集成RFID打造智能仓库物流系统
- 实战maven私有仓库三部曲之二:上传到私有仓库
- BI和数据仓库:企业分析决策真的离不开数据仓库吗?
- java~gradle构建公用包并上传到仓库~使用私有仓库的包
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。