简单的解决方案:合并后删除“工作”分支
简短回答:您可以随意使用 git(请参阅下面的简单工作流程),包括合并。只需确保在每个“ git merge work ”后面加上“ git branch -d work ”即可删除临时工作分支。
背景说明:
合并/dcommit 问题是,每当您“git svn dcommit”一个分支时,该分支的合并历史就会“变平”:git 忘记了进入该分支的所有合并操作:只保留文件内容,但是该内容(部分)来自特定的其他分支的事实丢失了。请参阅:为什么 git svn dcommit 会丢失本地分支的合并提交历史记录?
(注意: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 之前清理历史:一旦我达到了我想与他人分享的稳定里程碑,我会重写这个“工作”的历史分支并清理提交消息(其他开发人员不需要看到我在路上犯的所有小步骤和错误 --- 只是结果)。为此,我做
$> 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
现在我们回到旧的“master”分支,更新了 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:确保在合并和 dcommit之间使用 'git branch -d work' 删除您的分支:如果您尝试在 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”显示其他人在我的“工作”分支上工作时更改了 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 merges 与 svn merges 混合使用(使用 git-svn(或类似的)只是为了帮助 svn merge?)