WARNING :请注意,这将更改该提交的SHA-1 as well as all children - 换句话说,这将从该点向前重写历史记录 . You can break repos doing this如果使用命令 git push --force 推送
3
git stash + rebase automation
因为当我需要为Gerrit评论多次修改旧提交时,我一直在做:
git-amend-to() (
# Stash, apply to past commit, and rebase the current branch on to of the result.
current_branch="$(git rev-parse --abbrev-ref HEAD)"
apply_to="$1"
git stash
git checkout "$apply_to"
git stash apply
git add -u
git commit --amend --no-edit
new_sha="$(git log --format="%H" -n 1)"
git checkout "$current_branch"
git rebase --onto "$new_sha" "$apply_to"
)
用法:
修改文件
git-amend-to $old_sha
我喜欢这个 --autosquash 因为它没有压制其他无关的修正 .
2
使用令人敬畏的交互式rebase:
git rebase -i @~9 # Show the last 9 commits in a text editor
找到所需的提交,将 pick 更改为 e ( edit ),然后保存并关闭该文件 . Git将回退到该提交,允许您:
使用 git commit --amend 进行更改,或
使用 git reset @~ 丢弃最后一次提交,但不丢弃对文件的更改(即将您带到'd edited the files, but hadn't提交时所处的位置) .
后者对于执行更复杂的操作(如拆分为多个提交)非常有用 .
然后,运行 git rebase --continue ,Git将在修改后的提交之上重放后续更改 . 系统可能会要求您修复某些合并冲突 .
$ git reset @~3 # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started
*注意像 --hard 和 --force 这样的选项 - 他们可以丢弃数据 . *另外,请't rewrite history on any branches you'重新合作 .
在许多系统上, git rebase -i 默认会打开Vim . Vim不像大多数现代文本编辑器那样工作,所以看一下how to rebase using Vim . 如果您更愿意使用其他编辑器,请使用 git config --global core.editor your-favorite-text-editor 进行更改 .
#!/bin/bash
set -euo pipefail
script_name=${0##*/}
warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }
[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"
# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")
if [[ $OSTYPE =~ ^darwin ]]; then
sed_inplace=(sed -Ei "")
else
sed_inplace=(sed -Ei)
fi
export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)" # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty # Commit an empty commit so that that cache diffs are un-reversed
echo
echo "Editing commit: $message" >&2
echo
13 回答
跑:
$ git rebase --interactive commit_hash^
每个
^
表示要编辑的提交数量,如果它只是一个(您指定的提交哈希值),那么您只需添加一个^
.使用Vim,您可以为要更改,保存和退出的提交更改
pick
至reword
(:wq
) . 然后git将提示您标记为reword的每个提交,以便您可以更改提交消息 .每个提交消息都必须保存并退出(
:wq
)才能转到下一个提交消息如果要退出而不应用更改,请按
:q!
EDIT :在
vim
中导航你使用j
上升,k
下移,h
向左移动,l
向右移动(所有这些都在NORMAL
模式下,按ESC
进入NORMAL
模式) . 要编辑文本,请按i
以便进入INSERT
模式,您可以在其中插入文本 . 按ESC
返回NORMAL
模式:)UPDATE :这是github列出的一个很棒的链接How to undo (almost) anything with git
要获取非交互式命令,请在PATH中添加包含此内容的脚本:
通过暂存更改(使用
git add
)使用它,然后运行git fixup <commit-to-modify>
. 当然,如果你遇到冲突,它仍然是互动的 .对我来说,它是从一个回购中删除一些凭据 . 在试图改变时,我尝试了变调并遇到了大量看似无关的冲突 - 继续 . 不要试图自己动手,在Mac上使用名为BFG(brew install bfg)的工具 .
例如,如果要修改回提交
bbc643cd
,则可以使用git rebase运行在默认编辑器中,将
pick
修改为要修改其提交的行中的edit
. 进行更改,然后使用之前的相同消息提交它们:修改提交,然后修改
返回上一个头部提交 .
WARNING :请注意,这将更改该提交的SHA-1 as well as all children - 换句话说,这将从该点向前重写历史记录 . You can break repos doing this如果使用命令
git push --force
推送git stash + rebase automation
因为当我需要为Gerrit评论多次修改旧提交时,我一直在做:
用法:
修改文件
git-amend-to $old_sha
我喜欢这个
--autosquash
因为它没有压制其他无关的修正 .使用令人敬畏的交互式rebase:
找到所需的提交,将
pick
更改为e
(edit
),然后保存并关闭该文件 . Git将回退到该提交,允许您:使用
git commit --amend
进行更改,或使用
git reset @~
丢弃最后一次提交,但不丢弃对文件的更改(即将您带到'd edited the files, but hadn't提交时所处的位置) .后者对于执行更复杂的操作(如拆分为多个提交)非常有用 .
然后,运行
git rebase --continue
,Git将在修改后的提交之上重放后续更改 . 系统可能会要求您修复某些合并冲突 .注意:
@
是HEAD
的简写,~
是指定提交之前的提交 .在Git文档中阅读有关rewriting history的更多信息 .
不要害怕变革
ProTip™:不要害怕尝试重写历史记录的“危险”命令* - 默认情况下Git不会删除你的提交90天;你可以在reflog中找到它们:
*注意像
--hard
和--force
这样的选项 - 他们可以丢弃数据 .*另外,请't rewrite history on any branches you'重新合作 .
在许多系统上,
git rebase -i
默认会打开Vim . Vim不像大多数现代文本编辑器那样工作,所以看一下how to rebase using Vim . 如果您更愿意使用其他编辑器,请使用git config --global core.editor your-favorite-text-editor
进行更改 .采用这种方法(它可能与使用交互式rebase完全相同),但对我而言,它是直截了当的 .
注意:我提出这种方法是为了说明你可以做什么,而不是日常的替代方案 . 因为它有很多步骤(可能还有一些注意事项) .
假设您要更改提交
0
,并且您当前正在feature-branch
签出此提交并创建
quick-branch
. 您还可以将功能分支克隆为恢复点(在启动之前) .你现在会有这样的事情:
阶段变化,隐藏其他一切 .
提交更改并结帐回
feature-branch
你现在会有这样的事情:
Rebase
feature-branch
到quick-branch
(解决沿途的任何冲突) . 应用存储并删除quick-branch
.你最终得到:
Git不会复制(虽然我不能说在什么程度上)在重新定位时提交0 .
注意:所有提交哈希值都是从我们最初要更改的提交开始更改的 .
我解决了这个,
1)通过创建我想要的更改的新提交..
2)我知道我需要与它合并的提交 . 这是提交3 .
所以,
git rebase -i HEAD~4
#4代表最近的4次提交(这里提交3位于第4位)3)在交互式rebase中,最近的提交将位于底部 . 看起来很像,
4)如果你想要与特定的一个合并,我们需要重新安排提交 . 应该是这样的,
重新排列后,您需要将
p
pick
替换为f
( fixup 将合并而不提交消息)或s
( squash 合并提交消息可以在运行时更改)然后保存您的树 .
现在与现有提交合并完成 .
如果由于某种原因您不喜欢交互式编辑器,则可以使用
git rebase --onto
.假设您要修改
Commit1
. 首先,从Commit1
之前分支:其次,用
cherry-pick
grabCommit1
:现在,修改您的更改,创建
Commit1'
:最后,在隐藏任何其他更改之后,将其余提交移植到新提交之上
master
:阅读:“rebase,到分支
amending
,Commit1
(非包含)和master
(包括)之间的所有提交” . 也就是说,Commit2和Commit3完全削减了旧的Commit1 . 你可以挑选它们,但这种方式更容易 .记得清理你的树枝!
交互式rebase与
--autosquash
是我经常使用的东西,当我需要修复历史上更深层次的提交时 . 它实质上加快了ZelluX的答案所说明的过程,并且当您需要编辑多个提交时,它尤其方便 .从文档:
假设您的历史记录如下所示:
并且您有要修改为Commit2的更改,然后使用提交更改
或者你可以使用commit-sha而不是commit消息,所以
"fixup! e8adec4
甚至只是提交消息的前缀 .然后在提交之前启动交互式rebase
您的编辑器将打开已经正确订购的提交
你需要做的就是保存并退出
自动交互式rebase编辑,然后提交恢复准备好进行重建
我发现自己经常修复过去的提交,因此我为它编写了一个脚本 .
这是工作流程:
这将使您想要编辑的提交 .
(您可能希望使用
git stash save
来保留您未提交的任何文件)--amend
重做提交,例如:要使上述工作正常,请将以下脚本放入
$PATH
中某处名为git-commit-edit
的可执行文件中:基于Documentation
Amending the message of older or multiple commit messages
上面显示了当前分支上最后3个提交的列表,如果需要更多,则将3更改为其他提交 . 该列表将类似于以下内容:
在要更改的每个提交消息之前,将 pick 替换为 reword . 假设您更改了列表中的第二个提交,您的文件将如下所示:
保存并关闭提交列表文件,这将弹出一个新的编辑器,您可以更改提交消息,更改提交消息并保存 .
Finaly Force推动修改后的提交 .
完全非交互式命令(1)
我只是觉得我'd share an alias that I'米用于此 . 它基于非交互式交互式rebase . 要将它添加到您的git,请运行此命令(下面给出解释):
这个命令的最大优点是它是 no-vim .
(1)当然,在变形期间没有冲突
用法
名称
amend-to
似乎合适恕我直言 . 将流与--amend
进行比较:解释
git config --global alias.<NAME> '!<COMMAND>'
- 创建一个名为<NAME>
的全局git别名,它将执行非git命令<COMMAND>
f() { <BODY> }; f
- 一个"anonymous" bash函数 .SHA=
git rev-parse "$1";
- 将参数转换为git revision,并将结果赋给变量SHA
git commit --fixup "$SHA"
-SHA
的fixup-commit . 见git-commit docsGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
部分已被其他答案所涵盖 .--autosquash
与git commit --fixup
一起使用,有关详细信息,请参阅git-rebase docsGIT_SEQUENCE_EDITOR=true
是整个事物非交互的原因 . 这个黑客我学会了from this blog post .