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服务器上看到的修改(通常您只是因为想要加速编译并专注于给定功能而在主文件中注释了一些代码)
(work)$> git stash
Run Code Online (Sandbox Code Playgroud)使用SVN存储库重新绑定主分支(从SVN服务器更新)
(work)$> git checkout master
(master)$> git svn rebase
Run Code Online (Sandbox Code Playgroud)回到工作分支并与主人一起改变
(master)$> git checkout work
(work)$> git rebase master
Run Code Online (Sandbox Code Playgroud)确保一切正常,例如:
(work)$> git log --graph --oneline --decorate
Run Code Online (Sandbox Code Playgroud)现在是时候将"work"分支中的所有三个提交合并到"master"中,使用这个精彩的--no-ff
选项
(work)$> git checkout master
(master)$> git merge --no-ff work
Run Code Online (Sandbox Code Playgroud)您可以注意到日志的状态:
(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
Run Code Online (Sandbox Code Playgroud)现在你可能想编辑(amend
)你的SVN家伙的最后一次提交(否则他们只会看到一个提交消息"合并分支'工作'"
(master)$> git commit --amend
Run Code Online (Sandbox Code Playgroud)最后在SVN服务器上提交
(master)$> git svn dcommit
Run Code Online (Sandbox Code Playgroud)回去工作,最终恢复你的藏匿文件:
(master)$> git checkout work
(work)$> git stash pop
Run Code Online (Sandbox Code Playgroud)Gre*_*ill 49
使用git-svn绝对可以创建本地分支.只要您自己只使用本地分支,而不是尝试使用git在上游svn分支之间进行合并,您应该没问题.
我有一个"主"分支,用于跟踪svn服务器.这是我唯一提出的分支.如果我正在做一些工作,我会创建一个主题分支并继续努力.当我想提交它时,我会执行以下操作:
我还有另一种情况,我需要保持一些本地更改(用于调试),永远不应该推送到svn.为此,我有上面的主分支,但也有一个叫做"工作"的分支,我通常在那里工作.主题分支是分支工作.当我想在那里提交工作时,我会检查master并使用cherry-pick来从我想要提交给svn的工作分支中选择提交.这是因为我想避免提交三个本地更改提交.然后,我从主分支中提交并重新设定所有内容.
首先运行是值得的git svn dcommit -n
,以确保您准备提交您打算提交的内容.与git不同,在svn中重写历史很难!
我觉得必须有一个更好的方法来合并主题分支上的更改,同时跳过那些本地更改提交而不是使用cherry-pick,所以如果有人有任何想法,他们将受到欢迎.
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?)
Greg Hewgill回答顶部并不安全!如果在两个"git svn rebase"之间的主干上出现任何新提交,则合并将不会快进.
通过在git-merge中使用"--ff-only"标志可以确保它,但我通常不在分支中运行"git svn rebase",只在它上面运行"git rebase master"(假设它只是一个本地科).然后一个"git merge thebranch"保证快进.
在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)
然后,它将在主分支上播放您的提交,准备让您同意