Git 笔记¶
基本文件操作¶
git add¶
git add .添加当前项目所有文件git add [<pathspec>…]添加任意多个文件或文件夹到暂存区
git commit¶
git commit 的常用选项有:
-a/--all自动暂存所有文件,未追踪的文件不受影响-m/--message <msg>指定提交的注释,若不指定则会弹出编辑器-C <commit>重用指定提交的信息,包括注释、作者信息和时间戳-c <commit>与-C选项相似,但会打开编辑器提供机会修改提交信息--amend让新的提交替换当前分支的末端,相当于git reset --soft HEAD^+git commit -c ORIG_HEAD
git mv¶
git mv <source> <destination>若目标不存在则改变路径,若目标已存在且是文件则会报错,加上-f/--force选项则可以强制重命名或移动git mv <source>… <destination directory>移动多个文件到目标文件夹
由于 git 不追踪文件的移动或重命名,直接操作被当成删除原文件并增加新的未追踪文件,使用 git mv 可以避免这一点,减少麻烦,这在大规模移动文件时尤其重要。
git rm¶
git rm [<pathspec>…]若文件没有修改,则将文件从暂存区和工作区中移除;若已修改,可使用-f/--force选项强制移除git rm --cached [<pathspec>…]仅将文件从暂存区移除,解除追踪
在 pathspec 中,可以使用通配符进行匹配,例如 git rm 'log/*.log' 会删除 log 文件夹中的所有 .log 文件。
信息查看¶
git status¶
git status显示当前所处分支、暂存区与 HEAD 有区别的文件、工作区与暂存区有区别的文件,以及未追踪的文件git status -s/--short以简短的形式输出
git diff¶
git diff [--] [<path>…]显示工作区与暂存区的差别,不包括未追踪的文件git diff --no-index [--] <path> <path>显示两个指定文件的差别git diff --cached/--staged [<commit>] [--] [<path>…]显示暂存区与某次提交的差别,默认为 HEADgit diff <commit> [--] [<path>…]显示工作区与某次提交的差别git diff <commit> <commit> [--] [<path>…]显示任意两次提交的区别
若在上述命令中使用了 --stat 选项,则只会显示每个文件的统计情况。
在 git 中,可用 -- 分隔 path 与其前面部分,以避免选项混淆。
git log¶
git log [<options>] [<revision-range>] [[--] <path>…]
git log 会列出可由指定提交追溯到的提交历史,并会排除可由前带有 ^ 的提交追溯到的提交历史,例如 git log ^foo bar 会列出 bar 的提交历史,但不包括 foo 的提交历史,foo..bar 可用作其简写,常用于表示一连串提交。
需要注意的是,与之类似还有 foo...bar,其定义为 r1 r2 --not $(git merge-base --all r1 r2),常用于表示由同一祖先分出的两串分支。同时,这两种写法都可以省略一端,以默认的 HEAD 来代替,例如 origin..HEAD 可以简写为 origin..,表示当前分支尚未推送到远程的提交。
若指定了 path,则只会显示与 path 相关的提交历史。
以下选项可以用于筛选提交:
-<number>最多只显示 number 条提交--since/--after=<date>只显示在指定日期之后的提交,日期格式可为:YYYY-MM-DDYYYY.MM.DDYYYY/MM/DD,若不指定则默认为今天HH:MM:SS,若不指定则默认为午夜n minutes/hours/days/weeks/months/years ago,其中末尾的s可省略,空格也可替换成.-/
--until/--before=<date>只显示在指定日期之前的提交--author/--commiter=<pattern>只显示作者名符合 pattern 的提交,可使用-i选项忽略大小写
以下选项可用于修改显示格式:
--stat显示修改的统计信息-p/--patch显示提交的具体修改,可与--stat选项一起使用--abbrev-commit显示提交哈希的缩写--pretty[=<format>]--format=<format>修改显示格式,默认为medium--oneline等价于--pretty=oneline --abbrev-commit--graph在左侧绘制图,显示分支与合并历史
--pretty 或 --format 选项中的 format 可为:
=oneling显示在一行=short/medium/full/fuller显示内容依次变多,short 只含提交哈希、作者名与标题行,fuller 则包括提交哈希、作者名、作者日期、提交者名、提交日期、标题行与完整提交注释=format:<format-string>显示指定格式,可以使用以下占位符:%H提交哈希%h提交哈希的缩写%an作者名%ae作者邮箱%ad作者日期%ar作者相对日期%ai类 ISO 8601 格式的作者日期%as作者日期的缩写,格式为YYYY-MM-DD%cn提交者名。其余各占位符与作者信息相同,只需将a替换成c%d引用名,包括分支与标签%s标题行,即提交注释的第一行%Cred%Cgreen%Cblue%Creset%C(…)切换之后的颜色,其中%Creset用于重置颜色,%C(auto)可以自动设置颜色
git show¶
git show [<options>] [<object>…]
与 git log 和 git cat-file 类似,但侧重于显示指定对象且可读性更强,可以是提交、标签、树或者 blob,会根据对象的类型,显示对象的内容:
- 若对象是提交和标签,则会显示详细信息与具体修改,可接受 git log 的那些修改显示格式的选项
- 若是树,则会列出其下文件名称
- 若是 blob,则会显示其内容
git cat-file¶
git cat-file -t <object>显示对象的类型git cat-file -s <object>显示对象的大小git cat-file -p <object>根据对象的类型,显示对象的内容- 若对象是提交或标签,则会显示其所有信息,包括树、父提交、作者等
- 若对象是树,则会显示其所有 blob 与子树的信息,包括权限、类型、哈希值与文件名
- 若对象是 blob,则会显示其内容
git cat-file --batch-check=<format>打印 stdin 提供的对象信息,可用于批量检查对象信息,format 可为:%(objecttype) %(objectname) %(objectsize) %(rest)显示对象类型、名称、大小及路径
git ls-files¶
git ls-files [-c/--cached]列出暂存区的文件,即所有被追踪的文件git ls-files -d/--deleted列出所有已被删除但尚未暂存的文件git ls-files -m/--modified列出所有已被修改但尚未暂存的文件,包括被删除git ls-files -o/--other列出尚未被追踪的文件git ls-files -i/--ignored列出所有被忽略的文件,必须使用-c或-o选项来指定搜索范围,同时还必须使用--exclude*选项来进行匹配,例如git ls-files -io --exclude='*.log'可以列出所有未追踪的被忽略的 .log 文件git ls-files -s/--stage列出暂存区文件的信息,包括权限、哈希值与文件名等
git rev-list¶
git rev-list 是 git log 的底层命令,用于列出提交对象,其接受的参数与 git log 类似,但更适用于脚本。
git rev-list --count HEAD统计从 HEAD 开始的提交数量git rev-list --objects --all列出所有可达对象,包括提交、树和 blobgit rev-list --all --objects | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | grep '^blob' | sort -k3 -n -r | tail -n 5查找仓库中最大的 5 个文件
恢复保存¶
git restore¶
git restore [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>…
git restore 可用于恢复工作区和暂存区中的文件,恢复源可以通过 -s/--source <tree> 手动指定。若 pathspec 已被追踪但不存在于恢复源中,则会被删除以匹恢复源。
默认情况下,git restore 恢复工作区文件,恢复源为 index;若使用了 -S/--stage 选项,则恢复暂存区文件,恢复源为 HEAD;若同时使用了 -S/--stage 和 -W/--worktree 选项,则同时恢复工作区与暂存区文件。
git reset¶
git reset 可用于重置暂存区的文件,如:
git reset [<tree-ish>] [--] <pathspec>…重置暂存区的文件,使其与 tree-ish 一致,tree-ish 默认为 HEAD
但相比之下,git reset 更常用于回退版本,具体命令为:
git reset [<mode>] [<commit>]将当前分支重置为指定 commit,暂存区和工作区的文件的改变视模式而定,默认为 mixed--soft不改变工作区和暂存区--mixed仅重置暂存区--hard重置工作区与暂存区
需要注意的是,该操作会同时移动 HEAD 和当前分支到指定提交上,更加危险。不过在进行该操作前,git 会将原分支设为 ORIG_HEAD,以便回退。
在指定提交时,可以使用相对引用,例如 HEAD^ 可以表示 HEAD 的父提交,其中 ^ 可以叠加使用;HEAD~2 可以更方便地表示 HEAD 的父提交的父提交;当存在多个父提交时,可以使用 ^n 来指定第 n 父级,若不使用则默认为第一父级。
git reflog¶
git reflog [show] [<log-options>] [<ref>]
git 的引用存储在 .git/refs 文件夹中,主要分为以下几类:
- 本地分支,格式为
refs/heads/<branch> - 远程追踪分支,格式为
refs/remotes/<remote>/<branch> - 标签,格式为
refs/tags/<tagname>
以上引用在使用时,大多可将 refs/heads 等前缀略去。
除此以外,还会有一些特殊的引用存储在 .git 文件夹中,例如 HEAD 指向当前检出 commit,ORIG_HEAD 指向危险操作前的 HEAD,FETCH_HEAD 指向最近一次拉取的分支(可能会有多个),MERGE_HEAD 指向欲合并的目标分支。
git 会记录下所有引用的变动,包括提交、合并、重置等,这些记录被称为 reflog,可以通过 git reflog 来查看,具体形式为 HEAD@{n},可用于恢复历史。
git reflog 的默认子命令为 show,可以接受 git log 的所有参数。除 show 外,还有以下子命令:
expire用于修剪过期的 reflog 条目delete用于删除指定的 reflog 条目
git stash¶
git stash [push] [--] [<pathspec>…]临时保存未提交的更改,使工作目录回到干净的状态,默认会贮藏所有更改-S/--staged仅贮藏暂存区的更改-u/--include-untracked也贮藏未追踪的文件-k/--keep-index保留暂存区的更改-m/--message <msg>指定贮藏项的注释,默认为当前 commit 的注释
git stash list [<log-options>]列出所有贮藏项,具体形式为stash@{n}: <message>git stash show [<diff-options>] [<stash>]显示贮藏项的内容git stash pop [<stash>]弹出一个贮藏项并应用,默认为stash@{0}git stash drop [<stash>]删除一个贮藏项git stash clear删除所有贮藏项
分支管理¶
git branch¶
以下命令可以列出分支:
git branchgit branch -l/--list列出所有本地分支git branch -r/--remotes列出所有远程追踪分支git branch -a/--all列出所有分支git branch -v列出本地分支的最后一次提交git branch -vv列出本地分支的最后一次提交与上游分支
上述各选项可以组合使用,而且需要注意的是,如果想要使用 pattern 匹配分支,则必须要使用 --list 选项,例如 git branch -rl *dev*。
以下命令可以修改分支:
git branch <branchname> [<start-point>]新建一个指向 start-point 的本地分支,默认为 HEAD,若为远程追踪分支则会自动设置其为上游分支git branch -d/--delete <branchname>…删除本地分支git branch -m/--move [<oldbranch>] <newbranch>重命名本地分支git branch -c/--copy [<oldbranch>] <newbranch>复制本地分支
被删除的分支不能是当前分支,且必须要完全合并进上游分支,若没有上游分支则要完全合并进 HEAD,也就是说,删除目标需要能通过上游分支或 HEAD 恢复,以免丢失未合并的更改;newbranch 也不能是已存在的分支名。若要强制如此,可以使用 -f/--force 选项,或者直接使用 -D -M -C 选项来代替。此外,-d 和 -r 选项可以组合使用,以删除存储在本地的远程追踪分支。
以下命令可以设置上游分支:
git branch -u/--set-upstream-to <upstream> [<branchname>]设置上游分支git branch --unset-upstream [<branchname>]移除上游分支<upstream>的形式为<remote>/<branch><branchname>若未被指定,则默认为当前分支
本地分支在推送和拉取前,需要先设置上游分支,以与某个远程仓库的远程分支建立联系,其在本地的存在形式为远程追踪分支。如果此前本地并没有远程追踪分支,可以先使用 git fetch 拉取远程仓库,然后再将拉取来远程追踪分支的设置为上游分支。
git checkout¶
git checkout 可以切换 HEAD 的位置,更新工作区和暂存区,常用的命令有:
git checkout <branch>切换到指定分支git checkout <commit>切换到指定 commitgit checkout -切换到前一个位置git checkout -d/--detach [<branch>]切换分支并分离 HEADgit checkout -b <new-branch> [<start-point>]新建分支并切换,start-point 默认为 HEAD,若为远程追踪分支则会自动设置其为上游分支
需要注意的是,只有在前后 HEAD 的文件完全相同的情况下,git checkout 才会保持本地的更改,否则会报错,这样可以避免本地的更改被覆盖。
此外,git checkout 还可以做到从已给分支名推测远程追踪分支,或者从远程追踪分支推测分支名:在使用 git checkout <branch> 时,如果本地没有该分支名,而且刚好有一个远程仓库有一个同名的远程追踪分支,则会自动新建分支并追踪;在使用 git checkout -t <remote>/<branch> 时,如果本地没有该分支名,同样也会自动新建分支并追踪。这两种情况都相当于在使用 git checkout -b <branch> --track <remote>/<branch>。当然,如果想要新建分支名和远程追踪分支名不同,就不能省略 -b 选项了。
git switch¶
git switch <branch>切换分支git switch -切换到前一个分支,不能是 commitgit switch -d/--detach [<start-point>]切换位置并分离 HEADgit switch -c/--create <new-branch> [<start-point>]新建分支并切换
git switch 和 git checkout 一样,可以在前后 HEAD 的文件完全相同的情况下保持更改,也可以做到从已给分支名推测远程追踪分支,或者从远程追踪分支推测分支名,从而在省略 -c 选项的情况下完成自动新建与追踪。
git merge¶
git merge <commit>…将指定提交合并到当前分支git merge --continue在解决了冲突后继续合并,需要处于合并过程git merge --abort取消合并,回到合并前的状态git merge --quit退出合并,但不回到合并前的状态
若当前分支是目标分支的祖先,则会进行快进合并,不会产生 merge commit,否则在没有冲突的情况下,会自动产生一个新的 merge commit。如果不想自动产生合并提交,可以使用 --no-commit 选项。
合并分支有多种策略,可以使用 -s/--strategy 选项来指定,常用的策略有:
ort是合并两个分支时的默认策略,使用三路合并算法,具体就是,如果只有一方有修改,或者双方都有修改但修改相同,则选择修改后的文件,否则就会产生冲突,需要手动解决- 可以使用
-X/--strategy-option ours/theirs选项来指定合并时的冲突解决策略,ours代表保留当前分支的修改,theirs代表保留合并分支的修改
- 可以使用
octopus是合并多于两个分支时的默认策略,在合并过程中一旦出现需要手动解决的冲突就会拒绝合并ours策略不同于-X ours,会完全保留当前分支的更改,不考虑其他分支
如果不想留下其他分支的记录,保持线性的提交历史,可以使用 --squash 选项,这样就会将其他分支的所有提交合并成一个提交附加到当前分支。
git rebase¶
git rebase [--onto <newbase>] [<upstream> [<branch>]]保存 branch 有而 upstream 没有的提交,也即保存从 upstream 到 branch 的提交,然后将其逐个应用到 upstream 上- 若有
--onto选项,则会将补丁应用到 newbase 上 - 若未指定
<upstream>,则会使用当前分支的上游分支
- 若有
git rebase --continue在解决了冲突后继续变基git rebase --abort取消变基,回到变基前的状态,若有 branch 则会切换到 branchgit rebase --quit退出变基,但不回到变基前的状态git rebase --skip继续变基,跳过当前补丁
git rebase 可用于删除提交,例如 git rebase --onto feature~5 feature~3 feature 会删除从 feature^4 到 feature^3 的提交;也可用于将某一分支的部分更改应用到另一分支上,例如 git rebase --onto master feature bugfix 会将 feature 分支上对 bug 的修复应用到 master 分支上。
git rebase 更常用的用法是加上 -i/--interactive 选项,以交互式的方式来变基,可以方便地对提交进行删除、合并等操作,并且只会改变提交时间,不会改变作者时间,其命令有:
p, pick <commit>使用提交r, reword <commit>使用提交,但是会弹出编辑器,提供修改提交信息的机会e, edit <commit>使用提交,但是会在应用该提交后停下,以便使用--amend选项来修改提交s, squash <commit>使用提交,但是会将该提交合并进上一个提交,然后弹出编辑器,显示合并后的提交信息,适用于合并多个相似的小更改f, fixup [-C | -c] <commit>和 squash 一样能够合并多个提交,但会自动使用之前的提交信息,若使用-C选项则会使用当前提交信息,若使用-c选项还会在使用当前提交信息的基础上打开编辑器,适用于将修复合并进之前的提交d, drop <commit>移除提交
git filter-branch¶
git filter-branch 可用于批量修改历史提交,但该命令较为复杂且缓慢,现在更推荐使用 git-filter-repo 等第三方工具。其基本用法如下:
git filter-branch --<filter> <command> [<rev-list-options>]
其中 <filter> 用于指定修改的范围,常用的有:
--env-filter <command>修改环境变量,可用于修改作者或提交者信息--tree-filter <command>修改暂存区和工作区,可用于删除或修改文件--index-filter <command>修改暂存区,比--tree-filter更快--parent-filter <command>修改父提交列表--msg-filter <command>修改提交信息
例如,若要删除所有提交中的 password.txt 文件,可以使用 git filter-branch --tree-filter 'rm -f password.txt' HEAD。
git tag¶
git tag列出所有标签git tag -l/--list [<pattern>…]列出所有标签,若有 pattern 则会匹配git tag <tagname> [<commit>]创建轻量标签git tag -a/--annotate <tagname> [-m <msg>] [<commit>]创建附注标签git tag -d/--delete <tagname>…删除标签
远程管理¶
git remote¶
git remote显示所有远程仓库git remote -v/--verbose显示所有远程仓库的详细信息,包括 URLgit remote add <name> <URL>添加远程仓库git remote rename <old> <new>重命名远程仓库git remote rm/remove <name>删除远程仓库git remote set-url [--push] <name> <newurl>修改远程仓库的 URL,若使用--push选项则只修改 push 地址
git fetch¶
git fetch [<options>] [<repository> [<refspec>…]]
git fetch 能从远程仓库拉取分支,用以更新远程追踪分支,其常用选项有:
--all拉取所有的远程仓库-v/--verbose显示详细信息-p/--prune删除远程仓库中不存在的远程追踪分支
refspec 用于表示本地引用和远程引用之间的映射关系,其格式为 [+]<src>:<dst>。在 git fetch 中,src 表示要拉取的远程引用,dst 表示要更新的本地引用,+ 号表示允许 non-fast-forward。
在使用 git fetch 时,若未指定 repository,则会使用上游分支的远程仓库,若没有上游分支,则会使用 origin 仓库;若未指定 refspec,则会使用 remote.<repository>.fetch 中的配置,一般为 +refs/heads/*:refs/remotes/origin/*,即将远程仓库的所有分支都拉取到本地对应的远程追踪分支中;若 refspec 中的 :<dst> 被忽略,则会更新与 src 对应的远程追踪分支。
git pull¶
git pull [<options>] [<repository> [<refspec>…]]
git pull 形式与 git fetch 相同,但会在拉取后自动合并,相当于 git fetch + git merge,其常用选项有:
-r/--rebase[=false|true|merges|interactive]使用变基而不是合并,可以在pull.rebasebranch.<name>.rebasebranch.autoSetupRebase中配置--no-rebase相当于--rebase=false--set-upstream若拉取成功,则设置上游分支- 其余更多选项可见 git fetch 和 git merge
git push¶
git push [<repository> [<refspec>…]]
git push 能推送本地分支到远程仓库,使用本地引用更新远程引用,其常用选项有:
--all推送所有分支--tags推送所有标签--prune删除远程仓库中不存在对应本地分支的分支-f/--force强制推送-d/--delete从远程仓库删去列出的引用,常见用法为git push origin --delete <branch>-u/--set-upstream若分支已最新或推送成功,则设置上游分支,常见用法为git push -u origin main
在 git push 中,src 表示要推送的本地引用,dst 表示要更新的远程引用,+ 号表示强制推送。可以使用 git push <repository> +:<dst> 强制删除任意引用。
在使用 git push 时,若未指定 repository,则会使用 branch.<name>.remote 中的配置,若没有配置则会默认使用 origin 仓库;若未指定 refspec,则会使用 remote.<name>.push 中的配置,若没有配置则会默认推送到远程仓库的同名分支;若 refspec 中的 :<dst> 被忽略,则默认为 :<src>,即推送到同名分支。
配置管理¶
git config¶
git config <name> <value>设置配置git config -l/--list列出所有配置git config --get <name>显示指定配置git config --get-regexp <name-regex> [<value-pattern>]显示匹配 name-regex 以及可选的 value-pattern 的配置git config --unset <name>删除指定配置
在 git 中,配置分为三个级别:系统级别、全局级别和仓库级别,分别对应三个配置文件:/etc/gitconfig ~/.gitconfig .git/config。在使用 git config 时,可以使用 --system --global --local 选项来指定配置级别,若未指定则默认为 --local。
在列出和显示配置时,可以使用 --show-origin 选项来显示配置的来源,还可以使用 --show-scope 选项来显示配置的级别。
常见的配置有:
user.name用户名user.email用户邮箱alias.<name>别名core.editor默认编辑器core.autocrlf行结束符的转换- 若为
true,则在提交时将 CRLF 转换成 LF,在检出时将 LF 转换成 CRLF - 若为
input,则在提交时将 CRLF 转换成 LF - 若为
false,则不做任何转换
- 若为
merge.tool默认合并工具mergetool.<tool>.cmd使用某合并工具时的命令diff.tool默认比较工具difftool.<tool>.cmd使用某比较工具时的命令init.defaultBranch默认分支名
另外一种与 git 无关但与 Github 有关的配置是 SSH 密钥,可以使用 ssh-keygen 来生成密钥,然后将 .pub 公钥添加到 Github 上。
# 生成带邮箱注释的的 rsa 密钥
ssh-keygen -t rsa -C "hr.zheng@outlook.com"
# 检验能否成功连接到 Github
ssh -T git@github.com
gitignore¶
可在项目根目录中的 .gitignore 文件中定义忽略规则,以忽略不需要追踪的文件,已追踪的文件不受影响。常见的规则如下:
build忽略所有名为 build 的文件或文件夹build/只忽略名为 build 的文件夹,忽略其内所有文件/build/只忽略当前目录下的名为 build 的文件夹/codes/*.c只忽略 codes 第一层目录下的 .c 文件/codes/*/*.c只忽略 codes 第二层目录下的 .c 文件/codes/**/*.c忽略 codes 内的所有 .c 文件,/**/可匹配零个或多个目录!所有因之前规则被忽略的匹配文件会被重新追踪
仓库清理¶
git gc¶
git gc [--aggressive | --auto | --prune=<date> | --no-prune]
git gc 会清理不必要的文件并优化本地仓库。
git 会在版本库中保留所有对象,即使它们已无法访问。git gc (garbage collection) 命令可以清理这些对象,减小仓库体积。
--aggressive选项会更积极地优化仓库,但耗时更长--auto选项会让 git 自行判断是否需要进行垃圾回收--prune=<date>选项可以指定一个日期,早于该日期的无法访问对象都将被清理,默认为两周前
git clean¶
git clean [-d] [-f] [-x] [-X]
git clean 会清理工作目录,删除未追踪的文件
常用选项有:
-d选项会删除未追踪的目录-f选项会强制删除未追踪的文件,默认情况下 git clean 是不删除任何文件的-x选项会删除所有未追踪的文件,包括 .gitignore 中的文件-X选项会删除 .gitignore 中的文件,但保留其他未追踪的文件
常见场景¶
查看文件的历史版本与比较差异¶
- 查看某个提交中的文件内容
可以使用 git show <commit>:<path> 来查看指定提交中某个文件的内容。
# 查看 5 个提交前 README.md 文件的内容
git show HEAD~5:README.md
- 比较历史版本与当前工作区文件的差异
可以使用 git diff <commit> -- <path> 来比较指定提交中的文件版本与当前工作目录中的文件。
# 比较 5 个提交前 README.md 文件与当前工作区版本的差异
git diff HEAD~5 -- README.md
- 比较两个历史版本之间的文件差异
可以使用 git diff <commit1> <commit2> -- <path> 来比较两个不同提交中同一个文件的差异。
# 比较 5 个提交前和 3 个提交前 README.md 文件的差异
git diff HEAD~5 HEAD~3 -- README.md
修改上一次提交的内容¶
- 修改上一次提交的内容,同时使用相同的提交信息
如果需要修改上一次提交的内容,可以使用 git commit --amend 命令。该命令会将当前暂存区的更改合并到上一次提交中。
# 修改上一次提交的内容
git add <file> # 添加需要修改的文件到暂存区
git commit --amend -C HEAD
-
修改上一次提交的内容,并修改提交信息 如果需要修改上一次提交的内容,并且修改提交信息,可以使用
-c HEAD命令,打开编辑器进行修改。# 修改上一次提交的内容,并修改提交信息 git add <file> # 添加需要修改的文件到暂存区 git commit --amend -c HEAD
压缩 .git 大小¶
如果使用 git 原生命令,可以使用以下步骤来压缩 .git 目录的大小:
- 使用
git count-objects -vH命令来查看 .git 目录的大小 - 使用
git rev-list --all --objects | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | grep '^blob' | sort -k3 -n -r | tail -n 5查找仓库中最大的几个文件 - 使用
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH" --prune-empty --tag-name-filter cat -- --all删除指定文件的所有历史记录 - 使用
rm -rf .git/refs/original/命令删除自动保存的原始引用,以免 Git 继续保留那些历史对象 - 使用
git reflog expire --expire=now --all命令清理引用日志,释放那些在 Git 中看不到但实际仍保存的历史引用 - 使用
git gc --prune=now --aggressive命令进行垃圾回收,压缩和清理.git/objects/中的对象数据库,释放磁盘空间
但是更好的选择是使用 git-filter-repo 工具来压缩 .git 目录的大小。该工具可以更快地处理大仓库,并且支持更多的过滤选项。
修改作者信息¶
可以使用 git filter-branch 来批量修改作者信息。
以修改作者名为例:
git filter-branch --env-filter "GIT_COMMITTER_NAME='新的作者名'; GIT_AUTHOR_NAME='新的作者名'"
另一个通过条件判断修改 email 的例子是(bash):
git filter-branch --env-filter '
OLD_EMAIL="旧的邮箱@example.com"
CORRECT_NAME="新的作者名"
CORRECT_EMAIL="新的邮箱@example.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