Git:如何重新定位到特定的提交?

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

Git: How to rebase to a specific commit?

gitversion-controlrebasegit-rebase

提问by Ondra ?i?ka

I'd like to rebase to a specific commit, not to a HEAD of the other branch:

我想重新定位到特定的提交,而不是另一个分支的 HEAD:

A --- B --- C          master
 \
  \-- D                topic

to

A --- B --- C          master
       \
        \-- D          topic

instead of

代替

A --- B --- C          master
             \
              \-- D    topic

How can I achieve that?

我怎样才能做到这一点?

采纳答案by Adam Dymitruk

You can avoid using the --onto parameter by making a temp branch on the commit you like and then use rebase in its simple form:

您可以通过在您喜欢的提交上创建临时分支来避免使用 --onto 参数,然后以简单的形式使用 rebase:

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp

回答by r0hitsharma

You can even take a direct approach:

你甚至可以采取直接的方法:

git checkout topic
git rebase <commitB>

回答by Adam Dymitruk

Use the "onto" option:

使用“onto”选项:

git rebase --onto master^ D^ D

回答by Nestor Milyaev

The comment by jsz above saved me tons of pain, so here's a step-by-step recipie based on it that I've been using to rebase/move any commit on top of any other commit:

上面 jsz 的评论为我节省了大量的痛苦,所以这里有一个基于它的分步指南,我一直在使用它来重新定位/移动任何提交到任何其他提交之上:

  1. Find a previous branching point of the branch to be rebased (moved) - call it old parent. In the example above that's A
  2. Find commit on top of which you want to move the branch to - call it new parent. In the exampe that's B
  3. You need to be on your branch (the one you move):
  4. Apply your rebase: git rebase --onto <new parent> <old parent>
  1. 找到要重新定位(移动)的分支的先前分支点 - 将其称为旧父节点。在上面的例子中是A
  2. 找到要将分支移动到的提交 - 将其称为新父级。在B的例子中
  3. 你需要在你的分支上(你移动的那个):
  4. 应用您的变​​基: git rebase --onto <new parent> <old parent>

In the example above that's as simple as:

在上面的例子中,这很简单:

   git checkout topic
   git rebase --onto B A

回答by Isaac Brown

Topic Solution

话题解决方案

The correct command to answer the posted question could be any of the following (assuming branch topicis already checked out):

回答发布的问题的正确命令可能是以下任何一个(假设分支topic已经签出):

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

If topicis not checked out, you simply append topicto the command (except the last one) like so:

如果topic未签出,您只需附加topic到命令(最后一个除外),如下所示:

git rebase --onto B master topic

Alternatively, check out the branch first with:

或者,首先检查分支:

git checkout topic

Rebase Any String of Commits to a Target Commit

将任何提交字符串变基为目标提交

The basic form of the command we need, cribbed from the documentation, is:

我们需要的命令的基本形式来自文档,是:

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch>is optional and all it does is checks out the branch specified before executing the rest of the command. If you've already checked out the branch you want to rebase, then you don't need this. Note that you must have specified <Upstream>in order to specify <Branch>or git will think you are specifying <Upstream>.

<Branch>是可选的,它所做的只是在执行命令的其余部分之前检查指定的分支。如果您已经签出要变基的分支,那么您不需要这个。请注意,您必须指定<Upstream>才能指定,<Branch>否则 git 会认为您正在指定<Upstream>.

<Target>is the commit we will attach our string of commits to. When providing a branch name, you are simply specifying the head commit of that branch. <Target>can be any commit that won't be contained in the string of commits being moved. For example:

<Target>是我们将提交的字符串附加到的提交。提供分支名称时,您只需指定该分支的头部提交。<Target>可以是任何不会包含在被移动的提交字符串中的提交。例如:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

To move the entire feature branch, you can not select X, Y, Z, or featureas the <Target>since those all are commits inside the group being moved.

要移动整个功能分支,您不能选择X, Y, Z, 或featureas<Target>因为这些都是被移动的组内的提交。

<Upstream>is special because it can mean two different things. If it is a commit that is an ancestor of the checked out branch, then it serves as the cut point. In the example I provided, this would be anything that isn't C, D, or master. All commits after <Upstream>until the head of the checked out branch are the ones that will be moved.

<Upstream>很特别,因为它可能意味着两个不同的东西。如果提交是检出分支的祖先,则它作为切点。在我提供的例子,这将是任何不是CDmaster<Upstream>在检出分支的头部之前的所有提交都是将被移动的提交。

However, if <Upstream>is not an ancestor, then git backs up the chain from the specified commit until if finds a common ancestor with the checked out branch (and aborts if it can't find one). In our case, an <Upstream>of B, C, D, or masterwill all result in commit Bserving as the cut point. <Upstream>is itself an optional command and if it is not specified, then git looks at the parent of the checked out branch which is the equivalent of entering master.

但是,如果<Upstream>不是祖先,则 git 从指定的提交备份链,直到找到具有检出分支的共同祖先(如果找不到,则中止)。在我们的例子中,<Upstream>of B, C, D, ormaster都会导致提交B作为切点。<Upstream>本身是一个可选命令,如果未指定,则 git 查看已检出分支的父级,这相当于输入master.

Now that git has selected the commits it will cut and move, it applies them in order to <Target>, skipping any that are already applied to target.

既然 git 已经选择了它将剪切和移动的提交,它会按顺序应用它们<Target>,跳过任何已经应用到目标的提交。

Interesting Examples and Results

有趣的例子和结果

Using this starting point:

使用这个起点:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    Will apply commits B, C, X, Y, Zto commit Dand end up skipping Band Cbecause they already have been applied.

  • git rebase --onto C X feature
    Will apply commits Yand Zto commit C, effectively deleting commit X

  • git rebase --onto D A feature
    将应用 commits B, C, X, Y,Z提交D并最终跳过BC因为它们已经被应用。

  • git rebase --onto C X feature
    将应用提交YZ提交C,有效地删除提交X

回答by Zack Morris

Since rebasing is so fundamental, here's an expansion of Nestor Milyaev's answer. Combining jsz'sand Simon South'scomments from Adam Dymitruk's answeryields this command which works on the topicbranch regardless of whether it branches from the masterbranch's commit Aor C:

由于变基是如此基础,这是Nestor Milyaev 答案的扩展。结合jszSimon SouthAdam Dymitruk 的回答中评论,可以生成此命令,该命令适用于topic分支,无论它是从master分支的提交分支A还是分支C

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

Note that the last argument is required (otherwise it rewinds your branch to commit B).

请注意,最后一个参数是必需的(否则它会将您的分支倒带到 commit B)。

Examples:

例子:

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

So the last command is the one that I typically use.

所以最后一个命令是我通常使用的命令。

回答by Number945

A simpler solution is git rebase <SHA1 of B> topic. This works irrespective of where your HEADis.

一个更简单的解决方案是git rebase <SHA1 of B> topic。无论您身在何处,这都有效HEAD

We can confirm this behaviour from git rebase doc

我们可以从git rebase doc确认这种行为

<upstream>Upstream branch to compare against. May be any valid commit, not just an existing branch name. Defaults to the configured upstream for the current branch.

<upstream>上游分支进行比较。可能是任何有效的提交,而不仅仅是现有的分支名称。默认为当前分支配置的上游。



你可能会想,如果我topictopic在上面的命令中提到 SHA1 会发生什么?

git rebase <SHA1 of B> <SHA1 of topic>

git rebase <SHA1 of B> <SHA1 of topic>

This will also work but rebase then won't make Topicpoint to new branch so created and HEADwill be in detached state. So from here you have to manually delete old Topicand create a new branch reference on new branch created by rebase.

这也将起作用,但 rebase 然后不会Topic指向如此创建的新分支,并且HEAD将处于分离状态。所以从这里你必须手动删除旧的Topic并在由 rebase 创建的新分支上创建一个新的分支引用。

回答by malat

I've used a mixture of solutions described above:

我使用了上述解决方案的混合物:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

I found it much easier to read and understand. The accepted solution lead me to a merge conflict (too lazy to fix by hand):

我发现它更容易阅读和理解。接受的解决方案导致我发生合并冲突(懒得手动修复):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

回答by Talha Ashraf

There is another way of doing it or if you wish to move back to more than just one commit.

还有另一种方法可以做到,或者如果您希望回到不止一个提交。

Here is a an example to move back to nnumber of commits:

这是一个返回到n提交次数的示例:

git branch topic master~n

For the sake of this question, this can also be done:

对于这个问题,也可以这样做:

git branch topic master~1

The command works perfectly on git version 2.7.4. Haven't tested it on any other version.

该命令在git version 2.7.4. 没有在任何其他版本上测试过。