合并 git 后 git-svn dcommit 是否危险?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/190431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is git-svn dcommit after merging in git dangerous?
提问by Knut Eldhuset
My motivation for trying out git-svn is the effortless merging and branching. Then I noticed that man git-svn(1) says:
我尝试 git-svn 的动机是轻松的合并和分支。然后我注意到 man git-svn(1) 说:
Running git-merge or git-pull is NOT recommended on a branch you plan to dcommit from. Subversion does not represent merges in any reasonable or useful fashion; so users using Subversion cannot see any merges you've made. Furthermore, if you merge or pull from a git branch that is a mirror of an SVN branch, dcommit may commit to the wrong branch.
不建议在您计划从中进行 dcommit 的分支上运行 git-merge 或 git-pull 。Subversion 不代表以任何合理或有用的方式进行合并;所以使用 Subversion 的用户看不到您所做的任何合并。此外,如果您从作为 SVN 分支镜像的 git 分支合并或拉取,dcommit 可能会提交到错误的分支。
Does this mean I cannot create a local branch from svn/trunk (or a branch), hack away, merge back into svn/trunk, then dcommit? I understand that svn users will see the same mess that merges in svn pre 1.5.x have always been, but are there any other drawbacks? That last sentence worries me, too. Do people routinely do these kinds of things?
这是否意味着我不能从 svn/trunk(或一个分支)创建一个本地分支,破解,合并回 svn/trunk,然后 dcommit?我知道 svn 用户会看到在 svn pre 1.5.x 中合并的混乱情况一直是这样,但是还有其他缺点吗?最后一句话也让我很担心。人们经常做这些事情吗?
回答by Sebastien Varrette
Actually, I found an even better way with the --no-ff
option on git merge.
All this squash technic I used before is no longer required.
实际上,我--no-ff
通过 git merge 选项找到了更好的方法。我以前使用的所有这些壁球技术都不再需要了。
My new workflow is now as follows:
我的新工作流程现在如下:
I have a "master" branch that is the only branch that I dcommit from and that clone the SVN repository (
-s
assume you have a standard SVN layout in the repositorytrunk/
,branches/
, andtags/
):git svn clone [-s] <svn-url>
I work on a local branch "work" (
-b
creates the branch "work")git checkout -b work
commit locally into the "work" branch (
-s
to sign-off your commit message). In the sequel, I assume you made 3 local commits... (work)$> git commit -s -m "msg 1" ... (work)$> git commit -s -m "msg 2" ... (work)$> git commit -s -m "msg 3"
我有一个“主”分支,是我从dcommit唯一分支机构和克隆SVN库(
-s
假设你已经在库中的标准SVN布局trunk/
,branches/
和tags/
):git svn clone [-s] <svn-url>
我在本地分支“工作”上工作(
-b
创建分支“工作”)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"
Now you want to commit onto the SVN server
现在你要提交到 SVN 服务器
[Eventually] stash the modifications you don't want to see committed on the SVN server (often you commented some code in the main file just because you want to accelerate the compilation and focus on a given feature)
(work)$> git stash
rebase the master branch with the SVN repository (to update from the SVN server)
(work)$> git checkout master (master)$> git svn rebase
go back to the work branch and rebase with master
(master)$> git checkout work (work)$> git rebase master
Ensure everything is fine using, for instance:
(work)$> git log --graph --oneline --decorate
Now it's time to merge all three commits from the "work" branch into "master" using this wonderful
--no-ff
option(work)$> git checkout master (master)$> git merge --no-ff work
You can notice the status of the logs:
(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
Now you probably want to edit (
amend
) the last commit for your SVN dudes (otherwise they will only see a single commit with the message "Merge branch 'work'"(master)$> git commit --amend
Finally commit on the SVN server
(master)$> git svn dcommit
Go back to work and eventually recover your stashed files:
(master)$> git checkout work (work)$> git stash pop
[最终] 将你不想看到的修改藏在 SVN 服务器上(通常你在主文件中注释了一些代码只是因为你想加速编译并专注于给定的功能)
(work)$> git stash
使用 SVN 存储库重新设置 master 分支(从 SVN 服务器更新)
(work)$> git checkout master (master)$> git svn rebase
返回工作分支并使用 master 进行 rebase
(master)$> git checkout work (work)$> git rebase master
确保一切正常,例如:
(work)$> git log --graph --oneline --decorate
现在是时候使用这个绝妙的
--no-ff
选项将来自“work”分支的所有三个提交合并到“master”(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
回答by Greg Hewgill
Creating local branches is definitely possible with git-svn. As long as you're just using local branches for yourself, and not trying to use git to merge between upstream svn branches, you should be fine.
使用 git-svn 绝对可以创建本地分支。只要您只是为自己使用本地分支,而不是尝试使用 git 在上游 svn 分支之间进行合并,就应该没问题。
I have a "master" branch that I use to track the svn server. This is the only branch that I dcommit from. If I'm doing some work, I create a topic branch and work away on it. When I want to commit it, I do the following:
我有一个用于跟踪 svn 服务器的“主”分支。这是我提交的唯一分支。如果我正在做一些工作,我会创建一个主题分支并进行处理。当我想提交时,我会执行以下操作:
- Commit everything to the topic branch
- git svn rebase (resolve any conflicts between your work and svn)
- git checkout master
- git svn rebase (this makes the next step a fast-forward merge, see Aaron's comments below)
- git merge topic_branch
- resolve any merge conflicts (there shouldn't be any at this point)
- git svn dcommit
- 将所有内容提交到主题分支
- git svn rebase (解决你的工作和 svn 之间的任何冲突)
- git结帐大师
- git svn rebase (这使下一步成为快进合并,请参阅下面的 Aaron 评论)
- git合并topic_branch
- 解决任何合并冲突(此时不应该有任何合并冲突)
- git svn 提交
I also have another situation where I need to maintain some local changes (for debugging) that should never be pushed up to svn. For that, I have the above master branch but also a branch called "work" where I normally do work. Topic branches are branched off work. When I want to commit work there, I checkout master and use cherry-pick to pick the commits from the work branch that I want to commit to svn. This is because I want to avoid committing the three local change commits. Then, I dcommit from the master branch and rebase everything.
我还有另一种情况,我需要维护一些不应被推送到 svn 的本地更改(用于调试)。为此,我有上面的主分支,还有一个名为“工作”的分支,我通常在那里工作。主题分支是从工作分支出来的。当我想在那里提交工作时,我检出 master 并使用cherry-pick 从我想提交到 svn 的工作分支中选择提交。这是因为我想避免提交三个本地更改提交。然后,我从主分支 dcommit 并重新设置所有内容。
It is worthwhile running git svn dcommit -n
first to make sure that you are about to commit exactly what you intend to commit. Unlike git, rewriting history in svn is hard!
首先运行git svn dcommit -n
以确保您将要提交的内容正是您打算提交的内容。与 git 不同,在 svn 中重写历史很难!
I feel that there must be a better way to merge the change on a topic branch while skipping those local change commits than using cherry-pick, so if anybody has any ideas they would be welcome.
我觉得必须有更好的方法来合并主题分支上的更改,同时跳过那些本地更改提交而不是使用cherry-pick,所以如果有人有任何想法,他们将受到欢迎。
回答by Yaakov Belch
Simple solution: Remove 'work' branch after merging
简单的解决方案:合并后删除“工作”分支
Short answer:You can use git however you like (see below for a simple workflow), including merge. Just make sure follow each 'git merge work' with 'git branch -d work' to delete the temporary work branch.
简短回答:您可以随心所欲地使用 git(请参阅下面的简单工作流程),包括合并。只需确保按照每个“ git merge work”和“ git branch -d work”删除临时工作分支。
Background explanation:The merge/dcommit problem is that whenever you 'git svn dcommit' a branch, the merge history of that branch is 'flattened': git forgets about all merge operations that went into this branch: Just the file contents is preserved, but the fact that this content (partially) came from a specific other branch is lost. See: Why does git svn dcommit lose the history of merge commits for local branches?
背景解释:merge/dcommit 的问题是,每当你 'git svn dcommit' 一个分支时,该分支的合并历史是“扁平化的”:git 忘记了进入这个分支的所有合并操作:只保留文件内容,但是该内容(部分)来自特定的其他分支的事实丢失了。请参阅:为什么 git svn dcommit 会丢失本地分支的合并提交历史记录?
(Note: There is not much that git-svn could do about it: svn simply doesn't understand the much more powerful git merges. So, inside the svn repository this merge information cannot be represented in any way.)
(注意:git-svn 对此无能为力:svn 根本不了解更强大的 git 合并。因此,在 svn 存储库中,无法以任何方式表示此合并信息。)
But this is the wholeproblem. If you delete the 'work' branch after it has been merged into the 'master branch' then your git repository is 100% clean and looks exactly like your svn repository.
但这是整个问题。如果在合并到“主分支”后删除“工作”分支,那么您的 git 存储库是 100% 干净的,并且看起来与您的 svn 存储库完全一样。
My workflow:Of course, I first cloned the remote svn repository into a local git repository (this may take some time):
我的工作流程:当然,我首先将远程 svn 存储库克隆到本地 git 存储库中(这可能需要一些时间):
$> git svn clone <svn-repository-url> <local-directory>
All work then happens inside the "local-directory". Whenever I need to get updates from the server (like 'svn update'), I do:
然后所有工作都发生在“本地目录”中。每当我需要从服务器获取更新(如“svn update”)时,我都会:
$> git checkout master
$> git svn rebase
I do all my development work in a separate branch 'work' that is created like this:
我在一个单独的分支“工作”中完成我所有的开发工作,它是这样创建的:
$> git checkout -b work
Of course, you can create as many branches for your work as you like and merge and rebase between them as you like (just delete them when you are done with them --- as discussed below). In my normal work, I commit very frequently:
当然,您可以根据需要为您的工作创建任意数量的分支,并根据需要在它们之间进行合并和变基(只需在完成它们后删除它们——如下所述)。在我的日常工作中,我非常频繁地提交:
$> git commit -am '-- finished a little piece of work'
The next step (git rebase -i) is optional --- it's just cleaning up the history before archiving it on svn: Once I reached a stable mile stone that I want to share with others, I rewrite the history of this 'work' branch and clean up the commit messages (other developers don't need to see all the little steps and mistakes that I made on the way --- just the result). For this, I do
下一步 (git rebase -i) 是可选的 --- 它只是在将历史存档到 svn 之前清理历史记录:一旦我达到了想要与他人分享的稳定里程碑,我就重写了这项“工作”的历史记录分支并清理提交消息(其他开发人员不需要看到我在此过程中所做的所有小步骤和错误 --- 只是结果)。为此,我做
$> git log
and copy the sha-1 hash of the last commit that is live in the svn repository (as indicated by a git-svn-id). Then I call
并复制 svn 存储库中最后一次提交的 sha-1 哈希值(如 git-svn-id 所示)。然后我打电话
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
Just paste sha-1 hash of our last svn commit instead of mine. You may want to read the documentation with 'git help rebase' for the details. In short: this command first opens an editor presenting your commits ---- just change 'pick' to 'squash' for all those commits that you want to squash with previous commits. Of course, the first line should stay as a 'pick'. In this way, you can condense your many little commits into one or more meaningful units. Save and exit the editor. You will get another editor asking you to rewrite the commit log messages.
只需粘贴我们最后一次 svn 提交的 sha-1 哈希值,而不是我的。您可能需要阅读带有“git help rebase”的文档以了解详细信息。简而言之:此命令首先打开一个编辑器,显示您的提交 ---- 只需将“pick”更改为“squash”,以将所有您想与先前提交压缩的提交。当然,第一行应该保留为“选择”。通过这种方式,您可以将许多小的提交压缩为一个或多个有意义的单元。保存并退出编辑器。你会得到另一个编辑器要求你重写提交日志消息。
In short: After I finish 'code hacking', I massage my 'work' branch until it looks how I want to present it to the other programmers (or how I want to see the work in a few weeks time when I browse history).
简而言之:在我完成“代码黑客”之后,我会按摩我的“工作”分支,直到它看起来像我想向其他程序员展示它的样子(或者我想在几周内浏览历史时看到的工作) .
In order to push the changes to the svn repository, I do:
为了将更改推送到 svn 存储库,我执行以下操作:
$> git checkout master
$> git svn rebase
Now we are back at the old 'master' branch updated with all changes that happened in the mean time in the svn repository (your new changes are hidden in the 'work' branch).
现在我们回到旧的“master”分支,更新了 svn 存储库中同时发生的所有更改(您的新更改隐藏在“work”分支中)。
If there are changes that may clash with your new 'work' changes, you have to resolve them locally before you may push your new work (see details further below). Then, we can push our changes to 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
Note 1: The command 'git branch -d work' is quite safe: It only allows you to delete branches that you don't need anymore (because they are already merged into your current branch). If you execute this command by mistake before merging your work with the 'master' branch, you get an error message.
注意 1:命令 'git branch -d work' 非常安全:它只允许您删除不再需要的分支(因为它们已经合并到您当前的分支中)。如果在将工作与“master”分支合并之前错误地执行了此命令,则会收到错误消息。
Note 2: Make sure to delete your branch with 'git branch -d work' betweenmerging and dcommit: If you try to delete the branch after dcommit, you get an error message: When you do 'git svn dcommit', git forgets that your branch has been merged with 'master'. You have to remove it with 'git branch -D work' which doesn't do the safety check.
注意 2:确保在合并和 dcommit之间使用 'git branch -d work' 删除您的分支:如果您尝试在 dcommit 之后删除分支,您会收到一条错误消息:当您执行 'git svn dcommit' 时,git 忘记了您的分支已与“master”合并。您必须使用不进行安全检查的“git branch -D work”将其删除。
Now, I immediately create a new 'work' branch to avoid accidentally hacking on the 'master' branch:
现在,我立即创建了一个新的“工作”分支,以避免意外入侵“主”分支:
$> git checkout -b work
$> git branch # show my branches:
master
* work
Integrating your 'work' with changes on svn:Here is what I do when 'git svn rebase' reveals that others changed the svn repository while I was working on my 'work' branch:
将您的“工作”与 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
More powerful solutions exist:The presented workflow is simplistic: It uses the powers of git only within each round of 'update/hack/dcommit' --- but leaves the long-term project history just as linear as the svn repository. This is ok if you just want to start using git merges in small first steps in a legacy svn project.
存在更强大的解决方案:所呈现的工作流程很简单:它仅在每一轮“更新/黑客/dcommit”中使用 git 的功能——但使长期项目历史与 svn 存储库一样线性。如果您只是想在遗留 svn 项目中的小的第一步中开始使用 git merges,这是可以的。
When you become more familiar with git merging, feel free to explore other workflows: If you know what you are doing, you canmix git merges with svn merges (Using git-svn (or similar) just to help out with svn merge?)
当您对 git merging 更加熟悉时,可以随意探索其他工作流程:如果您知道自己在做什么,则可以将 git merges 与 svn merges 混合使用(使用 git-svn(或类似的)只是为了帮助 svn merge?)
回答by Marius K
Greg Hewgill answer on top is not safe! If any new commits appeared on trunk between the two "git svn rebase", the merge will not be fast forward.
Greg Hewgill 上面的回答是不安全的!如果任何新提交出现在两个“git svn rebase”之间的主干上,合并将不会快进。
It can be ensured by using "--ff-only" flag to the git-merge, but I usually do not run "git svn rebase" in the branch, only "git rebase master" on it (assuming it is only a local branch). Then afterwards a "git merge thebranch" is guaranteed to be fast forward.
可以通过在 git-merge 中使用“--ff-only”标志来确保它,但我通常不在分支中运行“git svn rebase”,只在其上运行“git rebase master”(假设它只是一个本地分支)。然后,“git merge thebranch”保证快进。
回答by luntain
A safe way to merge svn branches in git is to use git merge --squash. This will create a single commit and stop for you to add a message.
在 git 中合并 svn 分支的一种安全方法是使用 git merge --squash。这将创建一个提交并停止让您添加消息。
Let's say you have a topic svn branch, called svn-branch.
假设您有一个主题 svn 分支,称为 svn-branch。
git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch
at this point you have all the changes from the svn-branch squashed into one commit waiting in the index
在这一点上,您将 svn-branch 中的所有更改压缩到一个在索引中等待的提交中
git commit
回答by JoeyJ
Rebase the local git branch onto the master git branch then dcommit and that way it looks like you did all those commits in sequence so svn people can see it linearly as they are accustomed to. So assuming you have a local branch called topic you could do
将本地 git 分支重新绑定到主 git 分支上,然后 dcommit,这样看起来你按顺序完成了所有这些提交,这样 svn 人就可以像他们习惯的那样线性地看到它。因此,假设您有一个名为 topic 的本地分支,您可以这样做
git rebase master topic
which will then play your commits over the master branch ready for you to dcommit
然后它将在主分支上播放您的提交,准备好让您进行 dcommit