合并到git后git-svn dcommit危险吗?
我尝试 git-svn 的动机是轻松的合并和分支。 然后我注意到 man git-svn(1) 说:
不建议在您计划的分支上运行 git-merge 或 git-pull d 提交自。 Subversion 不代表任何合并 合理或有用的时尚; 因此使用 Subversion 的用户看不到任何 您所做的合并。 此外,如果你从 git 合并或拉取 分支是 SVN 分支的镜像,dcommit 可以提交到 错误的分支。
这是否意味着我无法从 svn/trunk (或分支)创建本地分支,破解,合并回 svn/trunk,然后 dcommit? 我知道 svn 用户会看到 svn pre 1.5.x 中合并的混乱情况,但是还有其他缺点吗? 最后一句话也让我担心。 人们经常做这些事情吗?
My motivation for trying out git-svn is the effortless merging and branching. Then I noticed that man git-svn(1) says:
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.
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
实际上,我在 git merge 上使用
--no-ff
选项找到了更好的方法。我以前使用的所有这些挤压技术都不再需要了。
我的新工作流程现在如下:
我有一个“主”分支,这是我提交的唯一分支,它克隆 SVN 存储库(
-s
假设您有标准 SVN 布局在存储库trunk/
、branches/
和tags/
中):我在本地分支“work”上工作(
-b
创建分支“work”)本地提交到“work”分支(
- s
签署您的提交消息)。 在接下来的内容中,我假设您进行了 3 次本地提交<前><代码>...
(工作)$> git commit -s -m“消息1”
...
(工作)$> git commit -s -m“消息2”
...
(工作)$> git commit -s -m “消息 3”
现在您想要提交到 SVN 服务器
[最终] 存储您不希望看到在 SVN 服务器上提交的修改(通常您在主文件中注释了一些代码)文件只是因为您想加速编译并专注于给定的功能)
<前><代码>(工作)$> git 存储
使用 SVN 存储库对 master 分支进行变基(以从 SVN 服务器更新)
<前><代码>(工作)$> git 结账大师
(大师)$> git svn 变基
返回工作分支并使用 master 进行 rebase
<前><代码>(主)$> git 结账工作
(工作)$> git 变基大师
确保一切正常,例如:
<前><代码>(工作)$> git log --graph --oneline --decorate
现在是时候使用这个美妙的
--no-ff< 将“work”分支的所有三个提交合并到“master”中/code> 选项
<前><代码>(工作)$> git 结账大师
(大师)$> git merge --no-ff 工作
您可以注意到状态日志:
<前><代码>(主)$> git log --graph --oneline --decorate
* 56a779b(工作,主控)合并分支“工作”
|\
| * af6f7ae 消息 3
| * 8750643 消息 2
| * 08464ae 消息 1
|/
* 21e20fa (git-svn) 最后一次 svn 提交
现在您可能想要编辑(
修改
)您的 SVN 人员的最后一次提交(否则他们只会看到带有消息“合并分支'工作'”的单次提交<前><代码>(主)$> git commit --修改
最终在SVN服务器上提交
<前><代码>(主)$> git svn dcommit
返回工作并最终恢复您隐藏的文件:
<前><代码>(主)$> git 结账工作
(工作)$> git stash 流行
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.
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/
):I work on a local branch "work" (
-b
creates the branch "work")commit locally into the "work" branch (
-s
to sign-off your commit message). In the sequel, I assume you made 3 local commitsNow you want to commit onto the SVN server
[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)
rebase the master branch with the SVN repository (to update from the SVN server)
go back to the work branch and rebase with master
Ensure everything is fine using, for instance:
Now it's time to merge all three commits from the "work" branch into "master" using this wonderful
--no-ff
optionYou can notice the status of the logs:
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'"Finally commit on the SVN server
Go back to work and eventually recover your stashed files:
使用 git-svn 绝对可以创建本地分支。 只要您只是自己使用本地分支,而不是尝试使用 git 在上游 svn 分支之间进行合并,就应该没问题。
我有一个“master”分支,用来跟踪 svn 服务器。 这是我提交的唯一分支。 如果我正在做一些工作,我会创建一个主题分支并继续努力。 当我想提交时,我会执行以下操作:
我还有另一个我需要维护一些本地更改(用于调试)的情况,这些更改永远不应该推送到 svn。 为此,我有上面的 master 分支,还有一个名为“work”的分支,我通常在其中工作。 主题分支是从工作中分支出来的。 当我想在那里提交工作时,我会签出 master 并使用cherry-pick 从工作分支中选择我想要提交到 svn 的提交。 这是因为我想避免提交三个本地更改提交。 然后,我从主分支提交并重新设置所有内容。
首先运行 git svn dcommit -n 是值得的,以确保您将要准确地提交您想要提交的内容。 与 git 不同,在 svn 中重写历史非常困难!
我觉得一定有一种比使用cherry-pick更好的方法来合并主题分支上的更改,同时跳过那些本地更改提交,所以如果有人有任何想法,他们将受到欢迎。
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.
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:
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.
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!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.
简单的解决方案:合并后删除“工作”分支
简短回答:您可以根据需要使用 git (参见下面的简单工作流程),包括合并。 只需确保在每个“git merge work”后面加上“gitbranch -d work”即可删除临时工作分支。
背景说明:
合并/dcommit 问题是,每当您“git svn dcommit”一个分支时,该分支的合并历史记录就会“扁平化”:git 会忘记进入该分支的所有合并操作:仅保留文件内容,但事实是该内容(部分)来自特定的其他分支已丢失。 请参阅: 为什么git svn dcommit 会丢失本地分支合并提交的历史记录吗?
(注意:git-svn 对此无能为力:svn 根本不理解更强大的 git merges。因此,在svn 存储库此合并信息无法以任何方式表示。)
但这就是整个问题。 如果您在将“工作”分支合并到“主分支”后将其删除,那么您的 git 存储库就是 100% 干净的,并且看起来与您的 svn 存储库完全相同。
我的工作流程:
当然,我首先将远程 svn 存储库克隆到本地 git 存储库(这可能需要一些时间):
然后所有工作都发生在“本地目录”内。 每当我需要从服务器获取更新(例如“svn update”)时,我都会这样做:
我在一个单独的分支“work”中完成所有开发工作,该分支的创建方式如下:
当然,您可以为您的应用程序创建尽可能多的分支按照你喜欢的方式工作,并按照你喜欢的方式在它们之间合并和变基(使用完它们后只需删除它们 --- 如下所述)。 在我的正常工作中,我非常频繁地提交:
下一步(git rebase -i)是可选的——它只是在将历史记录归档到 svn 之前清理历史记录:一旦我达到了一个稳定的里程碑,我想与其他人分享,我重写了这个“工作”分支的历史记录并清理了提交消息(其他开发人员不需要看到我在此过程中犯的所有小步骤和错误——只需要结果)。 为此,我
复制了 svn 存储库中最后一次提交的 sha-1 哈希值(如 git-svn-id 所示)。 然后我调用
Just Paste 我们最后一次 svn 提交的 sha-1 哈希值而不是我的。 您可能需要阅读“git help rebase”文档以了解详细信息。 简而言之:此命令首先打开一个编辑器,显示您的提交 ---- 只需将您想要与以前的提交一起压缩的所有提交的“pick”更改为“squash”即可。 当然,第一行应该保留为“pick”。 通过这种方式,您可以将许多小提交压缩为一个或多个有意义的单元。
保存并退出编辑器。 您将看到另一个编辑器要求您重写提交日志消息。
简而言之:在完成“代码黑客”后,我会调整我的“工作”分支,直到它看起来像我想要向其他程序员展示的那样(或者我想要在几周后浏览历史记录时看到的工作) 。
为了将更改推送到 svn 存储库,我这样做:
现在我们回到了旧的“master”分支,更新了 svn 存储库中同时发生的所有更改(您的新更改隐藏在“work”中)分支)。
如果存在可能与您的新“工作”更改发生冲突的更改,您必须在本地解决它们,然后才能推送新工作(请参阅下面的详细信息)。 然后,我们可以将更改推送到 svn:
注意 1:命令 'gitbranch -d work' 非常安全:它只允许您删除不再需要的分支(因为它们已经合并到您当前的分支中) )。 如果您在将工作与“master”分支合并之前错误地执行了此命令,您会收到一条错误消息。
注意 2:确保在合并和 dcommit 之间使用 'gitbranch -d work' 删除分支:如果您尝试在 dcommit 后删除分支,您会收到一条错误消息:当您执行 'git svn dcommit',git 忘记了你的分支已经与 'master' 合并了。 您必须使用“git Branch -D work”删除它,这不会进行安全检查。
现在,我立即创建一个新的“工作”分支,以避免意外侵入“主”分支:
将您的“工作”与 svn 上的更改集成:
当“git svn rebase”显示其他人在我处理“工作”分支时更改了 svn 存储库时,我会执行以下操作:
存在更强大的解决方案:
所提出的工作流程很简单:它仅在每一轮“更新/黑客/dcommit”中使用 git 的功能——但使长期项目历史记录与 svn 存储库一样线性。 如果您只想在遗留 svn 项目中的小第一步中开始使用 git merges,这是可以的。
当您更加熟悉 git 合并时,请随意探索其他工作流程:如果您知道自己在做什么,您可以将 git 合并与 svn 合并混合使用(使用 git-svn (或类似的)只是为了帮助 svn 合并?)
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.
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?
(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.)
But this is the whole problem. 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.
My workflow:
Of course, I first cloned the remote svn repository into a local git repository (this may take some time):
All work then happens inside the "local-directory". Whenever I need to get updates from the server (like 'svn update'), I do:
I do all my development work in a separate branch 'work' that is created like this:
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:
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
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
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.
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:
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).
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:
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.
Note 2: Make sure to delete your branch with 'git branch -d work' between merging 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.
Now, I immediately create a new 'work' branch to avoid accidentally hacking on the 'master' branch:
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:
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.
When you become more familiar with git merging, feel free to explore other workflows: If you know what you are doing, you can mix git merges with svn merges (Using git-svn (or similar) just to help out with svn merge?)
Greg Hewgill 上面的答案并不安全! 如果两个“git svn rebase”之间的主干上出现任何新的提交,则合并将不会快进。
可以通过在 git-merge 中使用“--ff-only”标志来确保这一点,但我通常不在分支中运行“git svn rebase”,只在其上运行“git rebase master”(假设它只是本地的)分支)。 然后“git merge thebranch”保证快进。
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.
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 中合并 svn 分支的一个安全方法是使用 git merge --squash。 这将创建一个提交并停止供您添加消息。
假设您有一个主题 svn 分支,称为 svn-branch。
此时,您已将 svn 分支中的所有更改压缩为一个提交,并在索引中等待
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.
Let's say you have a topic svn branch, called svn-branch.
at this point you have all the changes from the svn-branch squashed into one commit waiting in the index
将本地 git 分支重新设置到主 git 分支上,然后进行 dcommit,这样看起来就像您按顺序完成了所有这些提交,以便 svn 人们可以按照他们习惯的方式线性地看到它。 因此,假设您有一个名为 topic 的本地分支,您可以这样做
,然后它将在 master 分支上播放您的提交,准备好进行 dcommit
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
which will then play your commits over the master branch ready for you to dcommit