简单的解决方案:合并后删除“工作”分支
简短回答:您可以随意使用 git(请参阅下面的简单工作流程),包括合并。只需确保在每个 'git merge work' 后面加上 'git branch -d work' 即可删除临时工作分支。
背景说明:
合并/dcommit 问题是,每当您“git svn dcommit”一个分支时,该分支的合并历史就会“扁平化”:git 忘记了进入该分支的所有合并操作:只保留了文件内容,但事实该内容(部分)来自特定的其他分支会丢失。见:Why does git svn dcommit lose the history of merge commits for local branches?
(注意:git-svn 对此无能为力:svn 根本无法理解更强大的 git 合并。因此,在 svn 存储库中,无法以任何方式表示此合并信息。)
但这是整个的问题。如果您在将“工作”分支合并到“主分支”后删除它,那么您的 git 存储库是 100% 干净的,并且看起来与您的 svn 存储库完全一样。
我的工作流程:
当然,我先将远程svn仓库克隆到本地git仓库(这可能需要一些时间):
$> git svn clone <svn-repository-url> <local-directory>
然后所有工作都在“本地目录”内进行。每当我需要从服务器获取更新(例如“svn update”)时,我都会这样做:
$> git checkout master
$> git svn rebase
我在一个单独的分支“工作”中完成所有开发工作,该分支的创建方式如下:
$> git checkout -b work
当然,您可以根据需要为您的工作创建任意数量的分支,并在它们之间进行合并和变基(只需在完成后删除它们 --- 如下所述)。在我的正常工作中,我经常提交:
$> git commit -am '-- finished a little piece of work'
下一步 (git rebase -i) 是可选的 --- 它只是在将其归档到 svn 之前清理历史:一旦我达到了我想与他人分享的稳定里程碑,我会重写此历史'work' 分支并清理提交消息(其他开发人员不需要看到我在路上犯的所有小步骤和错误 --- 只是结果)。为此,我这样做了
$> git log
并复制 svn 存储库中最后一次提交的 sha-1 哈希(如 git-svn-id 所示)。然后我打电话给
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
只需粘贴我们上次 svn 提交的 sha-1 哈希值,而不是我的。您可能需要阅读带有 'git help rebase' 的文档以了解详细信息。简而言之:此命令首先会打开一个编辑器来显示您的提交 ---- 只需将您想要与以前的提交压缩的所有提交更改“pick”为“squash”。当然,第一行应该保留为“选择”。通过这种方式,您可以将您的许多小提交压缩成一个或多个有意义的单元。
保存并退出编辑器。您将得到另一个编辑器,要求您重写提交日志消息。
简而言之:在我完成“代码破解”后,我会按摩我的“工作”分支,直到它看起来我想如何将它呈现给其他程序员(或者我想在几周后看到我的工作)浏览历史)。
为了将更改推送到 svn 存储库,我这样做:
$> git checkout master
$> git svn rebase
现在我们回到旧的“主”分支,更新了 svn 存储库中同时发生的所有更改(您的新更改隐藏在“工作”分支中)。
如果有可能与您的新“工作”更改发生冲突的更改,您必须先在本地解决它们,然后才能推送您的新工作(请参阅下面的详细信息)。然后,我们可以将更改推送到 svn:
$> git checkout master
$> git merge work # (1) merge your 'work' into 'master'
$> git branch -d work # (2) remove the work branch immediately after merging
$> git svn dcommit # (3) push your changes to the svn repository
注意 1:命令 'git branch -d work' 非常安全:它只允许您删除不再需要的分支(因为它们已经合并到您当前的分支中)。如果在将工作与“主”分支合并之前错误地执行了此命令,则会收到错误消息。
注意 2:确保使用 'git branch -d work' 在 merging 和 dcommit 之间删除您的分支:如果您在 dcommit 之后尝试删除分支,则会收到错误消息:当您执行“git svn dcommit”,git 忘记了您的分支已与“master”合并。您必须使用不进行安全检查的“git branch -D work”将其删除。
现在,我立即创建一个新的“工作”分支,以避免意外入侵“主”分支:
$> git checkout -b work
$> git branch # show my branches:
master
* work
将您的“工作”与 svn 上的更改相结合:
当 'git svn rebase' 显示其他人在我的 'work' 分支上工作时更改了 svn 存储库时,我会这样做:
$> git checkout master
$> git svn rebase # 'svn pull' changes
$> git checkout work # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master # try again to push my changes
$> git svn rebase # hopefully no further changes to merge
$> git merge integration # (1) merge your work with theirs
$> git branch -d work # (2) remove branches that are merged
$> git branch -d integration # (2) remove branches that are merged
$> git svn dcommit # (3) push your changes to the svn repository
存在更强大的解决方案:
所呈现的工作流程非常简单:它仅在每一轮“更新/黑客/dcommit”中使用 git 的功能 --- 但使长期项目历史与 svn 存储库一样线性。如果您只是想在遗留 svn 项目中的小第一步中开始使用 git 合并,这是可以的。
当您对 git 合并更加熟悉时,请随意探索其他工作流程:如果您知道自己在做什么,您可以将 git merge 与 svn merges 混合使用 (Using git-svn (or similar) just to help out with svn merge?)