如何仅重新恢复特定的提交?
当我做git rebase -i< commit>
时,它会从该提交开始提取提交列表,我必须选择我想通过更改pick
来编辑的提交。到e
。但是,当我将选择
更改为e
,然后关闭编辑器git仍会通过所有提交进行迭代,而不仅仅是我要编辑的内容。
例如,我做git rebase -i -root
,只选择编辑最新的提交。 Git仍然尝试通过整个提交列表进行迭代。关闭编辑器后,它说重新打开(1/593)
其中593是列表中的提交数量。它遍历了所有593人。它只会让我编辑我选择的那些。
即使没有rebase
遍历整个列表,也有没有一种方法可以仅针对特定的提交?
When I do git rebase -i <commit>
it pulls up a list of commits starting from that commit and I have to choose which commits I want to edit by changing pick
to e
. But when I change pick
to e
and close out the editor git still iterates through all the commits and not just the ones I want to edit.
For example, I do git rebase -i --root
and only choose to edit the latest commit made. Git still tries to iterate through the entire list of commits. After I close out the editor it says Rebasing (1/593)
where 593 is the number of commits in the list. It goes through all 593 them. It only stops to let me edit the ones I chose.
Is there a way to target only a specific commit, even if it's in between a lot of other commits, without having rebase
go through the entire list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
理解这一点的方法是了解什么是是。 GIT遵循一些非常基本和重要的规则。这是其中两个:
永远不会更改提交。
提交的父指针是该提交的一部分(因此,根据规则1,无法更改)。
因此,请考虑以下情况:
时间从左到右流动:A首先创建了A,并且是B的父母,它是C的父母,它是D的父母。
现在我想更改A好吧,我不能!您不能改变任何关于提交的内容。但是,您的 can 做的是替换 a,不同的 commit-一个具有不同的提交消息(但包含相同的文件)的 commit。
但是,如果您这样做,那么您就有这样的:
a是一个像a一样的新提交,但在其提交信息中有所不同。这不是很好,因为这不是我们想要的。我们希望历史保持“相同”,而A'与B中的父母保持在一起。好吧,我们不能那样做!您不能更改B的额外款。但是您的 can do是替换 b,用a new 提交看起来 em>喜欢B,但有A'作为父母:
但是,还有更多!我们必须继续这样做,对于后续的所有提交。当我们完成后,git简单地移动
myBranch
指针指向新历史记录:是您使用Interactive rebase编辑A的提交消息时会发生的。 的所有新提交以及之后的所有提交。
这正是您所看到和询问的。
要查看这是真的,请在示例回购中尝试一下,然后观看SHA数字。这是一个例子。我使用
git log
来查看我一开始的内容:现在我的互动式折叠为根;以下是我编辑todo列表的方式:
我将第一个提交重新命名,以便它的消息为
a具有不同的提交消息
。现在,篮板完成了,这就是我得到的:查看SHA数字。 他们都更改了。那是因为它们是我开始的!
最后一个观察。如果您仔细观看,您应该说:在图中,原始 a Thru t thru t thru t thru d ther d the of被“替换”的情况会发生什么?
看起来他们仍然在那里。是的,你是对的!他们仍然在那里。大重新重新构想之后,您的所有提交都是重复的。新版本存在,也是旧版本。这实际上是git的一个非常酷的功能:更换时,consits 未删除。
在这种特殊情况下,您没有简单的方法可以访问原始D。但是,如果您愿意的话,您可以。例如,您可以使用回流。或者,您可以在进行重新启动之前在D上放置另一个分支名称。
最终,存储库将被“收集垃圾”。 git会注意到, 指向d,因此指向C,b和A。它们被认为是“无法实现的”,而git 将删除它们。但这可能是周之前。如果您想做的话,您有很多时间恢复原件。酷,是吗?
The way to understand this is to understand what Git is. Git follows some extremely basic and important rules. Here are two of them:
No commit can ever be changed.
The parent pointer of a commit is part of that commit (and therefore, in accordance with rule 1, cannot be changed).
So now consider this situation:
where time flows from left to right: A was created first, and is the parent of B, which is parent of C, which is parent of D.
Now let's say I want to change the commit message of A. Well, I can't! You can't change anything about a commit. But what you can do is replace A with a different commit — one that has a different commit message (but contains the same files).
But if you do that, you have this:
where A' is the new commit that is like A, but differs in its commit message. This is no good, because it isn't what we wanted. We want the history to stay "the same", with A' as the parent of B in the history. Well, we can't do that! You can't change the parentage of B. But what you can do is replace B with a new commit that looks like B but has A' as its parent:
But wait, there's more! We have to keep doing that, for all the subsequent commits. And when we get done, Git simply moves the
mybranch
pointer to the new history:That is what happens when you use interactive rebase to edit the commit message of A. You get all new commits for A and all the commits after it.
And that is exactly what you are seeing and asking about.
To see that this is true, try it on an example repo, and watch the SHA numbers. Here's an example. I use
git log
to see what I have at the start:Now I interactive rebase down to the root; here's how I edit the todo list:
I reword the first commit so that its message is
a with a different commit message
. Now the rebase finishes, and this is what I get:Look at the SHA numbers. They have all changed. That's because these are not the same commits I started with! They have all been replaced.
One final observation. If you're watching carefully, you should be saying: In the diagram, what happens to the original A thru D that have been "replaced"?
It looks like they are still there. Yes, you're right! They are still there. After your big rebase, all your commits are duplicated. The new versions exist, and so do the old versions. This is actually a really cool feature of Git: commits are not erased when they are replaced.
In this particular situation, you have no easy way to access the original A thru D. But you could if you wanted to. For example, you could use the reflog. Or you could have put another branch name on D before doing the rebase.
Eventually, the repo will be "garbage collected". Git will notice that no branch name points to D, and therefore to C, B, and A. They are considered "unreachable", and Git will delete them. But it could be weeks before that happens. You have lots of time to recover the originals if that's what you want to do. Cool, eh?
如何仅重新列入特定的提交
在调用中尽可能狭窄以编辑历史记录:
git Commit -amend
git rebase -i head〜4
git commit -i&lt; sha1&gt;
为什么要缩小
盲目
git rebase -i -root
操作很重要,这实际上是一件危险的事情。无害的问题,绩效:如果您要求rebase重新创建所有提交的所有提交,它将需要一个一个人来重新创建每个提交,但是由于结果是相同的只是重新创建了完全相同的提交,只是浪费了您的机器的时间。这就是您要观察到的(1/593)。
危险的问题,破坏合并:如果您的历史有任何合并,对它们进行重新估算实际上会默认地跳过它们,以具有相同代码(我相信)的线性历史记录代替原始历史记录(我相信)现在,从跳过的第一次合并开始,与原始历史截断了。您可以使用
git rebase -i -rebase -merges -root
,但是为什么您会无所作为呢?How to rebase only specific commits
Be as narrow as you can in your call to edit the history:
git commit --amend
git rebase -i HEAD~4
git commit -i <sha1>
Why it's important to be narrow
A blind
git rebase -i --root
operation is actually a dangerous thing to do.Innocuous issue, performance: if you ask rebase to recreate all the commits identically, it will take the commits one by one and recreate each of them, but since the result is identical it's a noop, you've just recreated the exact same commits, only wasting your and your machine's time doing it. This is what you're observing with that (1/593).
Dangerous issue, destroying merges: if your history has any merges in it, rebasing over them will actually skip them by default, replacing the original history with a linear history that has the same code (I believe) but is now disconnected from the original history starting at the first merge that got skipped. You can use
git rebase -i --rebase-merges --root
instead, but why would you do all that work for nothing?