撤销某次合并提交
* c935c9f (HEAD -> main, origin/main, origin/HEAD) Merge branch 'katspaugh:main' into main
|\
| * 4567c99 Optimized Method for Calculating Overlap Size in Spectrogram Resampling (#3848)
* | 1a0cc9d fix: #3707
|/
* 5f32d82 feature: [Minimap] more subscribable events (#3843)
* 4ffab8c 7.8.4我想要将 c935c9f 这次合并的代码撤销,并且强制覆盖到远程分支,操作流程如下:
- 确保在
main分支上,若没有使用git checkout main来切换 - 将 HEAD 移动到
1a0cc9d分支上,使用git reset --hard 1a0cc9d实现 - 强行覆盖远程分支,使用
git push -f origin main实现
执行完这些命令后,最终结果为:
* 1a0cc9d (HEAD -> main) fix: #3707
* 5f32d82 feature: [Minimap] more subscribable events (#3843)
* 4ffab8c 7.8.4NOTE
reset 共有三种选项,摘抄自博客园
git reset --mixed:此为默认方式,将撤回的代码,存放到工作区。同时会保留本地未提交的内容。git reset --soft:回退到某个版本 。将撤回的代码,存放到暂存区。同时会保留本地未提交的内容。git reset --hard:彻底回退到某个版本,丢弃将撤回的代码,本地没有 commit 的修改会被全部擦掉。
这里使用的是 reset --hard,是因为我们不需要留存前面提交的内容,
分支重命名
本地重命名只需要执行 git branch -m new-branch-name 即可,其中 m 的意思表示 move,和系统的 mv 指令很类似
如果想要同时更改远程分支的名称,还需要额外的步骤
- 先删除原来的分支
git push origin --delete old-branch-name - 推送新的分支
git push origin -u new-branch-name
这里的 -u 选项是 --set-upstream,用来设置设置本地分支跟踪的远程分支,相当于确定了一个对应关系
切换到远程分支
有时候想要切换到远程的分支,并且在本地创建同名分支来跟踪该远程分支,可以输入以下任一命令
git checkout --track origin/branch-name:这个命令会自动创建一个与远程分支同名的本地分支,并设置好跟踪关系git switch branch-name:如果远程分支存在而本地不存在,Git 会自动创建并跟踪远程分支git checkout -b branch-name origin/branch-name:这个命令会创建一个新的本地分支,并让它跟踪远程分支
对比两个提交之间的差异
有时候为了完成一个大任务,会分很多次进行提交,比如:
* 39e955e (HEAD -> fast-spectrogram) feat: add fast spectrogram plugin
* 9360e00 deps: add glob as dev dpes
* 1a0cc9d (origin/main, main) fix: #3707如果想要比对 39e955e 和 1a0cc9d 之间的变动,可以执行 git diff 1a0cc9d 39e955e
如果想要更详细的输出,可以添加一些选项:
如果只想看文件名的变化,而不是具体内容:
plaintextgit diff --name-only 1a0cc9d 39e955e如果你想看统计信息(比如增加/删除了多少行):
plaintextgit diff --stat 1a0cc9d 39e955e如果你想在图形界面中查看差异(如果你安装了图形化 diff 工具):
plaintextgit difftool 1a0cc9d 39e955e
提交 ID 的顺序很重要。第一个 ID 是"从",第二个是"到"。如果你交换它们的位置,会看到相反的变化
TIP
如果想要使用 neovim 作为 difftool
设置 Git 的默认 diff 工具为 nvimdiff:
plaintextgit config --global diff.tool nvimdiff设置 Git 使用 nvimdiff 作为合并工具:
plaintextgit config --global merge.tool nvimdiff(可选)如果希望 Git 直接启动 diff 工具而不询问,可以设置:
plaintextgit config --global difftool.prompt false(可选)如果想要在使用
git diff时自动调用 difftool,可以设置:plaintextgit config --global alias.d difftool这样,你就可以使用
git d来调用 nvimdiff 了。
提交记录压缩
有时候提交记录太多了(比如几千条提交记录),会导致 .git 目录过大,每次克隆都会花费比较长的时间,同时这些提交记录我们很多都用不上,因此希望可以进行压缩,可以通过下面的方法。
- 确保工作区没有文件,为接下来的变基做准备
- 假设我们希望将
f7e70c8到HEAD的提交合并为一个提交,可以执行git rebase -i f7e70c8^命令,找到f7e70c8之前的一个提交,从这里开始变基操作,将除了f7e70c8的所有提交打上 squash 的命令,这可以很容易的通过 neovim 来实现 - 关闭编辑器后会再次打开另一个编辑器,在这里为合并后的提交更新提交记录
- 强行 push 到远程
git push --force origin main - 运行垃圾回收
git gc --aggressive - 删除不再需要的远程跟踪分支
git remote prune origin
将工作区内容补充到历史 commit 中
* 86103c1 (HEAD -> refactor) e
* 407bf74 refactor: d
* 27b40b4 style: c
* ...目前工作区中有一些未提交的文件,它的工作内容与 407bf74 这个提交相同,我想将他们提交到 407bf74 这个提交中,可以通过以下流程解决
- 暂存(add)当前工作区并存储(stash)其中的内容
git add . && git stash - 使用交互式变基到
407bf74之前的一个提交,git rebase -i 407bf74^ - 应用之前的储存并暂存
git stash pop && git add . - 提交到
407bf74中,git commit --amend --no-edit - 结束变基过程
git rebase --continue
TIP
git commit --amend --no-edit 里面有一个 --no-edit 选项,可以让我们不必打开编辑器修改提交记录,直接使用原有的提交记录
工作区忽略特定文件
有时候我们想要更改一些文件,但不希望这些文件一直处于工作区,导致我们无法执行一些可能会清理工作区的指令(比如 pull),可以使用 Git 的 assume-unchanged 功能来解决
git update-index --assume-unchanged 文件名现在,Git 会忽略这个文件的本地更改,它不会出现在 git status 中。也不会被意外提交。 如果将来需要提交这个文件的更改,可以使用以下命令取消这个设置:
git update-index --no-assume-unchanged 文件名如果想查看哪些文件被设置为 assume-unchanged,可以使用:
git ls-files -v | grep '^h'想象这样一个场景,你对文件 A 做了 assume-unchanged 操作,假设远端有人修改了 A 的内容,pull 以后就会自动合并远端内容,如果不想让其合并,可以使用 git update-index --skip-worktree filename 来彻底忽略这个文件的更改,并且其他人的改动也不会被合并或者更新。如果要取消这个设置,可以使用 git update-index --no-skip-worktree filename
时间旅行
有时候很想要在一个分支的不同时间段进行时间旅行,来查看代码的工作状态,但是仅凭借 checkout 命令还是感觉力不从心,可以考虑使用 reflog 来进行从老分支到新分支的履行。
但这也许意味着我们必须先从最新的分支跳转到一个最近的可能的分支,然后慢慢的向老分支跳转,直到找到想要的分支后使用 reflog 重新跳回
大文件存储
我在给我的博客添加落霞孤鹜字体时,需要加入一个大小为 20MB 左右的 ttf 文件,但 git 对大文件管理并不是很友好,因此考虑引入 git lfs
- 首先是下载 git-lfs 工具
- 然后再我们的博客仓库根目录初始化 git lfs
- 指定需要用 git lfs 管理的文件类型
- 这时候可以看到多了一个
.gitattributes文件,我们追踪并提交它和要上传的大文件即可
brew install git-lfs
git lfs install
git lfs track "*.ttf"
git add .
git commit -m "配置 Git LFS 追踪字体文件"上面提到的是上传的步骤,如果要在其他设备克隆这个大文件,也需要一些额外的操作(初始化和单独拉取大文件)
git lfs install
git lfs pullstash 部分文件
我们直接使用 git stash push -m 暂存时,会存储当前所有的改动,如果我只想要存储 add 的文件,可以通过命令 git stash push --staged 完成,如果想要存储未 add 的文件,可以通过命令 git stash push --keep-index
可以看到我们这里使用了 git stash push 命令,他实际上是 git stash 的现代化写法,主要原因是让 stash 命令族结构更统一,这个命令族有比如:
git stash apply
git stash drop
git stash show
git stash push查看两次变更间的详情
有时候想看一次任务(分为多个 commit)之间有哪些文件变动或者变更行数,可以使用 git diff hashA..hashB --stat 实现
如果想看当前暂存区的变更行数,可以使用 git diff --cached --stat HEAD,但是使用的时候要注意,要把所有的变更都索引起来,如果是新建的文件没有 add 的话,是不会被统计进去的
git 清理锁文件
fatal: Unable to create 'xxx/xxx': File exists.
Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.这是一个残留的 Git 锁文件,不是当前有进程真的占用了它。直接删除 .git/index.lock 文件即可解决问题: