简体   繁体   English

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

[英]Is git-svn dcommit after merging in git dangerous?

My motivation for trying out git-svn is the effortless merging and branching. 我尝试git-svn的动机是毫不费力的合并和分支。 Then I noticed that man git-svn(1) says: 然后我注意到男人git-svn(1)说:

Running git-merge or git-pull is NOT recommended on a branch you plan to dcommit from. 不建议在您计划提交的分支上运行git-merge或git-pull。 Subversion does not represent merges in any reasonable or useful fashion; Subversion不以任何合理或有用的方式表示合并; so users using Subversion cannot see any merges you've made. 因此使用Subversion的用户无法看到您所做的任何合并。 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. 此外,如果您从作为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? 这是否意味着我无法从svn / trunk(或分支)创建本地分支,破解,合并回svn / trunk,然后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? 我知道svn用户会看到同样的混乱,在svn pre 1.5.x中一直是合并,但是还有其他缺点吗? That last sentence worries me, too. 最后一句也让我担心。 Do people routinely do these kinds of things? 人们经常做这些事吗?

Actually, I found an even better way with the --no-ff option on git merge. 实际上,我在git merge上使用--no-ff选项找到了更好的方法。 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 repository trunk/ , branches/ , and tags/ ): 我有一个“master”分支,它是我提交的唯一分支并克隆SVN存储库( -s假设您在存储库trunk/branches/tags/有一个标准的SVN布局):

     git svn clone [-s] <svn-url> 
  • I work on a local branch "work" ( -b creates the branch "work") 我在本地分支“work”上工作( -b创建分支“work”)

     git checkout -b work 
  • commit locally into the "work" branch ( -s to sign-off your commit message). 本地提交到“工作”分支( -s以签署您的提交消息)。 In the sequel, I assume you made 3 local commits 在续集中,我假设你做了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) [最终]存储您不希望在SVN服务器上看到的修改(通常您只是因为想要加速编译并专注于给定功能而在主文件中注释了一些代码)

     (work)$> git stash 
  • rebase the master branch with the SVN repository (to update from the SVN server) 使用SVN存储库重新绑定主分支(从SVN服务器更新)

     (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 现在是时候使用这个精彩的--no-ff选项将所有三个提交从“工作”分支合并到“主”

     (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'" 现在你可能想编辑( amend )你的SVN家伙的最后一次提交(否则他们只会看到一个提交消息“合并分支'工作'”

     (master)$> git commit --amend 
  • Finally commit on the SVN server 最后在SVN服务器上提交

     (master)$> git svn dcommit 
  • Go back to work and eventually recover your stashed files: 回去工作,最终恢复你的藏匿文件:

     (master)$> git checkout work (work)$> git stash pop 

Creating local branches is definitely possible with git-svn. 使用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分支之间进行合并,您应该没问题。

I have a "master" branch that I use to track the svn server. 我有一个“主”分支,用于跟踪svn服务器。 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: 当我想提交它时,我会执行以下操作:

  1. Commit everything to the topic branch 将所有内容提交到主题分支
  2. git svn rebase (resolve any conflicts between your work and svn) git svn rebase (解决你的工作和svn之间的任何冲突)
  3. git checkout master git checkout master
  4. git svn rebase (this makes the next step a fast-forward merge, see Aaron's comments below) git svn rebase (这使得下一步成为快进合并,请参阅下面的Aaron的评论)
  5. git merge topic_branch git merge topic_branch
  6. resolve any merge conflicts (there shouldn't be any at this point) 解决任何合并冲突(此时不应该有任何合并冲突
  7. git svn dcommit git svn dcommit

I also have another situation where I need to maintain some local changes (for debugging) that should never be pushed up to svn. 我还有另一种情况,我需要保持一些本地更改(用于调试),永远不应该推送到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. 当我想在那里提交工作时,我会检查master并使用cherry-pick来从我想要提交给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. 首先运行git svn dcommit -n是值得的,以确保你准备提交你想要提交的内容。 Unlike git, rewriting history in svn is hard! 与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,所以如果有人有任何想法,他们将受到欢迎。

Simple solution: Remove 'work' branch after merging 简单的解决方案:合并后删除“工作”分支

Short answer: You can use git however you like (see below for a simple workflow), including merge. 简短回答:您可以随意使用git(请参阅下面的简单工作流程),包括合并。 Just make sure follow each ' git merge work ' with ' git branch -d work ' to delete the temporary work branch. 只需确保使用' git branch -d work '跟随每个' git merge 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. 背景说明: merge / dcommit问题是,每当你'stn'scomn'一个分支时,该分支的合并历史就是'flattened':git忘记了进入这个分支的所有合并操作:只保留文件内容,但是这个内容(部分)来自特定的其他分支的事实已经丢失。 See: Why does git svn dcommit lose the history of merge commits for local branches? 请参阅: 为什么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 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. 如果在将“work”分支合并到“master branch”后删除它,那么你的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). 下一步(git rebase -i)是可选的 - 它只是清理历史记录,然后在svn上存档:一旦我达到了一个稳定的里程碑,我想与他人分享,我重写了这个'工作'的历史分支并清理提交消息(其他开发人员不需要查看我在路上所做的所有小步骤和错误 - 只是结果)。 For this, I do 对此,我这样做

$> 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). 并复制svn存储库中存在的最后一次提交的sha-1哈希(如git-svn-id所示)。 Then I call 然后我打电话

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

Just paste sha-1 hash of our last svn commit instead of mine. 只需粘贴我们上一次svn提交的sha-1哈希而不是我的。 You may want to read the documentation with 'git help rebase' for the details. 您可能需要阅读带有'git help rebase'的文档以获取详细信息。 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. 简而言之:这个命令首先打开一个编辑器,显示你的提交----只需将'pick'改为'squash',用于所有那些你希望用之前的提交压缩的提交。 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: 为了将更改推送到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). 现在我们回到旧的“主”分支,更新了svn存储库中同时发生的所有更改(您的新更改隐藏在“工作”分支中)。

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). 注1:命令'git branch -d work'非常安全:它只允许你删除不再需要的分支(因为它们已经合并到你当前的分支中)。 If you execute this command by mistake before merging your work with the 'master' branch, you get an error message. 如果在将工作与“master”分支合并之前错误地执行了此命令,则会收到错误消息。

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'. 注意2:确保合并和dcommit 之间使用'git branch -d work'删除分支:如果在dcommit之后尝试删除分支,则会收到一条错误消息:当你执行'git svn dcommit'时,git忘记了您的分支已与'master'合并。 You have to remove it with 'git branch -D work' which doesn't do the safety check. 您必须使用不执行安全检查的'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'显示其他人在我的'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

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. 存在更强大的解决方案:所呈现的工作流程过于简单:它仅在每一轮'update / hack / dcommit'中使用git的强大功能 ---但是将长期项目历史保留为与svn存储库一样线性。 This is ok if you just want to start using git merges in small first steps in a legacy svn project. 如果你只是想在遗留svn项目的小开头步骤中开始使用git merge,这是可以的。

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

Greg Hewgill answer on top is not safe! Greg Hewgill回答顶部并不安全! If any new commits appeared on trunk between the two "git svn rebase", the merge will not be fast forward. 如果在两个“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). 通过在git-merge中使用“--ff-only”标志可以确保它,但我通常不在分支中运行“git svn rebase”,只在其上运行“git rebase master”(假设它只是一个本地科)。 Then afterwards a "git merge thebranch" is guaranteed to be fast forward. 然后一个“git merge thebranch”保证快进。

A safe way to merge svn branches in git is to use git merge --squash. 在git中合并svn分支的一种安全方法是使用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. 假设您有一个主题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

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. 将本地git分支重新引导到主git分支然后dcommit,这样看起来你按顺序完成了所有这些提交,所以svn人们可以像他们习惯的那样线性地看到它。 So assuming you have a local branch called topic you could do 因此,假设您有一个名为topic的本地分支,您可以这样做

git rebase master topic

which will then play your commits over the master branch ready for you to dcommit 然后,它将在主分支上播放您的提交,准备让您同意

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM