git pull --rebase --preserve-merges

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21364636/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 09:38:30  来源:igfitidea点击:

git pull --rebase --preserve-merges

gitgit-rebase

提问by AturSams

Short version: Do you need to preserve-merges only if you explicitly merged after you did a local commit? What exactly happens otherwise? Does it reapply your committed code to the merged branch?

简短版本:只有在执行本地提交后显式合并时才需要保留合并吗?否则到底会发生什么?它是否将您提交的代码重新应用于合并的分支?

Please explain when it is useful to git pull --rebase --preserve-mergesvs. a regular git pull --rebase? I read about an issue with git pull --rebasehere: http://notes.envato.com/developers/rebasing-merge-commits-in-git/That could cause code changes to be duplicated.

请解释什么时候git pull --rebase --preserve-merges对普通人有用git pull --rebase?我git pull --rebase在这里阅读了一个问题:http: //notes.envato.com/developers/rebasing-merge-commits-in-git/这可能会导致代码更改被复制。

I read here: When will `git pull --rebase` get me in to trouble?

我在这里读到:“git pull --rebase”何时会给我带来麻烦?

That it only happens if you basically rebase after some the commits have been pushed.

只有当你在一些提交被推送后基本上重新设置时才会发生这种情况。

So I am not sure I understand when I would need git pull --rebase --preserve-mergesand if it's ever bad to use vs. git pull --rebase.

所以我不确定我是否理解我git pull --rebase --preserve-merges什么时候需要,以及使用 vs. 是否不好 git pull --rebase

回答by torek

Technically—and I claim this is a bit stupid of git, the pullscript (it's a shell script) should just do this for you—you have to run git pull --rebase=preserverather than attempting to use git pull --rebase --preserve-merges. (Or, as I noted in a commenton Vlad Nikitin's answer, you can set branch.name.rebaseto preserveto get the same effect automatically.)

从技术上讲——我声称这对 git 来说有点愚蠢,pull脚本(它是一个 shell 脚本)应该为你做这件事——你必须运行git pull --rebase=preserve而不是尝试使用git pull --rebase --preserve-merges. (或者,正如我在对Vlad Nikitin 的回答的评论中所指出,您可以设置为自动获得相同的效果。)branch.name.rebasepreserve

In other words, you should neverrun git pull --rebase --preserve-mergesas it (incorrectly) passes --preserve-mergesto the fetchstep, instead of to the merge-or-rebasestep. However, you canrun git pull --rebase=preserve.

换句话说,你应该永远不会运行git pull --rebase --preserve-merges,因为它(错误地)传递--preserve-mergesfetch代替步骤,merge-或-rebase步。但是,您可以运行git pull --rebase=preserve.

The question of when (and whether) to use any kind of rebase, whether merge-preserving or not, is more a matter of opinion. Which means it really does not go well on stackoverflow in the first place. :-)

何时(以及是否)使用任何类型的 rebase,无论是否保留合并,更多是一个意见问题。这意味着它首先在 stackoverflow 上并不顺利。:-)

Still, I'll make one claim here: you should only rebase if you know (in a sort of general sense) what you are doing,1and if you doknow what you are doing, you would probably prefer a merge-preserving rebase as a general rule, although by the time you've decided that rebasing is a good idea, you will probably find that a history that has its own embedded branch-and-merge-points is not necessarily the correct "final rewritten history".

不过,我在这里做一个要求:如果你知道(在那种一般意义上的),你应该只重订,你在做什么,1,如果你知道自己在做什么,你可能会喜欢一个合并保底垫作为一般规则,虽然当您确定重新定位是一个好主意时,您可能会发现具有自己嵌入式分支和合并点的历史不一定是正确的“最终重写历史”。

That is, if it's appropriate to do a rebase at all, it's at least fairly likely that the history to be rebased is itself linear, so that the preserve-vs-flatten question is moot anyway.

也就是说,如果完全适合进行重新定位,那么至少很有可能要重新定位的历史记录本身是线性的,因此无论如何保留与展平的问题都没有实际意义。



Edit: add drawing

编辑:添加绘图

Here's a drawing of part of a commit graph, showing two named branches, mainlineand experiment. The common base for mainlineand experimentis commit node A, and mainlinehas a commit Gthat is not on the experimentbranch:

这是提交图的一部分的绘图,显示了两个命名分支mainlineexperiment. mainlineand的共同基础experiment是 commit node A,并且mainline有一个G不在experiment分支上的提交:

...--o--A-------------G   <-- mainline
         \
          \ .-C-.
           B     E--F     <-- experiment
            \_D_/

Note that the experimentbranch has a branch-and-merge within it too, though: the base for these two branches is B, one branch holds commit C, and the other branch holds commit D. These two (unnamed) branches shrink back to a single thread of development at merge commit E, and then commit Fsits atop the merge commit and is the tip of branch experiment.

请注意,该experiment分支内部也有一个分支合并:这两个分支的基础是B,一个分支保存 commit C,另一个分支保存 commit D。这两个(未命名的)分支在合并提交时收缩回单个开发线程E,然后提交F位于合并提交的顶部并且是分支的尖端experiment

Here's what happens if you are on experimentand run git rebase mainline:

如果您打开experiment并运行,会发生以下情况git rebase mainline

$ git rebase mainline
First, rewinding head to replay your work on top of it...
Applying: B
Applying: C
Applying: D
Applying: F

Here's what is now in the commit graph:

这是提交图中现在的内容:

...--o--A--G               <-- mainline
            \
             B'-C'-D'-F'   <-- experiment

The "structural branch" that used to be there on branch experimentis gone. The rebaseoperation copied all the changesI'd made in commits B, C, D, and F; these became the new commits B', C', D', and F'. (Commit Ewas a pure merge with no changes and did not require copying. I have not tested what happens if I rebase a merge with embedded changes, either to resolve conflicts or, as some call it, an "evil merge".)

曾经存在于分支上的“结构分支”experiment已经消失。该rebase操作复制了所有的变化我会在提交了几次BCD,和F; 这些成为了新的提交B'C'D',和F'。(提交E是一个没有更改的纯合并,不需要复制。我还没有测试如果我使用嵌入的更改重新设置合并会发生什么,要么解决冲突,要么有人称之为“邪恶合并”。)

On the other hand, if I do this:

另一方面,如果我这样做:

$ git rebase --preserve-merges mainline
[git grinds away doing the rebase; this takes a bit longer
than the "flattening" rebase, and there is a progress indicator]
Successfully rebased and updated refs/heads/experiment.

I get this graph instead:

我得到了这个图:

...--o--A--G               <-- mainline
            \
             \ .-C'.
              B'    E'-F'  <-- experiment
               \_D'/

This has preserved the merge, and hence the "internal branchiness", of experiment. Is that good? Bad? Indifferent? Read the (very long) footnote!

这保留了合并,因此保留了experiment. 这样好吗?坏的?冷漠?阅读(很长的)脚注!



1It's a good idea to learn "what rebase does" anyway, which in git (alas!) pretty much requires learning "how it does it" as well, at least on a medium-level. Basically, rebase makes copiesof (the changes from your earlier) commits, which you then apply to (your or someone else's) later commits, making it "seem like" you did the work in some other order. A simple example: two developers, let's say Alice and Bob, are both working on the same branch. Let's say that Marketing has asked for a feature code-named Strawberry, and both Alice and Bob are doing some work to implement strawberry, both on a branch named strawberry.

1无论如何,学习“rebase 做什么”是个好主意,这在 git 中(唉!)几乎也需要学习“它是如何做到的”,至少在中等水平上。基本上,rebase 会复制(您之前的更改)提交,然后您将其应用于(您或其他人的)以后的提交,使其“看起来像”您以其他顺序完成工作。一个简单的例子:两个开发人员,假设 Alice 和 Bob,都在同一个分支上工作。假设 Marketing 要求一个代号为 Strawberry 的特性,Alice 和 Bob 都在做一些工作来实现strawberry,都在一个名为 的分支上strawberry

Alice and Bob both run git fetchto bring strawberryover from origin.

爱丽丝和鲍勃都跑过来git fetch把.strawberryorigin

Alice discovers that file abcneeds some change to prepare for the new feature. She writes that and commits, but does not push yet.

Alice 发现该文件abc需要进行一些更改才能为新功能做准备。她写了那个并提交,但还没有推送。

Bob writes a descriptionof the new feature, that changes file README, but has no other effect. Bob commits his change and pushes.

Bob 写了一个新特性的描述,它改变了 file README,但没有其他影响。Bob 提交他的更改并推送。

Alice then updates file featto provide the actual feature. She writes and commits (separately) that, and is now ready to push. But, oh no, Bob beat her to it:

Alice 然后更新文件feat以提供实际功能。她编写并提交(单独),现在准备推送。但是,哦不,鲍勃打败了她:

$ git push origin strawberry
...
! [rejected]        strawberry -> strawberry (non-fast-forward)

Alice should then fetch the changes and look at them(not just blindly merge or rebase):

Alice 然后应该获取更改并查看它们(不仅仅是盲目地合并或变基):

$ git fetch
...
$ git log origin/strawberry

(or using gitkor whatever—I tend to use git lolamyself, and git showindividual commits if/as needed).

(或使用gitk或其他 - 我倾向于使用git lola自己,git show如果/根据需要,个人提交)。

She can see from this that Bob only changed the README, so her changes are definitely not affected either way. At this point, she can tell that it's safe to rebase her changes onto origin/strawberry:

从中可以看出,Bob 只更改了README,因此她的更改绝对不会受到任何影响。在这一点上,她可以判断将她的更改重新设置为安全的origin/strawberry

$ git rebase origin/strawberry

(note that there are no merges to preserve), which makes it look(in terms of git history) like she first waited for Bob to update the documentation, and only then actually started to implement the changes—which are still split into two separate commits so that it's easy to tell, later, whether the change to file abcbroke anything else. Those two separate commits are now adjacent, though, so it's easy to tell, later, that the pointof the change to abcwas to enable the change to file feat. And since the change to READMEcomes first, it's even more clear that the this was the point of the change to abc. Not that it would be hard to tell even if Alice just did:

(请注意,没有要保留的合并),这使它看起来(就 git 历史记录而言)就像她首先等待 Bob 更新文档,然后才真正开始实施更改——这些更改仍然分为两个独立的提交以便以后很容易判断对文件的更改是否abc破坏了其他任何内容。这两个不同的提交现在是相邻的,虽然如此,很容易分辨,后来,该的变化来abc是为了使更改文件feat。并且由于更改 toREADME首先出现,更清楚的是 this 是更改为 的重点abc。并不是说即使爱丽丝刚刚做了也很难说:

$ git merge origin/strawberry

instead, although that creates a merge commit whose only point seems to be to say "Alice started in on abcbefore Bob finished updating README, and finished featafter", which is not really helpful.

相反,尽管这会创建一个合并提交,其唯一的点似乎是说“Aliceabc在 Bob 完成更新之前开始README,并在feat之后完成”,但这并没有真正的帮助。

In more complex cases, where Bob did more than just update the documentation, Alice might find that it's best to rearrange her own commits (probably more than two in this case) into a new, different linear history, so that some of Bob's changes (this time, probably more than one commit) are "in the middle", for instance, as if they had co-operated in real time (and who knows, maybe they did). Or she might find that it's better to keep her changes as a separate development line that merges, perhaps even more than once, with Bob's changes.

在更复杂的情况下,Bob 所做的不仅仅是更新文档,Alice 可能会发现最好将她自己的提交(在这种情况下可能超过两次)重新排列到一个新的、不同的线性历史中,以便 Bob 的一些更改(这一次,可能不止一个提交)“处于中间”,例如,好像他们已经实时合作(谁知道,也许他们确实合作过)。或者她可能会发现,最好将她的更改保留为一条单独的开发线,与 Bob 的更改合并,甚至可能不止一次。

It's all a matter of what will provide the most useful information to someone(s)—possibly Alice and Bob, possibly other developers—in the future, if and when it becomes necessary to go back and look at the (apparent, if rebased, or actual if not) sequence of events. Sometimes each individual commit is useful information. Sometimes it's more useful to rearrange and combine commits, or drop some commits entirely: for instance, changes that proved to be a bad idea. (But consider leaving them in just for the value of pointing out "this was a bad idea so don't try it again in the future" as well!)

这完全是一个问题,在未来,如果有必要回去查看(显然,如果重新定位,或实际(如果不是)事件序列。有时,每个单独的提交都是有用的信息。有时,重新排列和组合提交或完全删除一些提交更有用:例如,被证明是一个坏主意的更改。(但考虑将它们保留下来只是为了指出“这是一个坏主意,所以以后也不要再试一次”的价值!)

回答by Vlad Nikitin

git pull --rebaseis the same as git fetchand then git rebase, so git pull --rebase --preserve-mergesis the same as git fetchand then git rebase --preserve-merges. You can get good answer about git rebase --preserve-mergeshere What exactly does git's "rebase --preserve-merges" do (and why?)

git pull --rebasegit fetch与然后相同git rebase,所以与然后git pull --rebase --preserve-merges相同 。你可以在这里得到很好的答案git 的“rebase --preserve-merges”究竟做了什么(为什么?)git fetchgit rebase --preserve-mergesgit rebase --preserve-merges