简体   繁体   English

使用Git Rebase和导出修复合并冲突

[英]Fixing Merge Conflicts with Git Rebase and Exporting

I've run into a few merge conflicts with git rebase. 我已经遇到了一些与git rebase的合并冲突。

My question is, if I fix the conflicts, do I then do something like this: 我的问题是,如果我解决了冲突,那么我应该做这样的事情吗:

git add files
git commit "fixed merge conflicts"

then continue with 然后继续

git rebase --continue

My other question is if I mess up, can I do 我的另一个问题是,如果我搞砸了,我可以做吗

git rebase --abort 

and will that remove all the commits? 并会删除所有提交吗?

Based on your comment on jready's answer , your real question is whether you should save your original chain of commits somewhere / somehow. 根据jready答案的 评论 ,您真正的问题是您是否应该将原始的提交链保存在某个地方/以某种方式保存。

Rebase, at a sort of fundamental level, works by copying (because commits can never be changed—this includes their backwards-looking links). 在某种基础上,Rebase可以通过复制进行工作(因为无法更改提交,这包括其向后的链接)。 Branch names simply point to some specific commit. 分支名称只是指向某些特定的提交。 If we draw the commits as nodes in a graph, what we have looks like this: 如果我们将提交绘制为图形中的节点,那么我们将如下所示:

...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch

If you run git checkout your-branch && git rebase origin/whatever , Git must copy commit J , by turning it into a set of changes vs its parent G , and apply those changes to commit I (where origin/whatever points). 如果您运行git checkout your-branch && git rebase origin/whatever ,则Git必须复制提交J ,方法是将提交J转换为一组更改(相对于其父G ,并将这些更改应用于提交I (其中origin/whatever指向)。 Having copied J to J' , it then tries to copy K to a new commit K' , and so on. J复制到J' ,它将尝试将K复制到新的提交K' ,依此类推。 The eventual result, after you resolve any conflicts but before Git "peels the name off" commit L , is: 在解决了所有冲突之后但在Git“剥离名称”提交L之前,最终结果是:

                J'-K'-L'  <-- HEAD
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch

The very last step of git rebase is to remove the name your-branch from where it is pasted right now, pointing to commit L , and make it point instead to commit L' —the last copy that rebase made: 的最后一步git rebase是删除名字your-branch从那里现在粘贴,指着犯L ,并使其指向,而不是犯L'是底垫制成-the最后一个副本:

                J'-K'-L'  <-- your-branch (HEAD)
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   [abandoned]

If you use git rebase --abort instead of continuing, Git just abandons the copied chain instead, leaving the name your-branch still pointing to L : 如果您使用git rebase --abort而不是继续,那么Git只会放弃复制的链,而your-branch名称仍指向L

                J'-K'-L'  [abandoned]
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch (HEAD)

Before you start the rebase, or any time in the middle of the rebase when your-branch still points to commit L , you can add a new name to remember the raw hash ID of commit L : 在开始重新设置基准之前,或者在your-branch的中间任何时候your-branch仍然指向提交L ,您都可以添加一个新名称来记住提交L的原始哈希ID:

                J'-K'  <-- HEAD
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch, extra-name

which you might do with git branch extra-name your-branch for instance. 例如,您可以使用git branch extra-name your-branch That way, after you finish the rebase, assuming you do finish it, you end up with: 这样,在完成变基之后,假设您完成了变基,您将得到:

                J'-K'-L'  <-- your-branch (HEAD)
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- extra-name

You don't have to do this, because secretly, git rebase sets up a special name, ORIG_HEAD , to remember where your branch name was before it yanked it off L and pasted it onto L' . 不必这样做,因为偷偷git rebase设置了一个特殊的名字, ORIG_HEAD ,记住您的分支的名字是前猛拉其关闭L并粘贴它放到L' But the name ORIG_HEAD will be overwritten by whatever other Git command you use later (maybe another rebase) that yanks a label around like this, so that's sort of a short-term stop-gap you can use to recover if you don't like the result. 但是名称ORIG_HEAD将被您稍后使用的任何其他Git命令(可能是另一个重新设置)覆盖,该标签会像这样晃动标签,因此这是一种短期的权宜之计,您可以在不喜欢的情况下进行恢复结果。

Your Git also records, in something called the reflog for the branch, the previous value of the branch name, ie, the fact that your-branch used to point to commit L instead of L' . 您的Git还在分支的reflog中记录了分支名称的先前值,即your-branch以前指向提交L而不是L'的事实。 These reflog entries last for 30 or 90 days. 这些reflog条目持续30或90天。 1 They're not the easiest things to use, though: 1它们不是最容易使用的东西:

git reflog your-branch

will spill out all of them, but what you get is the one-line summary you used in each commit, and when you use git rebase you generally copy the original one-line summary from commit L to commit L' , so it can be hard to tell which one is which. 会溢出所有这些信息,但是您得到的是每次提交中使用的单行摘要,并且当您使用git rebase ,通常将原始的单行摘要从提交L复制到提交L' ,因此可以很难说是哪一个。

Still, some combination of ORIG_HEAD and the reflogs will usually let you recover without an extra name. 尽管如此, ORIG_HEAD和reflogs的某种组合通常会使您无需额外名称即可恢复。 Use the extra name if it makes you more comfortable. 如果使您更舒适,请使用多余的名称。 I do it a lot: if I am working on feature/X , and need to rebase, I create feature/X.0 and then rebase. 我做了很多事情:如果我正在使用feature/X ,并且需要重新设置feature/X.0 ,那么我将创建feature/X.0然后重新设置feature/X.0 My original series of commits are now available as the dot-zero version. 我的原始提交系列现在可以作为零点版本了。 A few days later, if I need to do another rebase, I create feature/X.1 and then rebase. 几天后,如果需要再次进行基准调整,请创建feature/X.1 ,然后进行基准调整。 So feature/X is the latest, and feature/X.<number> is the older one, with more older ones remaining until I collect them up and toss them out myself. 因此feature/X是最新版本, feature/X.<number>是较旧的版本,还有更多较旧的版本,直到我将它们收集起来并自己扔掉为止。


1 Technically, the ones that expire in 30 days are using the expireUnreachable time: these are commits that are not reachable from the current value of the reference. 1从技术上讲,那些在30天内到期的文件将使用expireUnreachable时间:这些是从引用的当前值无法达到的提交。 Rebase generally makes this kind of reference, so the default 30 day expiration is the one you should concentrate on. Rebase通常会提供这种参考,因此默认的30天到期时间是您应该关注的时间。

(Reflog entries that are reachable get the 90 day default.) 可以访问的Reflog条目将默认为90天。)

git rebase --abort will just back out of the rebase entirely, essentially reverting your repository back to the point in time right before you started the rebase . git rebase --abort将完全退出rebase,从本质上将您的存储库恢复到开始rebase之前的时间点。 The only commits that are lost will be the brand new commits that git rebase had created (since git rebase replays your original commits, thus forming new commits). 唯一丢失的提交将是git rebase创建的全新提交(因为git rebase 重播了原始提交,因此形成了新提交)。

The original commits are never touched regardless of whether you abort or not. 无论您是否中止,都不会触及原始提交。

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

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