寻找变基点

Find rebase point

假设我有这个:

I1 -- I2 -- I3 
 \            \
  F1 -- F2 -- ? -- F3 -- F4 -- F5

我创建了一个新的功能分支 F,提交了 F1 和 F2,然后我想合并来自集成分支的更改以防止冲突。

我也是:

git fetch origin I
git checkout F
git rebase origin/I

所以现在应该是这样的:

I1 -- I2 -- I3
               \
               F1 -- F2 -- F3 -- F4 -- F5

我的问题是 - 现在我想将提交 F1-F5 压缩为一个提交。我怎样才能安全地压缩提交?

我可以git reset --soft x,但是x是什么?我怎样才能找到要返回的提交?我不想丢失集成分支的任何历史记录。

在英语中,我想这将是我的分支中不在集成分支中的最旧的提交,而且该提交比集成分支中的任何提交都年轻。 (?) 如果我执行 git merge 而不是 git rebase(偶然),则可能会发生后一种情况。

如果您想通过软重置来压缩,请执行以下操作:

git reset --soft HEAD~5

这会将 HEAD 指针从 F5 的当前位置移回 I3 提交。但是,软重置 不会 触及工作目录和阶段。因此,最终效果是您的阶段将反映 5 F 次提交。然后,当您提交时,您将有效地将这 5 次提交压缩为一次:

git commit -m 'squashed 5 F commits'

这给你留下了:

I1 -- I2 -- I3 -- C

作为替代方案,您也可以进行交互式变基:

git rebase -i HEAD~5

您可以将每个要压缩的提交从 pick 更改为 squash,然后完成变基。

TL;DR

试试 git fetch && GIT_SEQUENCE_EDITOR="sed -i '' 's/^pick/squash/'" git rebase -i @{u}(你可以把它压缩成别名,shell 或 Git-to-shell)。

考虑以下几点:当您 运行 git rebase 时, 您告诉 git rebase 将副本 放在哪里。也就是说,你运行:

git checkout $branch
git rebase $onto

其中 $branch 是您的分支名称,$onto 是指定如何进行变基的东西。由于副本 之后 $onto 指定的提交,$onto 自动成为您的 git reset --soft.

的正确点

如果你有git pull --rebase运行git rebase,你在这里放弃对$onto的直接控制。 git pull 命令首先 运行s git fetch $remote for some $remote,然后使用 git fetch 记录(在 $GIT_DIR/FETCH_HEAD 中)的提取信息作为 $onto 参数.

由于分叉点代码,这里有点额外的复杂性,但在现代 Git 中,您的优势是 git fetch 将更新 $upstream,其中 $upstream 是当前分支的上游,之后 git rebase 将使用 $upstream 并自动完成所有分支点的工作,因此 $upstream 仍然是正确的。在这种情况下,使用:

. git-sh-setup
branch=$(git symbolic-ref -q --short HEAD) || die 'not currently on a branch'
remote=$(git config --get branch.$branch.remote) || die 'current branch has no upstream'
git fetch $remote && git rebase || die 'fetch or rebase failed'
git reset --soft $upstream && git commit

作为您的脚本(例如,在您的 $PATH 中命名为 git-rebase-and-squash,在 git rebase-and-squash 中命名为 运行)通常可以解决问题。

不过,与其直接使用 reset --softgit commit,不如将最后一行改为:

GIT_SEQUENCE_EDITOR="sed -i '' 's/^pick/squash/'" git rebase -i $upstream

这将为您将所有 pick 转换为 squash,在这种情况下,您甚至不需要更早的 git rebase,这样整个脚本就会崩溃到 git fetch,然后是 git rebase -i @{upstream}。 (您是否仍想自动进行序列编辑取决于您。)

如果您不介意误导性的错误消息,则也不需要检查。 运行 git fetch 默认会从 origin 获取,如果没有当前分支 如果当前分支 @upstream 将会失败分支没有上游,所以这可以减少到两个命令长的脚本或别名:

git fetch && GIT_SEQUENCE_EDITOR="sed -i '' 's/^pick/squash/'" git rebase -i @{u}