$ git svn rebase
M README.txt
r80 = ff829ab914e8775c7c025d741beb3d523ee30bc4 (trunk)
First, rewinding head to replay your work on top of it…
Applying: first user change
现在,你做出的修改都发生在服务器内容之后,所以可以顺利的运行 dcommit
:
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk …
M README.txt
Committed r81
M README.txt
r81 = 456cbe6337abe49154db70106d1836bc1332deed (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk
需要牢记的一点是,Git 要求我们在推送之前先合并上游仓库中最新的内容,而 git svn
只要求存在冲突的时候才这样做。假如有人向一个文件推送了一些修改,这时你要向另一个文件推送一些修改,那么 dcommit
将正常工作:
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk …
M configure.ac
Committed r84
M autogen.sh
r83 = 8aa54a74d452f82eee10076ab2584c1fc424853b (trunk)
M configure.ac
r84 = cdbac939211ccb18aa744e581e46563af5d962d0 (trunk)
W: d2f23b80f67aaaa1f6f5aaef48fce3263ac71a92 and refs/remotes/trunk differ, \
using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 \
015e4c98c482f0fa71e4d5434338014530b37fa6 M autogen.sh
First, rewinding head to replay your work on top of it…
Nothing to do.
这一点需要牢记,因为它的结果是推送之后项目处于一个不完整存在与任何主机上的状态。如果做出的修改无法兼容但没有产生冲突,则可能造成一些很难确诊的难题。这和使用 Git 服务器是不同的——在 Git 世界里,发布之前,你可以在客户端系统里完整的测试项目的状态,而在 SVN 永远都没法确保提交前后项目的状态完全一样。
即使还没打算进行提交,你也应该用这个命令从 Subversion 服务器拉取最新修改。sit svn fetch
能获取最新的数据,不过 git svn rebase
才会在获取之后在本地进行更新 。
$ git svn rebase
M generate_descriptor_proto.sh
r82 = bd16df9173e424c6f52c337ab6efa7f7643282f1 (trunk)
First, rewinding head to replay your work on top of it…
Fast-forwarded master to refs/remotes/trunk.
不时地运行一下 git svn rebase
可以确保你的代码没有过时。不过,运行该命令时需要确保工作目录的整洁。如果在本地做了修改,则必须在运行 git svn rebase
之前或暂存工作,或暂时提交内容——否则,该命令会发现衍合的结果包含着冲突因而终止。
Git 分支问题
习惯了 Git 的工作流程以后,你可能会创建一些特性分支,完成相关的开发工作,然后合并他们。如果要用 git svn 向 Subversion 推送内容,那么最好是每次用衍合来并入一个单一分支,而不是直接合并。使用衍合的原因是 Subversion 只有一个线性的历史而不像 Git 那样处理合并,所以 Git svn 在把快照转换为 Subversion 的 commit 时只能包含第一个祖先。
假设分支历史如下:创建一个 experiment
分支,进行两次提交,然后合并到 master
。在 dcommit
的时候会得到如下输出:
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk …
M CHANGES.txt
Committed r85
M CHANGES.txt
r85 = 4bfebeec434d156c36f2bcd18f4e3d97dc3269a2 (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk
COPYING.txt: locally modified
INSTALL.txt: locally modified
M COPYING.txt
M INSTALL.txt
Committed r86
M INSTALL.txt
M COPYING.txt
r86 = 2647f6b86ccfcaad4ec58c520e369ec81f7c283c (trunk)
No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk
在一个包含了合并历史的分支上使用 dcommit
可以成功运行,不过在 Git 项目的历史中,它没有重写你在 experiment
分支中的两个 commit ——另一方面,这些改变却出现在了 SVN 版本中同一个合并 commit 中。
在别人克隆该项目的时候,只能看到这个合并 commit 包含了所有发生过的修改;他们无法获知修改的作者和时间等提交信息。
Subversion 分支
Subversion 的分支和 Git 中的不尽相同;避免过多的使用可能是最好方案。不过,用 git svn 创建和提交不同的 Subversion 分支仍是可行的。
创建新的 SVN 分支
要在 Subversion 中建立一个新分支,需要运行 git svn branch [分支名]
:
$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r87 to file:///tmp/test-svn/branches/opera…
Found possible branch point: file: