在使用 Git 时,我们经常需要修改本地提交记录,比如:修改最近一次提交、将多次小的 commit 合并成一个、或者批量修改提交者信息。
以下操作会修改 Git 历史记录(SHA 值会变化),请确保不要对已推送到共享仓库的提交执行这些操作。
修改最近一次提交
修改提交说明
git commit --amend
进入编辑器修改提交说明,保存退出即可。
追加文件到最近一次提交
先将修改的文件添加到暂存区,再运行 --amend:
git add new_file.cpp
git commit --amend
也可以用 -a 自动暂存所有已跟踪文件的修改,但要注意不要提交多余文件:
git commit -a --amend
将文件从本次提交中移除
git reset HEAD~1
git checkout -- filename # 要从本次提交移除的文件
git commit -m "new commit"
修改多个提交记录(交互式 Rebase)
使用 git rebase -i 可以对历史提交进行修改、重排、合并、拆分等操作。
例如修改最近 3 次提交:
git rebase -i HEAD~3
进入交互界面后,会看到提交列表(注意顺序与 git log 相反,最早的在上面):
pick fecb551 Init the view model
pick bb199a0 Update the version
pick bc5cd9d Add new method
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
修改指定提交说明
将 pick 改为 reword:
reword fecb551 Init the view model
pick bb199a0 Update the version
pick bc5cd9d Add new method
保存退出后,rebase 会在该提交处打开编辑器让你修改说明。
如果还需要修改提交内容,使用 edit:
edit fecb551 Init the view model
pick bb199a0 Update the version
pick bc5cd9d Add new method
rebase 会在该提交处暂停,完成修改后运行:
git commit --amend
git rebase --continue
重排或删除提交
直接调整行的顺序或删除对应行即可。例如删除 “Update the version” 并交换其余两次提交的顺序:
pick bc5cd9d Add new method
pick fecb551 Init the view model
合并提交(Squash)
将 pick 改为 squash,该提交会被合并到上一个提交中:
pick fecb551 Init the view model
squash bb199a0 Update the version
squash bc5cd9d Add new method
保存退出后,rebase 会让你编辑合并后的提交说明。
拆分提交
使用 edit 暂停在要拆分的提交处,然后重置并分次提交:
pick fecb551 Init the view model
edit bb199a0 Update the version
pick bc5cd9d Add new method
rebase 暂停后执行:
git reset HEAD^
git add file1
git commit -m 'Update the version1'
git add file2
git commit -m 'Update the version2'
git rebase --continue
批量修改提交者信息
查看当前仓库中所有提交者信息:
git log --format='%aN %aE' | sort -u
使用 filter-branch 批量替换(如果 email 从未设置过,OLD_EMAIL 可以填 user.name):
git filter-branch -f --env-filter '
OLD_EMAIL="old@qq.com"
CORRECT_NAME="new_name"
CORRECT_EMAIL="new@gmail.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
修改历史后需要强制推送:
git push -f --tags
如果远程分支有保护策略(如 GitLab),需要先在 Project → Settings → Repository → Protected branches 中取消保护。
References
– EOF –