修改最后一次提交
仅修改提交信息
假设修改前的git日志如下:
1 2 3 4 $ git log --oneline 5e5996c (HEAD -> master) 修改b.java 6 cce2144 修改b.java 5 ...
如果我们只是希望修改最后一次提交的提交信息,我们可以通过如下的方式进行修改:
1 2 3 4 $ git commit --amend -m '修改B.java文件:删除无用的import语句' [master 055cda3] 修改B.java文件:删除无用的import语句 Date: Mon Apr 1 10:39:09 2024 +0800 1 file changed, 1 insertion(+)
此时再次查看git日志:
1 2 3 4 $ git log --oneline 055cda3 (HEAD -> master) 修改B.java文件:删除无用的import语句 cce2144 修改b.java 5 ...
可以发现,之前旧的提交对象5e5996c
被新的提交对象055cda3
覆盖,并没有增加新的提交对象。
修改提交的文件快照
如果你已经完成提交,又因为之前提交时忘记添加一个新创建的文件,想通过添加或修改文件来更改提交的快照,也可以通过类似的操作来完成。 通过修改文件然后运行 git add
或 git rm
一个已追踪的文件,随后运行 git commit --amend
拿走当前的暂存区域并使其做为新提交的快照。
使用这个技巧的时候需要小心,因为修正会改变提交的 SHA-1 校验和。 它类似于一个小的变基 - 如果已经推送了最后一次提交就不要修正它 。
比如修改前的git日志如下:
1 2 3 4 5 6 7 8 $ git log --oneline 055cda3 (HEAD -> master) 修改B.java文件:删除无用的import语句 cce2144 修改b.java 5 ... $ git status On branch master nothing to commit, working tree clean
此时如果我们希望追加一个新的文件D.java
,并删除B.java
中的某一行:
1 2 3 $ git status -s M B.java ?? D.java
但是我们希望将这些改动也加入最后一次改动中,可以通过如下的方式实现:
1 2 3 4 5 6 7 8 9 10 11 $ git add * $ git status -s M B.java A D.java $ git commit --amend [master 38063bd] 修改B.java文件:删除无用的import语句 Date: Mon Apr 1 10:39:09 2024 +0800 2 files changed, 2 insertions(+) create mode 100644 D.java
此时再次查看git日志:
1 2 3 4 $ git log --oneline 38063bd (HEAD -> master) 修改B.java文件:删除无用的import语句 cce2144 修改b.java 5 ...
修改多个提交信息
为了修改在提交历史中较远的提交,必须使用更复杂的工具。 Git 没有一个改变历史工具 ,但是可以使用变基工具 来变基一系列提交,基于它们原来的 HEAD
而不是将其移动到另一个新的上面。
通过交互式变基工具 ,可以在任何想要修改的提交后停止,然后修改信息、添加文件或做任何想做的事情。 可以通过给 git rebase
增加 -i
选项来交互式地运行变基。 必须指定想要重写多久远的历史,这可以通过告诉命令将要变基到的提交来做到。
详情阅读:修改多个提交信息
重新排序提交
详情阅读:修改多个提交信息
压缩提交
详情阅读:修改多个提交信息
拆分提交
详情阅读:修改多个提交信息
彻底移除文件
简单情况:仅涉及最近一次提交
参考:remove-sensitive-files-and-their-commits-from-git-history
如果改动需要移除的文件仅在本地的最后一次提交中存在,而且没有被Push到远端仓库,可以直接使用给git commit --amend
进行修复,比如错误的提交了
secret.txt
文件:
1 2 3 4 5 6 7 8 $ git log --all --oneline --graph * f1a16dc (HEAD -> master) 提交 secret.txt * d945ca3 app.properties中新增env 变量 $ ll total 7 ... -rw-r--r-- 1 86182 197609 0 4月 2 10:32 secret.txt
我们可以通过如下的方式覆盖本地提交:
1 2 3 4 5 6 7 8 9 $ git rm secret.txt rm 'secret.txt' $ git commit --amend -m '删除误提交的文件' You asked to amend the most recent commit, but doing so would make it empty. You can repeat your command with --allow-empty, or you can remove the commit entirely with "git reset HEAD^" . On branch master No changes
因为原先该次提交只提交了文件secret.txt
,而此次amend
删除了该文件,会导致原先的那次commit
内容为空,因此需要加上--allow-empty
参数,也可以根据提示直接删除这次提交:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ git commit --amend --allow-empty -m '删除误提交的文件' [master 84d04fe] 删除误提交的文件 Date: Tue Apr 2 10:32:28 2024 +0800 $ ll total 7 -rw-r--r-- 1 86182 197609 649 4月 1 10:38 A.java ... -rw-r--r-- 1 86182 197609 0 4月 1 13:43 D.java $ git log --all --oneline --graph * 84d04fe (HEAD -> master) 删除误提交的文件 * d945ca3 app.properties中新增env 变量 ... $ git show 84d04fe commit 84d04fe11239c940a1828dcdb446bc2151be7a88 (HEAD -> master) Author: slimterry <slimterry@qq.com> Date: Tue Apr 2 10:32:28 2024 +0800 删除误提交的文件
此次提交变为一次空提交。
如下的情况则不需要添加--allow-empty
参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ touch secret.txt bar.txt $ git add * $ git commit -m '添加2个文件' $ git rm secret.txt rm 'secret.txt' $ git commit --amend -m'剔除误提交的文件' [master ce592c7] 剔除误提交的文件 Date: Tue Apr 2 10:41:47 2024 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 bar.txt
复杂情况:涉及历史提交
参考:remove-sensitive-files-and-their-commits-from-git-history
不推荐使用filter-branch
有另一个历史改写的选项,如果想要通过脚本的方式改写大量提交的话可以使用它 - 例如,全局修改你的邮箱地址 或从每一个提交中移除一个文件 。 这个命令是 filter-branch
,它可以改写历史中大量的提交 。
除非你的项目还没有公开 并且其他人没有基于要改写的工作的提交做的工作 ,你不应当使用它 。 然而,它可以很有用。 你将会学习到几个常用的用途,这样就得到了它适合使用地方的想法。
注意:git-filter-branch(1) Manual Page 中都不推荐使用filter-branch
,推荐使用的是 git filter-repo :
git filter-branch has a plethora of pitfalls that can produce non-obvious manglings of the intended history rewrite (and can leave you with little time to investigate such problems since it has such abysmal performance). These safety and performance issues cannot be backward compatibly fixed and as such, its use is not recommended . Please use an alternative history filtering tool such as git filter-repo .
安装git filter-repo
1 2 3 4 5 6 7 $ pip install git-filter-repo Looking in indexes: https://mirrors.aliyun.com/pypi/simple Collecting git-filter-repo Downloading https://mirrors.aliyun.com/pypi/packages/8d/0b/49d4d620327b717fdc072b2efdfcb3588eb3cf780e60ed5ba98ebedb5637/git_filter_repo-2.38.0-py2.py3-none-any.whl (99 kB) ---------------------------------------- 99.1/99.1 kB 1.4 MB/s eta 0:00:00 Installing collected packages: git-filter-repo Successfully installed git-filter-repo-2.38.0
从每一个提交移除敏感文件、大文件
命令格式:
1 git filter-repo --path path/to/remove1 --path path/to/remove2 --invert-paths
这经常发生。 有人粗心地提交了一个巨大的二进制文件 largefile.iso
,你希望从git仓库中彻底删除该文件 :
①:误提交了大文件
1 2 3 4 5 6 7 8 9 10 $ ll -h largefile.iso -rw-r--r-- 1 86182 197609 1000M 4月 1 14:33 largefile.iso $ git status -s A largefile.iso $ git commit -m '提交iso文件' [master 98cca66] 提交iso文件 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 largefile.iso
此时你可能想通过git rm
删除该文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 git rm largefile.iso rm 'largefile.iso' $ git commit -m '删除错误提交的iso文件' [master a45b192] 删除错误提交的iso文件 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 largefile.iso $ git log --oneline a45b192 (HEAD -> master) 删除错误提交的iso文件 98cca66 提交iso文件 ...
此时工作区中,确实已经没有该文件,但是git仓库中仍然存在该文件,我们只需要检出到提交该大文件的版本,就可以找到该文件:
1 2 3 4 5 6 7 8 $ git checkout 98cca66 Note: switching to '98cca66' . $ ll -h total 1001M -rw-r--r-- 1 86182 197609 649 4月 1 10:38 A.java ... -rw-r--r-- 1 86182 197609 1000M 4月 1 14:41 largefile.iso
注意:
无法通过将largefile.iso
加入.gitignore
的方法实现从历史提交中彻底删除文件的效果,.gitignore
仅针对未提交的文件。
如果我们想彻底从git仓库中删除该文件,可以通过如下的命令实现:
1 2 3 4 5 6 7 8 9 10 11 12 $ git filter-repo --force --path largefile.iso --invert-paths Parsed 21 commitsHEAD is now at 2592cd4 删除错误提交的iso文件 Enumerating objects: 49, done . Counting objects: 100% (49/49), done . Delta compression using up to 16 threads Compressing objects: 100% (44/44), done . Writing objects: 100% (49/49), done . Total 49 (delta 20), reused 0 (delta 0), pack-reused 0 New history written in 0.21 seconds; now repacking/cleaning... Repacking your repo and cleaning out old unneeded objects Completely finished after 0.82 seconds.
此时我们再次切换到当初提交大文件的版本:
1 2 3 4 5 MINGW64 /d/coding/git-playground (master) $ git log --all --oneline --graph * 2592cd4 (HEAD -> master) 删除错误提交的iso文件 * d6aea11 提交iso文件 ...
注意:由于重写了提交历史,因此git log中的commit id 会发生改变
1 2 3 4 5 6 7 8 9 10 $ git checkout d6aea11 Note: switching to 'd6aea11' . MINGW64 /d/coding/git-playground ((d6aea11...)) $ ll total 6 -rw-r--r-- 1 86182 197609 649 4月 1 10:38 A.java -rw-r--r-- 1 86182 197609 205 4月 1 13:43 B.java -rw-r--r-- 1 86182 197609 5 3月 29 15:57 C.java -rw-r--r-- 1 86182 197609 0 4月 1 13:43 D.java
此时在历史版本d6aea11
中的大文件largefile.iso
已经被彻底删除。
如果你的仓库已经推送到远程目录,还需要执行:
替换git历史提交中某个字符串
参考how-to-replace-a-string-in-whole-git-history
假设我们在某次提交中新增了一个app.properties
文件:
1 2 3 4 5 6 7 8 9 10 11 $ cat app.properties passwd=12345 86182@yawen MINGW64 /d/coding/git-playground (master) $ git add app.properties 86182@yawen MINGW64 /d/coding/git-playground (master) $ git commit -m '提交app.properties文件' [master 1ebee67] 提交app.properties文件 1 file changed, 1 insertion(+) create mode 100644 app.properties
然后再后续的提交中又陆续修该了该文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ git commit -m 'app.properties中新增env变量' [master a067387] app.properties中新增env 变量 1 file changed, 1 insertion(+) $ git log --all --oneline --graph * a067387 (HEAD -> master) app.properties中新增env 变量 * 1ebee67 提交app.properties文件 MINGW64 /d/coding/git-playground (master) $ cat app.properties passwd=12345 env_name=dev
如果我们将各个提交历史中的app.properties
中的12345
替换成abc123
,可以通过如下的命令实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ echo 'literal:12345==>abc123' > expressions.txt $ git-filter-repo --replace-text expressions.txt Parsed 21 commitsHEAD is now at d945ca3 app.properties中新增env 变量 Enumerating objects: 55, done . Counting objects: 100% (55/55), done . Delta compression using up to 16 threads Compressing objects: 100% (28/28), done . Writing objects: 100% (55/55), done . Total 55 (delta 24), reused 46 (delta 20), pack-reused 0 New history written in 0.21 seconds; now repacking/cleaning... Repacking your repo and cleaning out old unneeded objects Completely finished after 0.77 seconds. MINGW64 /d/coding/git-playground (master) $ git log --all --oneline --graph * d945ca3 (HEAD -> master) app.properties中新增env 变量 * 0ca4f99 提交app.properties文件 ...
–replace-text <expressions_file>::
A file with expressions that, if found, will be replaced. By
default, each expression is treated as literal text, but
regex:
and glob:
prefixes are supported. You can end the
line with ==>
and some replacement text to choose a
replacement choice other than the default of ***REMOVED***
.
此时我们分别查看工作区和历史版本中的密码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ cat app.properties passwd=abc123 env_name=dev MINGW64 /d/coding/git-playground (master) $ git show 0ca4f99 commit 0ca4f99f453b9211a19c08de968e05579775cbc3 Author: slimterry <slimterry@qq.com> Date: Tue Apr 2 10:02:20 2024 +0800 提交app.properties文件 diff --git a/app.properties b/app.properties new file mode 100644 index 0000000..ed9939e --- /dev/null +++ b/app.properties @@ -0,0 +1 @@ +passwd=abc123
注意: