如何更改常见历史记录中的提交?

时间:2016-07-14 08:32:47

标签: git git-rebase

假设我有以下历史记录:

_typeSpecificSerializer

我想修改提交 --E <- branch y / A---B---C---D <- branch x ,例如添加提交B并使用B2将其压缩到B

历史应该是这样的:

git rebase -i

我的问题是:我该怎么做?

我尝试在 --E' <- branch y / A---B'--C'--D' <- branch x E之后提交并重新定位,但结果是:

D

解决方法是将 --B'--C'--E' <- branch y / A---B---C---D <- branch x 重新定位到E;然后我可以转到D,添加并压缩E',结果

B2

我可以将分支x指向 -E' <- branch y / A---B'--C'--D' \ --B---C---D <- branch x

D'

几乎类似于我想要实现的东西,但感觉有点 hacky 因为我手动移动分支指针。 (在我的特殊情况下,rebase是可以接受的,但我想知道一般情况。) 如果主要问题没有简单的解决方案,我想知道是否可以在不手动移动分支指针的情况下解决此问题。

其他信息:尚未推送任何相应的提交。

4 个答案:

答案 0 :(得分:1)

  1. 在分支X上使用git rebase -i并编辑您的提交B
  2. (在提交旁边设置e,使用git commit --amend然后git rebase --continue

    1. 使用分支X
    2. 重新分支您的分支Y.

      (当你在Y分支时,使用git rebase Y

      1. 删除提交D
      2. (只重置最后两次提交和git cherry-pick E提交)

答案 1 :(得分:1)

  

如何修改远程提交,不要丢失以下提交

  1. 回滚到B
  2. Implimed B2承诺B
  3. 应用C提交
  4. Stitch to branch_y
  5. 合并新的B2和C提交
  6. 推送更新分支
  7. 切换回branch_x
  8. 应用D commit
  9. 使用force
  10. 推送分支
    git reset B_HASH
    git commit B2 --amend
    git cherry-pick C_HASH
    
    git checkout branch_y
    git merge branch_x
    git push origin branch_y
    
    git checkout branch_x
    git cherry-pick D__HASH
    git push origin branch_x -f
    

    <强>更新

    其他信息:尚未推送任何相应的提交。

    如果是这样,那么您不需要使用推送

    的所有步骤

    git commit --amend

      

    通过创建新提交替换当前分支的提示。该   记录的树像往常一样准备(包括-i和。的效果)   -o options和explicit pathspec),来自原始提交的消息用作起始点,而不是空消息,   当没有通过选项从命令行指定其他消息时   例如-m,-F,-c等。新提交具有相同的父母和   作者是当前的作者(--reset-author选项可以反击   这一点)。

    git cherry-pick

      

    给定一个或多个现有提交,每个提交应用更改   介绍,记录每个提交的新提交。这需要你的   工作树要干净(没有HEAD提交的修改)。

    git push -f

      

    通常,该命令拒绝更新不是的远程引用   用于覆盖它的本地ref的祖先。还有,何时   使用--force-with-lease选项,该命令拒绝更新当前值与预期值不匹配的远程ref。

         

    此标志禁用这些检查,并可能导致远程存储库   失去承诺;小心使用它。

         

    请注意, - force适用于所有推送的引用,因此使用   将push.default设置为匹配或多次推送   配置了远程。* .push的目的地可能会覆盖其他的refs   比当前分支(包括严格落后的本地裁判)   他们的远程对手)。要强制推送到一个分支,请使用+   在refspec前面推(例如git push origin + master to force   推向主分支)。请参阅上面的...部分   的信息。

答案 2 :(得分:1)

使用--fixup--autosquash以及rebase --onto

#!/bin/bash
set -eu

t-a-c () {
    touch "$1"
    git add "$1"
    git commit -m "$1"
}

cd "$1"
git init

t-a-c A

git checkout -b x
git branch -d master

t-a-c B
t-a-c C

git branch y
t-a-c D

git checkout y
t-a-c E

git checkout @~2
git checkout -b z
echo "B'" > B
git add B
git commit --fixup @

git checkout x
git rebase --onto z z~

git rebase -i --autosquash z~2

git checkout y
git rebase --onto x~ x~2

git branch -D z

git log --oneline --graph --decorate --all

输出:

* a92a035 (HEAD -> y) E
| * d5c169a (x) D
|/  
* 0a2da9c C
* 2b0087e B
* b395d3a A

答案 3 :(得分:1)

一个简单的解决方案是首先在其中一个分支上执行交互式rebase,进行更改,然后将另一个分支重新绑定到新的C'

git checkout branch_x

git rebase -i A
# mark commit B as edit, modify it, and complete the rebase

# rebase branch_y to be based on the new C' instead of C
git rebase --onto C' C branch_y

因为我们告诉branch_y最初基于C的{​​{1}}被重新定位到新C',我们会根据修改后的提交恢复分支的原始分支结构。< / p>

请注意,我们需要知道C和新C'的提交哈希值。在我们执行第二个rebase命令之前,我们必须在第一个分支上的交互式rebase之后查找它们。

另一个避免必须知道提交哈希的解决方案是在这里进行合并保留交互式rebase。请注意,这要求您首先合并这两个分支。但是我们只为Git做这个以保持分支关系,所以之后我们可以再次摆脱这种合并。

所以要做到这一点,我们从任何分支开始,合并另一个分支。然后我们执行合并保留交互式rebase来修改提交B(以我们想要的任何方式)。之后,Git将正确地重放这些分支(包括合并),因此我们最终得到了这段历史:

A -- B' -- C' -- D' ---- M'  ← branch
            \           /
             \         /
              E' ------

然后我们可以将分支指针移动到更新的提交D'E',我们就完成了。

git checkout branch_x
git merge branch_y

# merge preserving interactive rebase
git rebase -p -i A
# mark commit B as edit, modify it, and complete the rebase

# we’re now on M', so move branch pointers to the new commits
git update-ref refs/heads/branch_y HEAD^2
git reset --hard HEAD^

历史现在应该是这样的:

A -- B' -- C' -- D'  ← branch_x
            \
             \
              E'  ← branch_y

不幸的是,我们必须在这里手动移动分支指针,因为我们一次只能重新绑定一个分支。因为我们已经为另一个分支重新设定了历史记录(因为合并),我们仍然需要移动它的指针。所以我们接受我们必须手动重置分支(这无论如何都不是坏事)。