我该如何保存git“rebase进行中”? [英] How can I save a git "rebase in progress"?

查看:158
本文介绍了我该如何保存git“rebase进行中”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正处在一个大型正在进行中的冲突中,冲突很多。



我想设置此进度并试图用另一种方法解决这个问题。



有没有一种方法可以保存正在进行的 rebase,以便我可以完成它后来呢?

解决方案

如果你坐在一个冲突的合并作为rebase的一部分,你有点卡住了。这就是为什么,如何以及你能做什么。



Rebase =重复的樱桃挑选



从根本上说,Git中的rebase操作仅仅是一系列的樱桃挑选操作。我们从这样的事情开始:

  ...-- A1  -  A2  -  A3  -  A4  -  A5< ;  -  branchA 
\
B1 - B2 - B3 < - branchB

,我们想要结束:

  ...-- A1  -  A2  -  A3- -A4-A5 < -  branchA 
\\
\ B1'-B2'-B3'< - branchB
\
B1-- B2 - B3 [弃用]

我们(或Git)实现这个的方式是使用 git cherry-pick 或其他相当于 copy 现有提交 B1 (将它变成修补程序和应用程序)紧接在 A5 之后,并复制 B2 B1之后',依此类推。



交互式rebase字面上运行 git cherry-pick 每个挑选操作你在说明中留下。非交互式数据库有多个选项,包括运行 git cherry-pick



当选择提交时,如果在应用它时发生冲突,Git可以使用三向合并。这仍然可能会因冲突而失败。这停止了​​rebase。或者,在使用交互式底图时,您可以选择编辑提交,在这种情况下,Git会选择提交并停止变形。在任何一种情况下,Git都会留下足够的信息,以便Git稍后恢复rebase。



冲突在索引中



作为一个快速提醒,让我们注意到Git的索引是您构建 next 提交的地方。通常每个文件都有一个条目要提交,这样如果你的下一个提交文件只包含三个名为 README file otherfile ,将会有三个索引条目。

注意,索引与工作树,其中包含正常的非Gitty格式的文件。您可以编辑这些文件,编译它们,使用它们来为网页提供服务等等,而不像索引和存储库文件的内部Git格式。 (工作树也可以容纳未跟踪的文件,而不是在重新绑定时这很重要。)

在冲突合并期间,每个索引条目都公开其各个 / em>的。每个条目最多有四个插槽,并且它们被编号。零槽保持正常的,未冲突的文件(如果存在的话),否则它是空的。插槽1-3如果在使用中,则保留三个必须解决的冲突部分。 1 这些是 base 版本(来自 merge base ),本地或 - 我们的版本,另一个或 - 他们的或有时远程版本。你的工作是编辑文件的工作树版本,解决冲突,然后 git add 结果。这将调整后的工作树版本复制到索引中的第零个槽中,清除第1-3个条目。现在文件已解析并准备提交。






1 因此, 插槽0被占用,并且1-3为空,否则插槽0为空,插槽1-3被占用。有一些奇怪的情况,插槽1,2和/或3也可以是空的,例如,如果您遇到修改/删除冲突或添加/添加冲突,但通常为0空表示1-3已满反之亦然。




但只有一个索引



这个短语暗示着只有一个。这主要是真的。



因为未合并状态位于此(the)索引中,并且只有一个索引,所以其他需要使用 索引才能继续执行,直到完成解决冲突(然后进行提交)。



如果你喜欢,只需 git add 未固定/未解析的项目和 git commit 结果,以获得冲突一路走来。这里的缺点是,Git不会保留哪些文件发生冲突:你将消除插槽1-3的条目,Git会认为你全部完成了。



你可以保存索引 - 它是一个普通的文件;你可以将它从 .git / index >别的地方复制出来。但是因为它是一个二进制文件,具有各种特殊的内部使用 - 索引也被称为缓存,它缓存内部文件系统数据的速度 - 这并不是很安全。 (如果Git有办法导出索引状态,然后再导入它,这样你真的可以保存和恢复合并冲突状态了,但是Git不会'所以,为了安全起见,如果没有别的,建议完成解决这个冲突的合并状态。或者,如果你还没有开始解析,那就不要开始:那么就没有工作要保存。



你现在在哪里



假设您开始在上面绘制的branch Brebase,并且目前停留在复制commit B2 ,有些冲突未解决。以下是您现在的实际情况:

  ...-- A1  -  A2  -  A3  -  A4  -  A5 <  -  branchA 
\\
\ B1'< - HEAD
\
B1 - B2 - B3< - branchB

,其索引处于冲突状态。你也有一个分离的HEAD:Git以这种方式构建新的提交链。名称 HEAD 指向所有已完成的提交。



如果你已经完成了一些解决工作,你应该完成它(因为它很难保存未解决的状态),或者至少记下什么是未解决的(因为你可以添加文件到你的下一个提交),然后运行 git commit 来创建提交 B2'

  ...-- A1  -  A2- -A3-A4-A5 < -  branchA 
\\
\ B1'-B2'< - 头部
\
B1-- B2 - B3 < - branchB

如果您还没有做任何解决工作,工作保存,所以不要运行 git commit 。但是 now 现在是创建分支或标记名称的时候了,它指向现在 HEAD 的相同提交指向:

  $ git branch saveme#或git标签saveme 
$ b $现在你有了这个:

$ $ $ $ $ code ... ... A1 - A2 - A3 - A4 - A5 < - branchA
\\
\ B1'-B2'< - HEAD,saveme
\
B1 - B2 - B3 < - branchB

现在您可以:

  $ git rebase --abort 

这使得Git停止了rebase尝试并返回到 branchB

<$ p $ A1-A2-A3-A4-A5 < - 分支A
\\
\ B1'-B2' < - saveme
\
B1 - B2 - B3< - HEAD - > branchB

现在,您已经保存了迄今为止完成的所有工作,并且可以稍后再返回并重试rebase。你有你(或Git)为 B1'所做的决议,如果你提交了 B2',你有你为此做出的决议。这些是分别提交 saveme〜1 saveme ;或只提交 saveme ,如果只有一个提交。


I'm in the middle of a large "rebase in progress" with numerous conflicts.

I would like to set this progress aside and attempt to resolve this issue using another approach.

Is there a way I can save an in-progress rebase such that I can finish it later?

解决方案

If you're sitting at a conflicted merge as part of a rebase, you are kind of stuck. Here is why, how, and what you can do.

Rebase = repeated cherry-pick

Fundamentally, a rebase operation in Git is just a series of cherry-pick operations. We start with something like this:

...--A1--A2--A3--A4--A5   <-- branchA
          \
           B1--B2--B3   <-- branchB

and we want to end up with:

...--A1--A2--A3--A4--A5   <-- branchA
          \           \
           \           B1'-B2'-B3'  <-- branchB
            \
             B1--B2--B3   [abandoned]

The way we (or Git) achieve this is by using git cherry-pick, or something equivalent, to copy existing commit B1 (turning it into a patch and applying it) to come just after A5, and copy B2 to come after B1', and so on.

Interactive rebase literally runs git cherry-pick for each "pick" operation you leave in the instructions. Non-interactive rebase has several options, including running git cherry-pick.

When cherry-picking a commit, if there are conflicts while applying it, Git can use a three-way merge. This can still fail with a conflict. This stops the rebase. Or, when using interactive rebase, you can choose to "edit" a commit, in which case Git cherry-picks that commit and then stops the rebase. In either case, Git leaves behind enough information for you to have Git resume the rebase later.

Conflicts are in the index

As a quick reminder, let's note that Git's index is where you build the next commit. Normally there is one entry for each file to be committed, so that if your next commit will consist of just three files named README, file, and otherfile, there will be three index entries.

Note that the index is separate from the work tree, which contains files in normal, non-Gitty format. You can edit these files, compile them, use them to serve web pages, and so on, unlike the internal Git format for index and repository files. (The work-tree can also hold untracked files, not that this matters during rebase.)

During a conflicted merge, each index entry exposes its individual slots. There are up to four slots per entry, and they are numbered. Slot zero holds the normal, unconflicted file (if that exists), otherwise it's empty. Slots 1-3, if in use, hold the three conflicting parts that must be resolved.1 These are the base version (from the merge base), the "local" or --ours version, and the other or --theirs or sometimes "remote" version respectively. Your job is to edit the work-tree version of the file, resolve the conflicts, and then git add the result. This copies the adjusted work-tree version into slot zero in the index, wiping out the slot 1-3 entries. Now the file is resolved and ready to commit.


1Hence, either slot 0 is occupied and 1-3 are empty, or else slot 0 is empty and slots 1-3 are occupied. There are some oddball cases where slot 1, 2, and/or 3 can also be empty, e.g., if you get a modify/delete conflict or an add/add conflict, but usually it's "0 empty means 1-3 are full" and vice versa.


But there's only one index

The very phrase the index implies that there is only one. This is mostly true.

Because the unmerged state is in this ("the") index, and there is only one index, anything else that needs to use the index cannot proceed until you finish resolving the conflicts (and then make a commit).

You can, if you like, simply git add the un-fixed/un-resolved items and git commit the result, just to get the conflicts out of the way. The drawback here is that Git won't retain which files were conflicted: you will wipe out the slot 1-3 entries and Git will think you are all done.

You could save the index—it's an ordinary file; you can copy it out of .git/index somewhere else. But because it's a binary file with various kinds of special internal use—the index is also called the "cache" and it caches internal file system data for speed—this is not really very safe. (It would be nice if Git had a way to "export" the index state, and then "import" it again later, so that you really could save and restore merge conflict states. But Git doesn't.)

So, for safety if nothing else, it's advisable to finish resolving this conflicted merge state. Or, if you have not started resolving, just don't even start: then there's no work to save.

Where you are now

Let's say you started that "branch B" rebase I drew above, and are currently stuck in the middle of copying commit B2, with some conflicts unresolved. Here's what you actually have right now:

...--A1--A2--A3--A4--A5   <-- branchA
          \           \
           \           B1'  <-- HEAD
            \
             B1--B2--B3   <-- branchB

with the index in conflicted state. You also have a "detached HEAD": Git is building the new chain of commits this way. The name HEAD points to all completed commits.

If you have done some resolving work, you should finish it up (since it's too hard to save unresolved state) or at least make note of what's unresolved (since you can add files to your next commit) and then run git commit to create commit B2':

...--A1--A2--A3--A4--A5   <-- branchA
          \           \
           \           B1'-B2'  <-- HEAD
            \
             B1--B2--B3   <-- branchB

If you have not done any resolving work, there's no actual work to save, so don't run git commit. But either way, now it's time to create a branch or tag name, pointing to the same commit that HEAD now points to:

$ git branch saveme    # or git tag saveme

Now you have this:

...--A1--A2--A3--A4--A5   <-- branchA
          \           \
           \           B1'-B2'  <-- HEAD, saveme
            \
             B1--B2--B3   <-- branchB

Now you can just:

$ git rebase --abort

which makes Git stop the rebase attempt and move back to branchB:

...--A1--A2--A3--A4--A5   <-- branchA
          \           \
           \           B1'-B2'  <-- saveme
            \
             B1--B2--B3   <-- HEAD->branchB

Now you have saved all the work you have done so far, and can go back and retry the rebase later. You have the resolution you (or Git) made for B1', and if you made commit B2', you have the resolution you made for that as well. These are commits saveme~1 and saveme, respectively; or just commit saveme, if there is only the one commit.

这篇关于我该如何保存git“rebase进行中”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆