Git SVN 工作流 - 特性分支和合并

27

我现在正在使用以下工作流程的git-svn:

git clone <SVN TRUNK URL> #done once

随后当我在开发一个功能时

git branch featureZ
git checkout featureZ
#make edits for featureZ
git commit

git checkout master
git svn rebase # fetch changes from server

git checkout featureZ #go back to branch
#git merge master 
git rebase master #get the changes from SVN->master onto the branch now. Optional if I want the branch to be current. (EDITED: Got from the answer given below)

#make edits for featureZ
git commit #featureZ completed

git checkout master
git merge featureZ #getting featureZ onto master. Prepare to send to SVN

git svn dcommit #push featureZ back to SVN

现在需要注意的是,当我将feature分支与master合并时,所有单独的提交都会被合并为一个,这对我来说很好。

提交信息会替换为“merged with featureZ”。可以使用merge fmt msg进行修复。

现在我的问题是:在这个工作流程中有什么可能出错或需要注意的地方吗?我在git-svn手册中读到,当使用git svn时不应该进行合并。我正在做的工作流程是他们所指的吗?如果是,会导致什么问题?其中一件事是我不想做任何影响SVN主干的事情。


5
顺便说一下,你可以使用 git checkout -b 命令来代替 git branch ..; git checkout。此外,使用 co 作为 checkout 命令的别名也是很常见的。 - jfs
4个回答

27

SVN无法处理非线性历史记录(它根本没有相应的符号)。因此,你需要执行重新定位而不是合并,因为它可以在 SVN 中保留线性历史记录(在 git-svn 手册这里中有说明)。

更具体地说,线性历史很容易处理。它们是以一条直线向前发展的(从 A 到 B 到 C 到 D)。然而,非线性历史可能会从 A 到 B 到 C,再从 B 到 D,接着从 C + D 到 E——换句话说,它们会分支开来。

重新定位将使你获得线性历史记录。请记住,重新定位应该只在你自己的本地分支上进行。例如,如果你有两个分支:master 和 experimental。你应该切换到 experimental 并执行 'git rebase master' 命令(最好加上 -i 标志)。反过来做可能会导致不良后果。

之后,你就可以切换到 master 分支,在其中合并来自 experimental 分支的更改。你的历史记录应该保持线性。


你能解释一下什么是非线性历史吗?另外,我不想让 SVN 知道我有本地分支并将其合并。你建议在我的工作流程中重新设置基础线吗?git rebase featureZ? - Pradeep
我详细阐述了我的答案。希望能有所帮助。 :) - Fake Code Monkey Rashid
谢谢解释。虽然我目前只创建线性历史记录(对分支本身还不熟悉),但我已经理解了非线性历史记录是什么。因此,为了准备好非线性历史记录,我开始使用从特性分支到主分支的git rebase master来拉取主分支上的更改到特性分支。这很好用。它将主分支上的更改拉到我的分支上,并在其上重放了我的提交。所以唯一的变化就是从分支中使用“git merge master”改为使用“git rebase master”。那么从主分支进行的最终“git merge featureZ”就可以了吗? - Pradeep
是的,基本上就是这样。因此,为了重新概括,您想从featureZ分支执行“git rebase master”而不是“git merge master”,然后从主分支执行“git merge featureZ”。当然,请记得使用“git log --graph --decorate --abbrev-commit”、gitk或gitview验证您的历史记录,以确保您实现了所需的结果。 - Fake Code Monkey Rashid
谢谢Rashid。我理解了在这个工作流程中使用rebase命令的方法。现在我能够按照rebase手册进行操作,因为它与此相关。(请注意,我只在featureZ分支的线性历史记录上测试过,但根据手册,rebase也可以移植非线性历史记录。) - Pradeep

4
你应该看一下这个合并选项:
git checkout master
git merge --squash featureZ

它将分支上的所有提交压缩成主分支上的单个提交。您将有机会编辑日志消息,该消息初始化为对分支上所做工作的摘要。
它的缺点是无法记录特性分支上的个别提交。此外,您应该只执行一次此操作,并且不要在分支上进行任何更多的工作,因为它不被注册为正确的合并,任何后续合并可能会产生不良结果。

压缩会破坏分支历史记录,因此我不能推荐使用它们。如果我可以给你点踩的话,我会这么做(而且我会这么做)。 - Fake Code Monkey Rashid
1
如果我不希望捕获本地特性分支历史记录,那么压缩提交就是有意义的。如果需要的话,我可以在主干上向 SVN 发送一个单独的大提交,这将隐藏所有我所做的分支操作。很好,git 不会阻止这种做法。感谢 Ropez。 - Pradeep
是的,它可以被认为有其用途,但我认为历史是珍贵的。我会尽可能使用最不具侵入性的方法轻微地重写它,而Squash则是非常具侵入性的。它会销毁你所做的所有更改以及你做出这些更改的顺序。它隐藏了所有的错误和帮助你修复它们的闪光点。它抹去了人的痕迹,并给你一个极其不个性化的结果(例如:那个单一的肥胖提交)。但这只是我的最新观点,你并不是我。所以我同意git灵活的观点。 :) - Fake Code Monkey Rashid
Sizzler说:“featureZ分支中的所有单个提交将合并为一个,这对我来说很好。” 总结提交可能在一般情况下不是明智的选择,但如果特性分支中的单个提交并不重要,则可以使用该选项,这正是上述情况的解决方案。这肯定是与此问题相关的一个选项。 - Ropez
1
编辑以包含有关丢失单个提交的警告。 - Ropez
1
作为补充说明,您实际上并没有“失去”那个历史记录 - 它仍然存在于您的git存储库中。如果您需要共享该历史记录,我相信您可以使用git-svn分支将这些提交应用到该分支中,然后再使用git-svn将其合并回来。 - deterb

2

fake-code-monkey-rashid所给出的答案是正确的。这不仅仅是一个答案,还是一个简化。

你可以从任何git分支svn rebase/dcommit。只有当你有其他本地更改需要与featureZ的更改合并时,才会使用master

git branch featureZ
git checkout featureZ
#bunch of changes
git commit
git svn rebase
# solve any conflicts
git svn dcommit

如果您想要保持一个干净的主分支,您可以使用 git svn rebase 或者 git merge featuresZ

0

除了使用git-svn,您还可以使用SubGit。它是一种服务器端工具,可自动同步Subversion和Git存储库。

您可以使用任何可用的Git工作流程和任何Git客户端,无需额外的客户端工具。

考虑到您的情况:

git branch featureZ
git checkout featureZ
# make edits for featureZ
git commit
git checkout master

您可以按照以下步骤进行:
  1. 全部推送功能分支。

    git merge featureZ
    git push origin refs/heads/*
    
  2. 将一个功能分支rebase到主分支上。

    git rebase featureZ
    git push
    
  3. 将一个功能分支的提交压缩。

    git merge --squash featureZ
    git commit
    git push
    

一旦您推送更改,SubGit钩子将把您的更改转换为Subversion修订。

更多细节:

  • 在许多方面,SubGit比git-svn更优越 - 更好的合并跟踪翻译,EOL和mime-type支持等。
  • SubGit需要本地访问Subversion存储库(它使用自定义钩子);
  • SubGit是一款商业产品,具有一些免费选项(开源和学术项目,小团队)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接