其实这个学习很早之前就开始了,主要的动机就是Xcode10不支持SVN,导致所有的项目代码在Xcode10上再也无法对照历史版本了(隔壁大佬提出严重抗议)。
解决方法也是大佬找到的,说试试git-svn这个玩意儿。然而组里一直用的SVN,大佬们也没有那么多时间去试错,因此这个任务就落到当时的“闲人”我身上了。
git-svn顾名思义,就是使用git来连接SVN仓库。
一句话概括:SVN充当了本地git的远程仓库,类似GitHub,使用的命令基本可以一一对应
图有一定自己理解的成分不一定都对,但意思应该表达清楚了
和以前用SVN相比就是多了本地git的环节,因此多了一些工作区和本地git操作的步骤。
——————————
这里再提一个概念,感觉明白这个概念后面的内容都很好理解。
git rebase命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 到最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。
具体的可选参数参照官方文档
1.从SVN仓库拉取代码并且使用git管理
git svn clone URLorOtherAddress //可类比为 git clone/svn checkout
2.暂存代码,清空工作区
git stash
3.从SVN更新代码
git svn rebase //可类比为 git pull/svn up
4.恢复工作区
git stash pop //如果缓存内容和3.拉取下来的内容发生冲突,即为git的一般冲突(以下称merge冲突),参考解决方法见后文
5.提交工作区修改到本地git上
git add filename
git commit -m"note" //等效于XCode10上使用Source Control的commit change操作
6.把本地git修改上传到SVN
git svn dcommit //可类比为 git push/svn ci
7.正常开发重复步骤2-6即可顺利提交代码。
有几点注意一下:
1.工作区no clear时是不能git svn rebase和git svn dcommit的,因此才会考虑先stash再rebase再dcommit
2.这里描述的步骤是认为远程的SVN仓库在其间没有变化,更保险的可以在dcommit前再进行一次stash+rebase的操作,这样可以处理merge冲突而非git svn rebase/git svn dcommit中的冲突(以下简称rebase冲突)。
Rebase(git svn rebase后发生的)冲突发生的主要情况:
git svn rebase前并没有使用git stash而是通过git add+git commit提交修改到本地git,这时候工作区是干净的,如果此时拉取下来的SVN代码和本地git代码有冲突就会进入rebase冲突处理模式
输入 git status 可以看到类似输出
rebase in progress; onto XXXXXX
You are currently rebasing branch 'master' on 'a5c0f62'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
如果能够理解三行命令其实也就能明白rebase冲突的解决方法了。
1.找到冲突文件处理冲突。此时git status也有冲突文件的相关提示
Unmerged paths:
(use "git reset HEAD ..." to unstage)
(use "git add ..." to mark resolution)
both modified: conflict.file
2.git add conflict file,变成了“常规”的待commit情况
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: conflict.file
3.接下来有两种情况
3.1 如果选择使用 git commit -m"注释" 的命令,在提交完成后使用git status会发现依然处于rebase状态,并且会提示如下
(all conflicts fixed: run "git rebase --continue")
这里会有一个坑,如果你按提示 git rebase --continue,会出现以下提示
Applying: “XXX”
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else
already introduced the same changes; you might want to skip this patch.
Resolve all conflicts manually, mark them as resolved with
"git add/rm ", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
这是因为commit使得rebase流程找不到add进来的修改好的冲突文件了,使用git rebase --skip跳过rebase流程即可
这时候rebase冲突就算解决完了,git svn dcommit即可上传到远程SVN库。
3.2 add之后使用 git rebase --continue,搞定收工,之后git svn dcommit即可上传到远程SVN库。
还会有这样的情况,git svn dcommit前并没有rebase更新到最新代码,这时候add+commit+dcommit的操作会出现这样的提示:
Committing to http://svn.XXX ...
ERROR from SVN:
Merge conflict during commit: resource out of date; try updating
W: 893984c3f86854327dbd557077fca5bbbdff2f45 and refs/remotes/git-svn differ, using rebase:
:040000 040000 4692cdc2348916edf991afa99f766e5650e69a42 505984ba896e9f255d183a53210c3454aebc2c9d M branch_2.2.1_201810261051
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.
这个时候并没有进入Rebase冲突和Merge冲突的情况中,而且代码很有可能提交失败,并没有提交到SVN库中。
最关键的是在本地工作区会认为文件已提交,对应的标记也会消失。
这种情况需要特别注意,也想找到好的解决方法,无论是找回冲突文件还是回到之前版本。
下面都是一些遇到的总结的点,补充一下
1.git和SVN有一点很不一样,SVN是通过文件目录控制其操作范围的,而git却不是。
假设根目录A下有三个文件一个文件夹B,B下有两个文件。在B下使用svn st只能看到B下两个文件的状态,使用git status能看总共五个文件的状态。
2.这里提一下merge冲突可选的处理方法(这里指stash pop时本地工作区代码和本地git代码冲突的情况):
最简单的就是根据git stash pop时的提示找到冲突文件,修改冲突的地方,然后add+commit+dcommit;
后来发现有一个工具,出现merge冲突时使用git mergetool,可视化显示冲突文件,下方选好要的版本,关闭时保存就好了,直接免去了找文件和add+commit的过程。使用mergetool后会产生一个名为“冲突文件名.org”的文件,用vi打开可以看到里面就是冲突文件的备份
3.Xcode10文件标记的情况:
出现正常冲突时出现C标记
修改冲突并add后变成M标记
git rebase —continue后M标记消失
4.单个文件更新:
SVN更新文件是会取决于文件路径的。只有本地文件和SVN仓库的概念,直接svn up file/to/update就可以更新单个文件
Git-svn想要更新可以使用git svn rebase,但是会把整个本地仓库、本地文件更新
如果想对本地文件进行单个更新,使用git checkout file/to/path命令可以用本地仓库覆盖本地文件,但不能取得SVN仓库的版本
解决方法:
git svn fetch //先更新本地仓库,但不更新本地文件
git checkout [git-svn分支字符串,fetch时会提供] file/to/path //单独更新某个文件
另外:提交时采用git svn dcommit —no-rebase 避免git svn rebase更新全部文件
5.从1.延伸开来,git由于不基于目录进行管理,所以在本地删除了文件夹,其实是推不上去svn,也就是无法删除svn仓库内的那个空目录
以上如有疏漏和错误,欢迎指正