简单解决方案:在合并后删除“work”分支
简短回答: 你可以使用git任何你喜欢的方式(参见下面的简单工作流),包括合并。只需确保在每个'git merge work'后跟 'git branch -d work'以删除临时工作分支。
背景说明:合并/提交的问题在于,每当你'git svn dcommit'一个分支时,该分支的合并历史会被'扁平化':git会忘记所有合并操作,只保留文件内容,但该内容(部分)来自特定的其他分支的事实将丢失。详情请见:为什么git svn dcommit会丢失本地分支合并提交历史?
(注意:git-svn 并没有太多可做的:svn根本不理解更强大的 git 合并。因此,在svn存储库中,不能以任何方式表示这种合并信息。)
但这就是整个问题所在。如果你在将“work”分支合并到“master分支”之后将其删除,则你的git存储库就是100%干净的,看起来完全像你的svn存储库。
我的工作流程:
当然,我首先将远程svn存储库克隆到本地git存储库中(这可能需要一些时间):
$> git svn clone <svn-repository-url> <local-directory>
所有工作都在“本地目录”中进行。每当我需要从服务器获取更新(例如“svn update”)时,我执行以下操作:
$> git checkout master
$> git svn rebase
我所有的开发工作都在一个名为“work”的单独分支中完成,创建方式如下:
$> 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" 命令查看详细信息。简而言之:此命令首先打开一个编辑器,呈现您的提交——只需将“选择”更改为“压缩”,以便所有这些提交都与以前的提交一起压缩。当然,第一行应保持为“选择”。通过这种方式,您可以将许多小的提交压缩成一个或多个有意义的单元。
保存并退出编辑器。然后您将得到另一个编辑器,要求您重新编写提交日志消息。
简而言之:在完成代码修改后,我对“工作”分支进行调整,直到它看起来符合我想向其他程序员展示它的方式(或者当我浏览历史记录时想要看到工作几周后的外观)。
为了将更改推送到svn存储库中,我执行:
$> git checkout master
$> git svn rebase
现在我们回到旧的“master”分支,其中包含svn存储库中发生的所有更改(您的新更改隐藏在“work”分支中)。
如果有可能与您的新“work”更改冲突的更改,则必须在推送新工作之前在本地解决这些更改(详见下文)。 然后,我们可以将更改推送到svn:
$> git checkout master
$> git merge work
$> git branch -d work
$> git svn dcommit
注意1:命令“git branch -d work”非常安全:它只允许你删除不再需要的分支(因为它们已经合并到当前分支中)。如果在将你的工作与'master'分支合并之前误执行此命令,你将收到错误消息。
注意2:确保在合并和dcommit之间使用“git branch -d work”命令删除分支。如果您尝试在dcommit之后删除分支,将会出现错误消息:当您执行“git svn dcommit”时,git会忘记您的分支已经与'master'合并。你必须用“git branch -D work”删除它,这不会执行安全检查。
现在,我立即创建一个新的“work”分支,以避免意外地操作'master'分支:
$> git checkout -b work
$> git branch # show my branches:
master
* work
将您的“工作”与svn上的更改集成:
当我使用“git svn rebase”时,它显示其他人在我正在处理的“工作”分支上进行了svn仓库的更改,这是我所做的:
$> git checkout master
$> git svn rebase
$> git checkout work
$> git checkout -b integration
$> git merge master
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master
$> git svn rebase
$> git merge integration
$> git branch -d work
$> git branch -d integration
$> git svn dcommit
还有更加强大的解决方案:
所提供的工作流程过于简单: 它仅在每轮“update/hack/dcommit”中利用 git 的威力,但是将长期项目历史记录保持线性,就像 svn 存储库一样。如果您只想在传统 svn 项目中小步使用 git 合并,则可以这样做。
当您熟悉 git 合并后,可以随意尝试其他工作流程: 如果您知道自己在做什么,可以将 git 合并与 svn 合并混合使用(Using git-svn (or similar) just to help out with svn merge?)
--mergeinfo=<mergeinfo>
选项,可以将合并信息传递给SVN。不过我不确定应该如何使用它。 - Mr_and_Mrs_D