git-svn在git中合并后会发生dcommit吗?

Knu*_*set 133 svn git merge branch git-svn

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

不建议在您计划提交的分支上运行git-merge或git-pull.Subversion不以任何合理或有用的方式表示合并; 因此使用Subversion的用户无法看到您所做的任何合并.此外,如果您从作为SVN分支镜像的git分支合并或拉出,则dcommit可能会提交到错误的分支.

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

Seb*_*tte 174

实际上,我--no-ff在git merge上找到了一个更好的方法.我以前用过的所有这种壁球技术都不再需要了.

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

  • 我有一个"主"分支,是我从dcommit唯一分支机构和克隆SVN库(-s假设你已经在库中的标准SVN布局trunk/,branches/tags/):

    git svn clone [-s] <svn-url>
    
    Run Code Online (Sandbox Code Playgroud)
  • 我在当地分公司工作"工作"(-b创建分支"工作")

    git checkout -b work
    
    Run Code Online (Sandbox Code Playgroud)
  • 在本地提交到"工作"分支(-s以签署您的提交消息).在续集中,我假设你做了3次本地提交

    ...
    (work)$> git commit -s -m "msg 1"
    ...
    (work)$> git commit -s -m "msg 2"
    ...
    (work)$> git commit -s -m "msg 3"
    
    Run Code Online (Sandbox Code Playgroud)

现在您想要提交到SVN服务器

  • 这不正是操作中引用的git-svn文档的警告吗?通过使用`--no-ff`选项运行merge,您将显式创建合并提交(具有两个父项的提交)而不是快进.为了确保svn-tracking分支中的所有提交都是单父提交,所有合并必须是快进的(`--ff-only`可以帮助这个),或者如果trunk在你背后改变了,` - -squash`,对吗? (19认同)
  • 使用`git merge --no-ff work -m"提交消息"`而不是额外的`git commit --amend`步骤 (9认同)
  • 这完全是git n00b正在寻找的工作流程.创建一个本地分支来修复错误,做任何事情,然后通过SINGLE提交将其发送到svn.使用评分最高的答案搞砸了我正在做的事情 - 不能没有错误地git svn rebase. (4认同)
  • 这适用于您立即删除的一次性分支,但`git svn dcommit`会重写您提供的git提交.这意味着你失去了另一个父级,现在你的git repo没有你曾经把那个分支合并成`master`的记录.这也可能使您的工作目录处于不一致状态. (4认同)
  • 对我来说,我更喜欢使用"git merge --ff-only work",因为我想保留所有提交而不仅仅是最后一个提交 (3认同)

Gre*_*ill 49

使用git-svn绝对可以创建本地分支.只要您自己只使用本地分支,而不是尝试使用git在上游svn分支之间进行合并,您应该没问题.

我有一个"主"分支,用于跟踪svn服务器.这是我唯一提出的分支.如果我正在做一些工作,我会创建一个主题分支并继续努力.当我想提交它时,我会执行以下操作:

  1. 将所有内容提交到主题分支
  2. git svn rebase (解决你的工作和svn之间的任何冲突)
  3. git checkout master
  4. git svn rebase (这使得下一步成为快进合并,请参阅下面的Aaron的评论)
  5. git merge topic_branch
  6. 解决任何合并冲突(此时不应该有任何合并冲突)
  7. git svn dcommit

我还有另一种情况,我需要保持一些本地更改(用于调试),永远不应该推送到svn.为此,我有上面的主分支,但也有一个叫做"工作"的分支,我通常在那里工作.主题分支是分支工作.当我想在那里提交工作时,我会检查master并使用cherry-pick来从我想要提交给svn的工作分支中选择提交.这是因为我想避免提交三个本地更改提交.然后,我从主分支中提交并重新设定所有内容.

首先运行是值得的git svn dcommit -n,以确保您准备提交您打算提交的内容.与git不同,在svn中重写历史很难!

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

  • Greg Hewgill的回答有很多选票,但我认为这是错误的.从topic_branch到master的合并只有在快速合并时才是安全的.如果它是需要合并提交的真正合并,那么当您提交时,合并提交将丢失.下次你尝试将topic_branch合并到master中时,git认为第一次合并从未发生过,并且所有的地狱都破裂了.请参阅问题[为什么git svn dcommit会丢失本地分支机构的合并提交历史记录?](http://stackoverflow.com/questions/425766/why-does-git-svn-dcommit-lose-the-history-of -merge-承诺为当地支行) (19认同)

Yaa*_*lch 33

简单的解决方案:合并后删除"工作"分支

简短回答:您可以随意使用git(请参阅下面的简单工作流程),包括合并.只需确保使用' git branch -d work ' 跟随每个' git merge work '即可删除临时工作分支.

背景说明: merge/dcommit问题是,每当你'stn'scomn'一个分支时,该分支的合并历史记录是'flattened':git忘记了进入这个分支的所有合并操作:只保留文件内容,但是这个内容(部分)来自特定的其他分支的事实已经丢失.请参阅:为什么git svn dcommit会丢失本地分支的合并提交历史记录?

(注意:git-svn可以做的事情并不多:svn根本不理解更强大的git合并.因此,在svn存储库中,这个合并信息无法以任何方式表示.)

但这是整个问题.如果在将"work"分支合并到"master branch"后删除它,那么你的git存储库是100%干净的,看起来就像你的svn存储库.

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

$> git svn clone <svn-repository-url> <local-directory>
Run Code Online (Sandbox Code Playgroud)

然后所有工作都在"本地目录"中进行.每当我需要从服务器获取更新时(比如'svn update'),我会:

$> git checkout master
$> git svn rebase
Run Code Online (Sandbox Code Playgroud)

我在一个单独的分支"工作"中完成所有开发工作,这个工作是这样创建的:

$> git checkout -b work
Run Code Online (Sandbox Code Playgroud)

当然,您可以根据需要为您的工作创建尽可能多的分支,并根据需要在它们之间进行合并和重新组合(只需在完成它们时将其删除 - 如下所述).在我的正常工作中,我经常犯下:

$> git commit -am '-- finished a little piece of work'
Run Code Online (Sandbox Code Playgroud)

下一步(git rebase -i)是可选的 - 它只是清理历史记录,然后在svn上存档:一旦我达到了一个稳定的里程碑,我想与他人分享,我重写了这个'工作'的历史分支并清理提交消息(其他开发人员不需要查看我在路上所做的所有小步骤和错误 - 只是结果).对此,我这样做

$> git log
Run Code Online (Sandbox Code Playgroud)

并复制svn存储库中存在的最后一次提交的sha-1哈希(如git-svn-id所示).然后我打电话

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
Run Code Online (Sandbox Code Playgroud)

只需粘贴我们上一次svn提交的sha-1哈希而不是我的.您可能需要阅读带有'git help rebase'的文档以获取详细信息.简而言之:这个命令首先打开一个编辑器,显示你的提交----只需将'pick'改为'squash',用于所有那些你希望用之前的提交压缩的提交.当然,第一行应该保留为"选择".通过这种方式,您可以将许多小提交压缩为一个或多个有意义的单元.保存并退出编辑器.您将获得另一个编辑器,要求您重写提交日志消息.

简而言之:在我完成'代码黑客攻击'后,我按下我的"工作"分支,直到看起来我想将它呈现给其他程序员(或者我想在几周内浏览历史记录时看到工作) .

为了将更改推送到svn存储库,我这样做:

$> git checkout master
$> git svn rebase
Run Code Online (Sandbox Code Playgroud)

现在我们回到旧的"主"分支,更新了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
Run Code Online (Sandbox Code Playgroud)

注1:命令'git branch -d work'非常安全:它只允许你删除不再需要的分支(因为它们已经合并到你当前的分支中).如果在将工作与"master"分支合并之前错误地执行了此命令,则会收到错误消息.

注意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
Run Code Online (Sandbox Code Playgroud)

将您的"工作"与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
Run Code Online (Sandbox Code Playgroud)

存在更强大的解决方案: 所呈现的工作流程过于简单:它仅在每一轮'update/hack/dcommit'中使用git的强大功能 ---但是将长期项目历史保留为与svn存储库一样线性.如果你只是想在遗留svn项目的小开头步骤中开始使用git merge,这是可以的.

当你更熟悉git merge时,随意探索其他工作流程:如果你知道你在做什么,你可以将git merges与svn merges混合使用(使用git-svn(或类似)只是为了帮助svn merge?)


Mar*_*s K 8

Greg Hewgill回答顶部并不安全!如果在两个"git svn rebase"之间的主干上出现任何新提交,则合并将不会快进.

通过在git-merge中使用"--ff-only"标志可以确保它,但我通常不在分支中运行"git svn rebase",只在它上面运行"git rebase master"(假设它只是一个本地科).然后一个"git merge thebranch"保证快进.


lun*_*ain 6

在git中合并svn分支的一种安全方法是使用git merge --squash.这将创建一个提交并停止添加消息.

假设您有一个主题svn分支,称为svn-branch.

git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch
Run Code Online (Sandbox Code Playgroud)

此时,您将svn-branch中的所有更改压缩到索引中等待的一个提交中

git commit
Run Code Online (Sandbox Code Playgroud)


小智 5

将本地git分支重新引导到主git分支然后dcommit,这样看起来你按顺序完成了所有这些提交,所以svn人们可以按照习惯线性地看到它.因此,假设您有一个名为topic的本地分支,您可以这样做

git rebase master topic
Run Code Online (Sandbox Code Playgroud)

然后,它将在主分支上播放您的提交,准备让您同意