git-svn dcommit合并后在git危险吗?

我尝试git-svn的动机是毫不费力的合并和分支。 然后我注意到man git-svn(1)说:

运行git-merge或git-pull不build议在你打算从dcommit分支。 颠覆不代表任何合理或有用的方式合并; 所以使用Subversion的用户不能看到你所做的任何合并。 另外,如果你从SVN分支的镜像分支合并或者拉出,dcommit可能会提交错误的分支。

这是否意味着我不能从svn / trunk(或分支)创build一个本地分支,破解,合并回svn / trunk,然后dcommit? 我知道svn用户会看到在svn pre 1.5.x中合并的混乱,但是还有其他的缺点吗? 最后一句话也让我担心。 人们经常做这些事情吗?

实际上,我发现在git merge上使用--no-ff选项更好。 我以前使用的所有这种压扁技术不再是必需的。

我现在的新工作stream程如下:

  • 我有一个“主”分支,这是我提出并克隆SVN仓库的唯一分支( -s假设你在仓库中的trunk/branches/tags/有一个标准的SVN布局):

     git svn clone [-s] <svn-url> 
  • 我在本地分公司工作( -b创build分支“工作”)

     git checkout -b work 
  • 在本地提交到“工作”分支( -s来签署你的提交信息)。 在续集中,我假设你做了3个本地提交

     ... (work)$> git commit -s -m "msg 1" ... (work)$> git commit -s -m "msg 2" ... (work)$> git commit -s -m "msg 3" 

现在你想提交到SVN服务器

  • [最后]隐藏你不想在SVN服务器上看到提交的修改(通常你在主文件中注释了一些代码,仅仅是因为你想加快编译和关注给定的function)

     (work)$> git stash 
  • 使用SVN仓库重新绑定master分支(从SVN服务器更新)

     (work)$> git checkout master (master)$> git svn rebase 
  • 回到工作分支,并与主人分享

     (master)$> git checkout work (work)$> git rebase master 
  • 确保一切正常使用,例如:

     (work)$> git log --graph --oneline --decorate 
  • 现在是时候把“work”分支的所有三个提交合并到“master”中,用这个美妙的--no-ff选项

     (work)$> git checkout master (master)$> git merge --no-ff work 
  • 您可以注意到日志的状态:

     (master)$> git log --graph --oneline --decorate * 56a779b (work, master) Merge branch 'work' |\ | * af6f7ae msg 3 | * 8750643 msg 2 | * 08464ae msg 1 |/ * 21e20fa (git-svn) last svn commit 
  • 现在你可能想编辑( amend )你的SVN帅哥的最后一个提交(否则他们只会看到一个提交消息“合并分支”的工作“

     (master)$> git commit --amend 
  • 最后在SVN服务器上提交

     (master)$> git svn dcommit 
  • 回去工作,并最终恢复你的隐藏文件:

     (master)$> git checkout work (work)$> git stash pop 

使用git-svn创build本地分支是绝对可能的。 只要你只是使用本地分支为自己,而不是尝试使用git合并上游svn分支之间,你应该没问题。

我有一个“主”分支,我用它来跟踪svn服务器。 这是我承诺的唯一分支。 如果我正在做一些工作,我创build了一个主题分支,然后解决它。 当我想提交它时,我执行以下操作:

  1. 把一切都交给主题分支
  2. git svn rebase (解决您的工作和svn之间的任何冲突)
  3. git checkout master
  4. git svn rebase (这使得下一步快速合并,见下面的Aaron的评论)
  5. git合并topic_branch
  6. 解决任何合并冲突(这里不应该有任何)
  7. git svn dcommit

我也有另一种情况,我需要维持一些本地的变化(debugging),永远不应该推到SVN。 为此,我有上面的主分支,但也有一个叫做“工作”的分支,我通常工作。 主题分支分支工作。 当我想在那里工作时,我签出master并使用cherry-pick从我想提交给svn的工作分支中select提交。 这是因为我想避免提交三个本地更改提交。 然后,我从主分支提交并重新设置所有内容。

首先运行git svn dcommit -n以确保你准备提交你准备提交的内容。 与git不同,svn中的重写历史很难!

我觉得在跳过本地更改提交时,必须有一个更好的方法来合并主题分支上的更改,而不是使用cherry-pick,所以如果有人有任何想法,他们将受到欢迎。

简单的解决scheme:合并后删除“工作”分支

简短的回答:你可以使用git,只要你喜欢(见下面的简单工作stream程),包括合并。 只要确保按照' git merge-work '和' git branch -d work '来删除临时工作分支。

背景说明: merge / dcommit的问题在于,每当你分支一个git svn dcommit的时候,该分支的合并历史就会被压扁:git会忘记进入这个分支的所有合并操作:只保留文件内容,但是这个内容(部分地)来自特定的其他分支的事实丢失了。 请参阅: 为什么git svn dcommit会失去本地分支合并提交的历史logging?

(注意:git-svn可以做的并不多:svn根本不理解更强大的git合并,所以在svn仓库里,这个合并信息不能以任何方式表示)。

但这是整个问题。 如果删除了“工作”分支后,它已被合并到“主分支”,那么你的git仓库是100%干净,看起来就像你的svn仓库。

我的工作stream程:当然,我首先将远程svn存储库克隆到本地git存储库(这可能需要一些时间):

 $> git svn clone <svn-repository-url> <local-directory> 

所有的工作都发生在“本地目录”中。 每当我需要从服务器获取更新(如'svn update')时,我会这样做:

 $> git checkout master $> git svn rebase 

我在一个单独的分支“工作”中完成所有的开发工作,

 $> git checkout -b work 

当然,你可以根据自己的喜好为自己的工作创build尽可能多的分支,然后根据自己的喜好进行合并和重新分配(只要在完成之后删除它们,如下所述)。 在我的正常工作中,我经常提到:

 $> 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”来提交所有那些你想用前一个提交进行压缩的提交。 当然,第一行应该保持“select”。 通过这种方式,你可以将许多小的提交压缩成一个或多个有意义的单元。 保存并退出编辑器。 你会得到另一个编辑器,要求你重写提交日志消息。

简而言之:在完成“代码黑客行为”之后,我按摩了我的“工作”分支,直到看起来我想将其展示给其他程序员(或者我在几周内浏览历史时想要看到这些工作) 。

为了推动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:确保合并和dcommit 之间用'git branch -d work'删除你的分支:如果你试图在dcommit之后删除分支,你会得到一个错误信息:当你做'git svn dcommit'时,git会忘记你的分支已经与“主”合并。 你必须用'git branch -D work'删除它,这不会做安全检查。

现在,我立即创build一个新的“工作”分支,以避免意外地攻击“主”分支:

 $> 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 

更强大的解决scheme存在:提供的工作stream程是简单的:它只使用git的权力,在每一轮“更新/黑客/ dcommit”—但离开长期的项目历史就像svn存储库一样线性。 这是好的,如果你只是想开始在一个旧的svn项目中的第一小步开始使用git合并。

当你对git合并更熟悉的时候,随时去探索其他的工作stream程:如果你知道你在做什么,你可以把 git merges和svn merges混合在一起( 使用git-svn(或者类似的)来帮助svn merge? )

格雷格Hewgill回答顶部是不安全的! 如果两个“git svn rebase”之间的主干上出现任何新的提交,合并将不会快进。

可以通过在git-merge中使用“–ff-only”标志来保证,但是我通常不在分支中运行“git svn rebase”,只有“git rebase master”(假设它只是一个本地科)。 然后,“git合并分支”保证快进。

在git中合并svn分支的一种安全方法是使用git merge –squash。 这将创build一个单一的提交,并停止为您添加一条消息。

假设你有一个名为svn分支的主题,叫做svn-branch。

 git svn fetch git checkout remotes/trunk -b big-merge git merge --squash svn-branch 

在这一点上,你已经把svn-branch的所有更改压缩成一个等待索引的提交

 git commit 

将本地git分支重新绑定到主git分支上,然后dcommit,这样看起来就像所有提交的顺序一样,svn的人可以按照习惯线性地看到它。 所以假设你有一个叫做主题的本地分支,你可以这样做

 git rebase master topic 

然后在主分支上玩你的提交,准备好提交给dcommit