简体   繁体   English

Git rebase 冲突,实际修改了哪些分支?

[英]Git rebase conflict, which branches are actually modified?

So even after doing it plenty of time, I am still very scared of rebasing, and I think one the problem I have is I do deeply understand what it does.所以即使做了很多时间,我仍然非常害怕变基,我认为我遇到的一个问题是我确实深刻理解它的作用。

So I have branch develop and my branch, starting out of develop.所以我有分支开发和我的分支,从开发开始。 To avoid/solve conflict, I wish to update from which commit is my branch starting.为了避免/解决冲突,我希望更新我的分支从哪个提交开始。 For that reason, on my branch I perform a git rebase develop .出于这个原因,在我的分支上,我执行了git rebase develop

My question is, Let say, during the rebasing phase, I decide to delete/modify every single changes performed.我的问题是,假设在变基阶段,我决定删除/修改执行的每一个更改。 Once I push, will only my branch will be modified, or my rebase did also modified the actual commit from develop?一旦我推送,是否只会修改我的分支,或者我的 rebase 是否也修改了来自开发的实际提交?

Only the branch you're currently on will be modified.只有您当前所在的分支会被修改。 The branch you're rebasing onto will not be touched: it's only used as a starting point for the work.您正在变基的分支不会被触及:它仅用作工作的起点。

If you want to understand git more in depth, I recommend reading A Hacker's Guide to Git , which is a really good article that goes into depth.如果你想更深入地了解 git,我推荐阅读A Hacker's Guide to Git ,这是一篇深入浅出的好文章。 It really improved my understanding of how git works, and what it does.它确实提高了我对 git 的工作原理及其作用的理解。 Shown below is an exerpt of the article:下面显示的是文章的摘录:

在此处输入图像描述

As kapsiR commented , have no fear.正如kapsiR 所说,不要害怕。 Well, maybe have a little, just enough to take a few precautions, like running git status often.好吧,也许有一点点,足以采取一些预防措施,比如经常运行git status

What git rebase is really about is copying (some) commits to new-and-improved commits . git rebase的真正目的是将(一些)提交复制到新的和改进的提交 To understand how and why this works, you first need to understand commits:要了解其工作原理和原因,您首先需要了解提交:

  • What is a commit?什么是提交?
  • How do we find commits?我们如何找到提交?
  • How do we make new commits?我们如何进行新的提交?

These are the first few crucial questions.这是前几个关键问题。 When you know the answers, you will understand Git itself.当您知道答案时,您将了解 Git 本身。 Then git rebase just requires one more item:然后git rebase只需要一项:

  • How does Git copy a commit? Git 如何复制提交?

(although there will always be more to learn). (虽然总会有更多的东西要学)。

What, exactly, is a commit (and why do we care)确切地说,什么是提交(以及我们为什么要关心)

A commit in Git: Git 中的提交:

  • Is numbered.有编号。 Every commit has a unique hash ID .每个提交都有一个唯一的hash ID This is a very large, impossible-to-remember number expressed in hexadecimal .这是一个非常大的、无法记住的数字,以十六进制表示 Whenever you make a new commit, that commit gets a unique number.每当您进行的提交时,该提交都会获得一个唯一编号。 By unique I don't mean "maybe unique" or "sort of unique", but rather absolutely unique.我所说的独特并不是指“可能独特”或“某种独特”,而是绝对独特。 No other Git anywhere in the universe is allowed to have or use that number now, unless you give that other Git this commit that you just made.现在,宇宙中任何地方都不允许其他 Git 拥有或使用该号码,除非您向其他 Git 提供您刚刚提交的提交。 Then they'll use this number for this commit and both repositories will have the same commit.然后他们将使用编号进行提交,并且两个存储库将具有相同的提交。

    This means that the commit's number–its hash ID– is the commit, in a sense.这意味着提交的编号——它的 hash ID——在某种意义上提交。 When you connect two Git versions to each other, to exchange commits from one repository to another, they just look at the numbers .当您将两个 Git 版本相互连接时,将提交从一个存储库交换到另一个存储库时,他们只需查看数字 If they have the same number, they have the same thing.如果他们有相同的号码,他们有相同的东西。 If not, whoever's missing the number can get the thing from the other Git, and now they have the same thing with the same number.如果没有,谁丢了号码,可以从另一个Git那里得到东西,现在他们有了同样的东西,同样的号码。

  • Stores two things:存储两个东西:

    • Each commit stores a full snapshot of every file.每个提交都存储每个文件的完整快照。 The files in the commit are stored in a special, compressed and de-duplicated, Git-only form: only Git can actually read these things, and nothing—not even Git itself—can overwrite them.提交中的文件特殊的、压缩和去重的、仅 Git 的形式存储:只有 Git 可以实际读取这些内容,没有任何东西——甚至 Git 本身——可以覆盖它们。 The fact that they can't change allows the de-duplication, and keeps the repository from getting tremendously fat quickly, even though most commits mostly re-use most of the files from some previous commit(s).它们无法更改的事实允许重复数据删除,并防止存储库快速变得非常胖,即使大多数提交主要重用了以前提交的大部分文件。

    • Each commit also stores some metadata , or information about the commit.每个提交还存储一些元数据,或有关提交的信息。 This includes the name and email address of the person who made the commit, for instance.例如,这包括提交人的姓名和 email 地址。 It includes some date-and-time stamps.它包括一些日期和时间戳。 It includes your log message, so you can look back later and remember why you made the commit, or read someone else's text explaining why they made their commit.它包含您的日志消息,因此您可以稍后回顾并记住您提交的原因,或者阅读其他人解释他们提交的原因的文本。 ( Good commit messages are important. ) 好的提交信息很重要。

    There's a part of this metadata that Git uses for its own purposes, that is crucial here. Git 将部分元数据用于自己的目的,这在这里至关重要。 When you make a new commit, Git stores, in that commit's metadata, the hash ID of some previous commit or commits.当您进行的提交时,Git 会在该提交的元数据中存储一些先前提交的 hash ID。 Most commits get exactly one hash ID stored here;大多数提交都得到一个存储在这里的 hash ID; we'll see more about this in a moment.我们稍后会看到更多关于这个的信息。

  • Is read-only: no part of any Git commit can ever change.是只读的:任何Git 提交的任何部分都不能更改。

    In fact, Git's magic hash technique means that no internal object of any kind can ever change.事实上,Git 的神奇 hash 技术意味着任何类型的内部 object 都无法改变。 This provides the read-only nature of commits, the read-only nature of the de-duplicated files, and the ability to de-duplicate files.这提供了提交的只读性质、去重文件的只读性质以及重文件的能力。

Why we care about this is simple.为什么我们关心这个很简单。 Git is all about the commits . Git 都是关于提交的。 Git isn't about files or branches (branch names, that is). Git 与文件或分支(即分支名称)无关。 It's about the commits.这是关于提交的。 The commits are the currency of exchange between Git repositories.提交是 Git 存储库之间的交换货币。 We connect one Git to another, with git fetch or git push , 1 and we transfer commits from one Git to another.我们将一个 Git 连接到另一个,使用git fetchgit push , 1我们将提交从一个 Z0365Z1 转移到另一个 Z0365Z105ADFE279

A Git repository is, to a first extent, just a big database of commits. Git 存储库首先是一个大型的提交数据库。 The commits hold files and metadata.提交保存文件和元数据。 Our own personal goals may well have to do with files, but Git doesn't deal in files at this level.我们自己的个人目标很可能与文件有关,但 Git 在这个级别不处理文件 It deals only in commits.它只处理提交。 So we have to use commits to get anything done with files.所以我们必须使用提交来处理文件。


1 The git pull command is a kind of convenience wrapper that first runs git fetch , to get new commits from somewhere, then runs a second Git command to do something with the commits just fetched. 1 git pull命令是一种方便的包装器,它首先运行git fetch ,从某个地方获取新的提交,然后运行第二个 Git 命令来执行一些操作 This is a bit of a trap: it leads people to believe that git pull is the right command to use, when actually the two separate commands are just as often right, especially because you can then squeeze a command between them.这有点陷阱:它使人们相信git pull是正确的命令,而实际上这两个单独的命令通常是正确的,特别是因为您可以在它们之间挤压一个命令。 That is, you can get new commits and look at them before you decide how, or even if, you want to incorporate them.也就是说,您可以在决定如何甚至是否要合并它们之前获得新的提交并查看它们。 When you use git pull you don't get this choice.当您使用git pull时,您不会得到这个选择。


How we find commits我们如何找到提交

I mentioned above that each commit stores the hash ID of a previous commit.我在上面提到过,每个提交都存储了之前提交的 hash ID。 Or, more precisely, each commit has a list of previous commits: the list can be empty ("I have no parent, I am an orphan"), or just one entry long ("my dad/mom is ________"—fill in the blank with a hash ID), or two or more entries long ("I am a merge. My parents are ________ and ________"—fill in the blanks again).或者,更准确地说,每个提交都有一个先前提交的列表:列表可以是空的(“我没有父母,我是孤儿”),或者只有一个条目(“我的爸爸/妈妈是 ________”——填写具有 hash ID 的空白),或两个或多个长条目(“我是一个合并。我的父母是 ________ 和 ________”——再次填写空白)。

Note that no parent knows its children.请注意,没有父母知道它的孩子。 When the commit is "born", it knows who its parent is, but from that point on it's frozen for all time.当提交“出生”时,它知道它的父母是谁,但从那时起它就一直被冻结。 It cannot learn the "names" (hash IDs) of its children.它无法学习其子代的“名称”(哈希 ID)。 So the history, in a repository, works backwards .因此,存储库中的历史记录是反向的。

We find commits by starting from a later commit.我们从稍后的提交开始找到提交。 Each later points backwards to its parent.后面的每一个都向后指向其父级。 As long as we have no merge commits, we have a simple linear chain, like this:只要我们没有合并提交,我们就有一个简单的线性链,如下所示:

... <-F <-G <-H

Here H stands in for the real (big and ugly) hash ID of the last commit in the chain.这里H代表链中最后一个提交的真实(又大又丑)hash ID。 We have to know its hash ID somehow—and we'll come back to this in a moment—but assuming that we do know its hash ID, that's sufficient for Git to retrieve the commit from its big database of all the commits.我们必须以某种方式知道它的 hash ID - 我们稍后会回到这个问题 - 但假设我们确实知道它的 hash ID,这足以让 Z0BCC70105AD279503E51FE7B3F47B6 的所有提交从其大数据库中检索提交。

Having retrieved H , Git now has a snapshot—all the files that go with H —and some metadata.检索到H后,Git 现在有了一个快照——所有 go 和H的文件——以及一些元数据。 The metadata include the hash ID of earlier commit G .元数据包括早期提交G的 hash ID。 So Git can now reach back into its database and pull commit G out, and now it has another snapshot and more metadata.所以 Git 现在可以回到它的数据库并拉出提交G ,现在它有另一个快照和更多元数据。

By comparing the files in the two snapshots, G and H , Git can tell us which files did change, and which ones did not.通过比较两个快照中的文件GH , Git 可以告诉我们哪些文件发生变化,哪些没有。 (This goes pretty fast, too, because of the de-duplication. Files that aren't changed are shared , ie, the two commits refer to the same underlying file .) Git can look more closely at the files that did change, and show us what changed in those files . (这也很快,因为重复数据删除。更改的文件是共享的,即两个提交引用相同的底层文件。)Git 可以更仔细地查看确实更改的文件,并且向我们展示这些文件中发生了什么变化 That's how we normally view a commit: as changes since the previous commit.这就是我们通常如何看待提交:作为自上次提交以来的更改。 But Git doesn't store changes;但是 Git 不存储更改; it stores whole files, as a snapshot.它将整个文件存储为快照。

Having shown us H 's metadata and changes, Git can now step back one hop to commit G (whose hash ID it already retrieved).向我们展示了H的元数据和更改后,Git 现在可以后退一跳以提交G (它已经检索到其 hash ID)。 This of course is a commit, with snapshot and metadata.这当然是一个提交,带有快照和元数据。 Its metadata refers back to earlier commit F .它的元数据指的是较早的提交F So Git can now repeat what it just did with H , to show us commit G .所以 Git 现在可以重复它刚刚对H所做的事情,向我们展示提交G

Having shown commit G , Git can now move back one hop to commit F .显示提交G后,Git 现在可以后退一跳提交F It can show us F , and then move back one hop again.它可以向我们显示F ,然后再次向后移动一跳。 This continues until we get to the very first commit.这一直持续到我们到达第一个提交。 That first commit is special in exactly one way: it has no parent.第一次提交在一个方面很特别:它没有父级。 Its list of "previous commits" is empty.它的“先前提交”列表是空的。 This is how Git knows when to stop going backwards.这就是 Git 知道何时停止倒退的方式。 (In a big repository, you'll probably quit out of git log long before Git gets all the way back to the start, but that's fine too.) (在大型存储库中,您可能会在 Git 回到开始之前很久就退出git log ,但这也很好。)

There's one big problem here though.不过这里有一个大问题。 How did we find commit H ?我们如何找到提交H We said above that we just assume we have the hash ID saved somewhere.我们在上面说过,我们只是假设我们在某处保存了 hash ID。 Maybe we wrote it down on a scrap of paper, or on the office whiteboard, or whatever.也许我们把它写在一张纸上,或者写在办公室的白板上,或者其他什么地方。 But here's a better idea: we have a computer, running software with a database of commits.但这里有一个更好的主意:我们有一台计算机,运行带有提交数据库的软件。 Let's have a database of latest hash IDs too.让我们也有一个最新的 hash ID的数据库。 We can call these branch names .我们可以称这些分支名称

Branch names find commits and are updated by new commits分支名称查找提交并由新提交更新

A branch name like master or main , develop , feature , and so on simply holds one commit hash ID .mastermaindevelopfeature等分支名称只包含一个提交 hash ID The one hash ID stored in the branch name is the hash ID of the last commit in the chain .存储在分支名称中的一个 hash ID是链中最后一个提交的 hash ID。 So if we have:所以如果我们有:

...--F--G--H   <-- main

then commit H is, by definition, the latest commit on branch main .那么根据定义,提交H是分支main上的最新提交。

We can make more branch names.我们可以制作更多的分支名称。 Let's add the name develop , also pointing to commit H :让我们添加名称develop ,也指向提交H

...--F--G--H   <-- develop, main

We need some way, now, to know which name we're using—although whichever name we're using, we'll be working with commit H —so let's add the special all-caps name HEAD :现在,我们需要某种方法来知道我们正在使用哪个名称——尽管无论我们使用哪个名称,我们都将使用提交H所以让我们添加特殊的全大写名称HEAD

...--F--G--H   <-- develop, main (HEAD)

We're currently on branch main , because HEAD is attached to (or next to) main .我们目前on branch main ,因为HEAD附加到(或旁边) main If we git checkout develop or git switch develop , we get:如果我们git checkout developgit switch develop ,我们得到:

...--F--G--H   <-- develop (HEAD), main

We're still using commit H , so nothing else has changed, but we're using it through the name develop .我们仍在使用提交H ,所以没有其他任何改变,但我们通过名称develop使用它。

When we make a new commit—I'll skip entirely over most of the details of Git's index aka staging area here—we run git commit and Git:当我们进行新的提交时——我将在这里完全跳过 Git索引(即暂存区)的大部分细节——我们运行git commit和 Git:

  • gathers metadata, such as your name and email address and a log message;收集元数据,例如您的姓名和 email 地址和日志消息;
  • uses HEAD to find the current commit's hash ID H ;使用HEAD查找当前提交的 hash ID H
  • writes out a snapshot of all the files (de-duplicated) to go into the new commit;将 go 的所有文件(已删除重复)的快照写入新提交;
  • writes out the metadata, creating the new commit itself and getting a new unique hash ID;写出元数据,创建新的提交本身并获得一个新的唯一 hash ID; and
  • writes the hash ID into the name to which HEAD is attached.将 hash ID 写入HEAD所附加的名称中。

So now that we've made a new commit I , new commit I points back to existing commit H .所以现在我们已经做了一个新的提交I ,新的提交I指向现有的提交H And because HEAD is attached to develop , the name develop now points to the new commit I .并且因为HEADdevelop相关联,因此名称develop现在指向新的提交I The name main still points to commit H :名称main仍然指向提交H

...--F--G--H   <-- main
            \
             I   <-- develop (HEAD)

Nothing else changes: commit H doesn't change (it does not point forwards to I ; I points backwards to H instead).没有其他改变:提交H没有改变(它没有向前指向II向后指向H )。 HEAD is still attached to develop . HEAD仍然依附于develop The only changes are that we have a new commit I , with new metadata and snapshot, and that new commit I 's hash ID is stored in develop now.唯一的变化是我们有一个新的提交I ,带有新的元数据和快照,并且新提交I的 hash ID 现在存储在develop中。

Suppose you now make your own new branch name fix-123 , and switch to that branch:假设您现在创建自己的新分支名称fix-123 ,并切换到该分支:

...--F--G--H   <-- main
            \
             I   <-- develop, fix-123 (HEAD)

Now you make two new commits J and K :现在你做了两个新的提交JK

...--F--G--H   <-- main
            \
             I   <-- develop
              \
               J--K   <-- fix-123 (HEAD)

Now let's say that someone else has made a new commit for develop .现在假设其他人对develop做了一个新的提交。 You git checkout develop or git switch develop to get:git checkout developgit switch develop得到:

...--F--G--H   <-- main
            \
             I   <-- develop (HEAD)
              \
               J--K   <-- fix-123

Then you obtain their new commit ( git fetch + git merge , perhaps, or git pull if you use the shorthand all-in-one command that works about as well as all-in-one washer/dryer combinations for instance), so now you have:然后你获得他们的新提交( git fetch + git merge ,也许,或者git pull如果你使用速记的一体式命令,那么它适用于实例,现在和干燥器组合)你有:

...--F--G--H   <-- main
            \
             I--L   <-- develop (HEAD)
              \
               J--K   <-- fix-123

It's now time for rebase.现在是 rebase 的时候了。

Rebasing is copying变基是复制

We'll stop drawing in main now, and just use:我们现在将停止在main中绘制,只需使用:

...--I--L   <-- develop (HEAD)
      \
       J--K   <-- fix-123

to make things a bit more compact.使事情更紧凑。 Our problem now is commits JK .我们现在的问题是提交JK There's nothing really wrong with them, except... well, the problem is that commit J has, as its parent, commit I .它们并没有什么问题,除了......好吧,问题是提交J作为其父级,提交I We'd like a commit that has commit L as its parent.我们想要一个以提交L作为其父级的提交。

Nothing about any existing commit can ever change.任何现有的提交都不会改变。 We can't fix commit J .我们无法修复提交J But we can make a new commit that is very much like J , only different.但是我们可以做出一个非常J提交,只是不同而已。 We can do the same with commit K , too.我们也可以对提交K做同样的事情。 What we want to get is this:我们想要得到的是这样的:

          J'-K'  <-- new-and-improved-fix-123 (HEAD)
         /
...--I--L   <-- develop
      \
       J--K   <-- old-and-lousy-fix-123

Here J' is our copy of J , and K' is our copy of K .这里J'是我们的J副本,而K'是我们的K副本。 There are two things different in J vs J' . J vs J'有两点不同。 There are two things different in K vs K' too. K vs K'也有两点不同。 In particular, both copies have a different parent commit, which we can see from the drawing.特别是,两个副本都有不同的提交,我们可以从图中看到。 Both copies also have any differences needed in their snapshots, being based on the snapshot that's in L instead of the snapshot that is in I .两个副本的快照有任何差异,基于L中的快照而不是I中的快照。

To get here, from where we are, we need to:为了到达这里,从我们所在的地方,我们需要:

  • list out the hash IDs of the commits that we want to copy, J and K ;列出我们要复制的提交的 hash ID, JK
  • make a new branch name at commit L ;在提交L处创建一个新的分支名称;
  • check out that new branch name;检查新的分支名称;
  • copy the first commit J ;复制第一个提交J and
  • copy the second commit K .复制第二个提交K

When we're done with all of that, we have the new diagram, and all we have to do now is fix up the branch names .当我们完成所有这些后,我们有了新的图表,我们现在要做的就是修复分支名称

There's a way to do this manually, and it's not even all that hard:有一种手动执行此操作的方法,甚至不是那么难:

git checkout -b new-fix-123 develop
git cherry-pick <hash-of-J>
git cherry-pick <hash-of-K>

We can make this even shorter:我们可以让它更短:

git checkout -b new-fix-123 develop
git cherry-pick <hash-of-J> <hash-of-K>

reduces this to two commands.将其简化为两个命令。 But then we still need to move the fix-123 name to where we are now, and check out fix-123 again:但是我们仍然需要将fix-123名称移动到我们现在所在的位置,并再次检查fix-123

git checkout -B fix-123

would do that, and then we can delete new-fix-123 and we'll have:会这样做,然后我们可以删除new-fix-123 ,我们将拥有:

          J'-K'  <-- fix-123 (HEAD)
         /
...--I--L   <-- develop
      \
       J--K   <-- ???

Note that there is no longer any name by which to find commit K .请注意,不再有任何名称可以用来查找提交K We forced Git to move the name fix-123 to point to K' .我们强制 Git 将名称fix-123移动到指向K' The old commits still exist.旧的提交仍然存在。 We just can't find them any more.我们再也找不到他们了。

The git rebase command does this all in one step git rebase命令一步完成

Again, we're starting with:同样,我们从以下开始:

...--I--L   <-- develop (HEAD)
      \
       J--K   <-- fix-123

Running:跑步:

git checkout fix-123
git rebase develop

has Git:有 Git:

  • list out commits that are "on" fix-123 , but not "on" develop : that's hash IDs J and K .列出“on” fix-123但不是“on” develop的提交:那是 hash IDs JK Git actually generates this list backwards—because Git always works backwards—but git rebase then reverses the backwards list, so that it's forward. Git 实际上是向后生成此列表 - 因为 Git 总是向后工作 - 但git rebase然后反转向后列表,使其向前。

  • Create a temporary "branch" at commit L .在提交L处创建一个临时“分支”。 Git uses detached HEAD mode for this, rather than bothering with a branch name. Git 为此使用分离的 HEAD模式,而不是使用分支名称。 We'll skip the details here, but they matter if something goes wrong.我们将在此处跳过详细信息,但如果出现问题,它们很重要。

  • Run a git cherry-pick for each commit in the list.为列表中的每个提交运行git cherry-pick

  • Force the branch name we were on— fix-123 —to here and check it out again.将我们所在的分支名称 — fix-123 — 强制到此处并再次检查。

That's exactly what we'd do manually, but Git does it all automatically.这正是我们手动执行的操作,但 Git 会自动完成所有操作。 As long as nothing goes wrong, we end up with what we wanted.只要没有出错,我们最终就会得到我们想要的。 The real trick here is recovering from failures.这里真正的诀窍是从失败中恢复。

What could go wrong? go 会出现什么问题?

"Copying" a commit—with cherry-pick, or with more primitive methods that git rebase used to use in older versions of Git— can fail. “复制”一个提交——使用cherry-pick,或者使用git rebase在旧版本 Git 中使用的更原始的方法——可能会失败。 In particular, each git cherry-pick operation:特别是每个git cherry-pick操作:

  • has to figure out what changed, then必须弄清楚发生了什么变化,然后
  • has to figure out how to apply those changes here, to the other commit.必须弄清楚如何在此处将这些更改应用于另一个提交。

Technically speaking, what Git does to achieve this is to use its merge engine .从技术上讲,Git 所做的就是使用它的合并引擎 This usually works pretty well, but it can stop with a merge conflict.这通常工作得很好,但它可能会因合并冲突而停止。 When it does, you must resolve the conflict, then continue the rebase.当它发生时,您必须解决冲突,然后继续变基。

When Git goes to figure out which commits to copy, sometimes you don't get the set of commits you expected.当 Git 去确定要复制的提交时,有时您没有得到预期的提交集。 You can use git rebase --onto to help out here, but I'm not going to say anything more in this answer.您可以在这里使用git rebase --onto来提供帮助,但我不会在这个答案中多说什么。 If you have a set of commits that includes any merge commits, they complicate matters.如果您有一组包含任何合并提交的提交,它们会使事情复杂化。 I'm not going to cover them at all here.我根本不打算在这里介绍它们。 Git does now (as of 2.22) have a --rebase-merges option that can make this work, but it's a bit tricky. Git 现在(从 2.22 开始)有一个--rebase-merges选项可以完成这项工作,但这有点棘手。

Finally, if a rebase does go wrong and you wish you hadn't started it in the first place... well, if you're stuck in the middle of a failing rebase, you can use git rebase --abort :最后,如果一个 rebase 错误go并且你希望你没有首先启动它......好吧,如果你被困在失败的 rebase 中间,你可以使用git rebase --abort

          J'  <-- HEAD
         /
...--I--L   <-- develop
      \
       J--K   <-- fix-123

When the copying of K fails, perhaps because there's a conflict with L , and you decide you'd prefer to be back to this:当复制K失败时,可能是因为与L发生冲突,并且您决定更愿意回到这个:

          J'  [abandoned]
         /
...--I--L   <-- develop
      \
       J--K   <-- fix-123 (HEAD)

a simple git rebase --abort suffices.一个简单的git rebase --abort就足够了。 But if you've let the rebase finish, or worked on the conflicts and continued the rebase and are now at:但是,如果您已经让 rebase 完成,或者解决了冲突并继续 rebase 并且现在处于:

          J'-K'  <-- fix-123 (HEAD)
         /
...--I--L   <-- develop
      \
       J--K   [abandoned]

and decide that the whole thing was a mistake, you need to find the hash ID of original commit K in order to recover.并确定整个事情是一个错误,您需要找到原始提交K的 hash ID才能恢复。

There is a way to do this, using git reflog .有一种方法可以做到这一点,使用git reflog But it's a pain.但这是一种痛苦。 Fortunately, there's a much easier way .幸运的是,有一个更简单的方法 If you're about to start a rebase, and are not sure you want to use the result or stick with the original, just create a new branch before you start:如果您即将开始一个 rebase,并且不确定要使用结果还是坚持原来的,只需在开始之前创建一个新分支

...--I--L   <-- develop
      \
       J--K   <-- fix-123.0, fix-123 (HEAD)

Now after your rebase, you will have:现在,在你的 rebase 之后,你将拥有:

          J'-K'  <-- fix-123 (HEAD)
         /
...--I--L   <-- develop
      \
       J--K   <-- fix-123.0

The old series of commits ending at K are still easy to find, using branch name fix-123.0 .K结尾的旧系列提交仍然很容易找到,使用分支名称fix-123.0 2 If I find myself rebasing again, I make a new fix-123.1 before I start. 2如果我发现自己再次变基,我会在开始之前制作一个新的fix-123.1 So fix-123 is the current one and the numbered ones are the previous ones, there if I want them, delete-able once I'm sure I am done with them.所以fix-123是当前的,编号的是以前的,如果我想要它们,一旦我确定我完成了它们,就可以删除它们。


2 With older computer folks like me, you can often tell whether we came out of the maths department or the physics / engineering department by whether we start counting from zero. 2对于像我这样的计算机老手,您通常可以通过我们是否从零开始数数来判断我们是从数学系还是物理/工程系出来的。 I kind of did both, but my heart was a little more with the mathematicians.我两者都做过,但我的心更多地与数学家在一起。 Sometimes I think I should make these names more detailed, eg, have dates on them, but simple numbering seems to work pretty well.有时我想我应该把这些名字写得更详细一些,例如,上面有日期,但简单的编号似乎效果很好。 I rarely get higher than about 3 or 4.我很少会高于 3 或 4。

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

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