寻找变基点
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 --soft
和 git 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}
假设我有这个:
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 --soft
和 git 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}