在对代码进行开源时,我们往往并不希望代码开发过程中的提交记录被其他人看到,因为提交的过程中往往会涵盖一些敏感信息。因此会存在 将仓库中所有 commit 合成一个 的需求。

直觉上,往往会用 rebase 和 squash 或 reset,不过我尝试了一下存在问题,会出现最后仍然剩两个 commit 的情况。

接下来分享三种可用的方式,并简单介绍一下为什么不用 rebase

方式一:git commit --amend(官方建议)

这一种方式意思就是追加提交,最符合 git 的使用原则,也最轻量。我建议使用这种方式,这也是 git 官方建议的方式。

首先在 github 网页上或者使用 git log 查看第一个 commit 的 id,然后运行:

git reset --soft <第一个 commit 的 id>
git commit --amend

这两行指令的含义是:

  1. 将当前分支的状态切换到第一个提交中,并保留本地的修改以及暂存区的设置;
  2. 将现在的暂存区的内容直接 amend 到前一个提交(在这里指的就是第一个 commit)。

运行这两行指令之后,将会弹出一个新的编辑框,要求填写 commit message。默认的 commit message 就是你的第一个提交的 commit 信息,如果你需要修改,就修改一下。

更多配置

  1. 如果不希望保留第一个 commit 的作者信息,可以加参数--reset-author

    git commit --amend --reset-author
  2. 如果希望不要修改作者和日期,可以加参数--no-edit

    git commit --amend --no-edit
  3. 如果希望修改日期,可以加参数--date,例如:

    git commit --amend --date "Mon Aug 1 12:23:11 2022 +0800"

以上配置均可以组合使用。

方式二:新建本地的 git 仓库

这种方式是最直观直接的,新建了当然什么都没有了咯。
不过操作起来比较麻烦,需要删除文件夹、调整当前的目录。

# 1. 删除当前目录的 .git/ 文件夹
# 2. 新建 git 仓库
git init
# 3. 建立当前 git 目录与远端仓库的关系
git remote add origin git@github.com:user/repo
# 4. 重新添加所有文件并提交
git add .
git commit -m 'message'
# 5. 对远端仓库强制更新
git push -f origin master

方式三:新建空白的子分支

这种方式也很直观,就是新建空白子分支,再将子分支直接命名为原来的主分支,李代桃僵。
不过在推送时有点邪门,弄不好也容易出错,不建议使用,不过可以用来了解一下 orphan 参数。

# 1. 新建一个空白分支
git checkout --orphan <分支名> # orphan 代表这个分支是一个初始提交
# 2. 重新添加所有文件并提交
git add .
git commit -m "new"
# 3. 删除原来的主分支
git branch -D master
# 4. 将新建的空白分支的名称改成master
git branch -m master
# 5. 对远端仓库强制更新
git push -f origin master --set-upstream

注意,主分支有可能叫做 main,也有可能叫做 master

为什么不建议用 rebase 进行该合并操作?

rebase 用于压缩 commit 的时候,往往是这样的过程:

  1. git rebase -i HEAD~n,其中 n 是需要合并的 commit 数量;
  2. 弹出新的编辑窗口,选择(pick)一个分支,压缩(squash)其他分支:
    pick commitid
    s commitid1
    s commitid2
  3. 保存并退出。

rebase 这个 git 指令仅看名字,意思大概是重新设置一下 base commit。因此它在使用时,是需要有一个 base commit 的,它的 pick、squash 等操作,都是基于这个 base 去做的。

就拿上述所说的过程中的第二步解释,在这一步中,其 base commit 其实是 commitidparent commit,它实际上做的操作,是先切换到 parent commit,然后再在 parent commit 里去进行 cherry-picksquash 操作。然后再重新提交。

而你无法使用 rebase 去合并仓库中的所有 commit 的原因,也仅仅是因为它的机制:

  1. 最初的那个 commit,它没有它的 base commit。所以你无法使用 rebase 去 pick 第一个 commit。
  2. 当你每个 commit 都不 pick 的时候,压缩完了的 commit 将会不知道存给哪个 commit。

所以如果要使用 rebase 里提供的 squash(压缩)对所有分支进行压缩,压缩成唯一的一个 commit,那 rebase 操作时,要么无法找到 base commit 从而指令直接运行出错,要么你压缩完成之后 commit 不知道存给谁就报错。

而这些报错在处理起来,对于一个只想简单交个代码的人来说是比较难懂的。

如果你不相信,我这边提供一个例子。

假如现在总共有 3 个 commit,其中第一个 commit 的 id 是 d2d48778,如下所示:

用 rebase 进行合并的时候,只能对最后两个 commit 进行操作。
如果你强行操作 3 个,运行的是如下指令:

git rebase -i HEAD~3

那你将会得到报错的结果fatal: invalid upstream 'HEAD~3'

如果你运行 git rebase -i HEAD~2,那么将一切正常。

而如果你发觉不对劲,因此干脆直接去 rebase 第一个 commit,运行了如下指令:

git rebase -i d2d48778

那你将不会得到报错,但会得到如下编辑框,没有第一个 commit 的 id:

此时,直观上讲,我们肯定会不管不顾地将 pick 直接全改成 squash,期望出现奇迹。可是当我们保存并退出时,会发现出现的是报错error: cannot 'squash' without a previous commit,要求必须选择一个此前的 commit 去作为压缩的结果存储的 commit:

既然如此,干脆手动新增一行 pick 行不行呢?强行指定第一个 commit 作为存储 squash 结果的 commit,如下所示:

实际上,这也不行。原因就在于第一个 commit 没有前一个 commit,根本不能被 cherry-pick。如果你真的这样做了,那么你会得到一个报错The previous cherry-pick is now empty, possibly due to conflict resolution.,与我的描述一致,如下图所示:

你或许还注意到了 git 官方给出了一个解决办法,就是 git commit --allow-empty,那么,它解决的结果是什么呢?当运行了这行指令之后,弹出新的编辑框要求输入 commit message,然后查看当前 git 日志,如下两图所示:


你会惊讶地发现,居然还是有两个提交。

更可怕的是,当你终于想起来去看看自己的 git 状态时,你会发现操作日志也没有了,rebase 也没执行,本地的修改也不见了。如下图所示:

虽然实际上,本地的修改其实还在 本地的 commit 文件里,但由于你也不知道到底怎么 rebase,在百般 rebase 失败之后,你或许已经忘记了最新代码的 commitid、或者已经失手推送更新了远端仓库、或者已经忘记了自己到底要改什么东西,最后的结果可能是让人崩溃的。

其实在 git status 时,git 命令行就已经显示了这个问题的所有解决方案:

  1. 你可以修改你的 rebase 操作,使用 git rebase --edit-todo,让它 pick 第二个 commit、基于第一个 commit,这样起码能够保留你的代码文件,只是第一个 commit 会多余。
  2. 你可以使用git commit --amend操作,只是做简单的追加操作,而不是像现在这样使用 rebase 乱来。具体可以参考本文的方式一
  3. 你可以重新执行 rebase 操作,使用 git rebase --continue,如果你坚持觉得自己是正确的话。(当然,这样做只会导致继续报错罢了)

综上所述,我为了讲清楚为什么不在合并所有 commit 的时候使用 rebase,简单地思考并描述了一下 rebase 的原理和机制,希望对遇到这个问题的人有所帮助。

另外,大部分机制是直接通过操作看或猜出来的,仅结合 git 输出信息,并未结合官方的描述文档,若有错误,还请在评论区留言指正。

本账号所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/qq_46106285/article/details/130459829。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

【笔记】Git|将git仓库中所有的 commit 合成一个,清空所有 git 提交记录的更多相关文章

  1. git从远程仓库中更新代码到本地仓库

    git从远程仓库中更新代码到本地仓库 有时候在使用git pull的时候,会莫名才报错.查了很多资料,尝试过git的很多命令.包括git fetch命令,都会报同样的错.最后终于发现了一条捷径,由网友 ...

  2. GIT 如何合并另一个远程Git仓库的文件到本地仓库里某个指定子文件夹并不丢失远程提交记录?

    问题背景:     最近在重新整理手中的一个项目,目前该项目分为PC项目,手机项目,某第三方接口项目,第三方接口服务项目和手机项目     因为之前规划的原因,原来的四个项目是分两个解决方案来管理的 ...

  3. git删除远程仓库中的文件夹

    具体操作如下: git rm -r --cached .history    #删除目录 git commit -m”删除.history文件夹” git push -r表示递归所有子目录,如果你要删 ...

  4. git将本地仓库中的文件上传到远程仓库

    现在我们开始创建本地git仓库(版本库又叫仓库) (本地仓库:$ git init之后的目录): 1.任意地方新建文件夹aaa,右击git bash here, 2.弹出一个对话框, 3. 首先配置你 ...

  5. git删除远程仓库的文件或目录

    git rm -r --cached a/2.txt //删除a目录下的2.txt文件   删除a目录git rm -r --cached a git commit -m "删除a目录下的2 ...

  6. git在实际开发中的应用

    PS: git操作实例(https://learngitbranching.js.org/?demo) 一, 创建分支,合并分支到master 1. 在远程仓库中创建master和test分支 2.本 ...

  7. Git之创建仓库并上传/更新项目版本

    1.Git配置 使用Git的第一件事就是设置你的名字和email,这些就是你在提交commit时的签名,每次提交记录里都会包含这些信息.使用git config命令进行配置: $ git config ...

  8. git学习——远程仓库操作

    查看当前的远程库——git remote 列出了仅仅是远程库的简单名字 可以加上-v 现实对应的克隆地址 添加远程仓库——git remote add [shortname] [url] git re ...

  9. [转]git修改远程仓库地址

    原文链接:http://www.cnblogs.com/lazb/articles/5597878.html 问:Coding远程仓库地址变了,本地git仓库地址如何更新为最新地址 git修改远程仓库 ...

  10. (数据科学学习手札67)使用Git管理Github仓库

    一.简介 Git是目前使用最广泛的分布式版本控制系统,通过Git可以方便高效地管理掌握工作过程中项目内容文件的更新变化情况,通过Git我们可以以命令行的形式完成对Github上开源仓库的clone,以 ...

随机推荐

  1. 管理虚拟机(virsh)

    [root@kvm1 qemu]# virsh --help 开启和关闭 [root@kvm1 qemu]# virsh virsh # help list virsh # list virsh # ...

  2. Docker 持续集成部署+ELK日志相关等 完美实践

    docker(ubuntu) 卸载docker # 卸载(如有) for pkg in docker.io docker-doc docker-compose docker-compose-v2 po ...

  3. ABB喷涂机器人控制柜维护保养

    ABB喷涂机器人的管理与维护保养目的是减少机器人的故障率和停机时间,充分利用机器人这一生产要素,最大限度地提高产效率.喷涂机器人维修与保养在企业生产中尤为重要,直接影响到系统的寿命,必须精心维护. A ...

  4. 【Unity】热更新原理与Xlua配置

    [Unity]热更新原理与 Xlua 配置 热更新 直接理解即是让代码可以像资源包一样被运行时更新.当然它其实还一个名称叫热修复,即实现不重新打包项目也能把 Bug 修好,这也正是它常用的地方. 原理 ...

  5. 5090D-deepseek-Anythingllm-Ollama运行测试

    ollama ollama配置环境变量 ollama地址与镜像 C:\Users\DK>curl http://10.208.10.240:11434 Ollama is running C:\ ...

  6. centos使用gcc编译c++源码文件(*.cpp)

    1.检查gcc是否安装 输入g++如提示:g++: fatal error: no input files说明已经安装gcc环境 2.安装gcc环境,如已经安装略过此步骤 yum install gc ...

  7. 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧

    昨天DD以为阿里开源的QwQ-32B会刷爆全网,毕竟对标的是上一个热门项目deepseek-r1.但是,万万没想到,获得更多关注的居然是:Manus. 简单的从网上介绍信息了解了一下,感觉跟OpenA ...

  8. 【Python-Json】自定义类输入json序列化、json的读取与写入

    AI 问答 Question json支持numpy数组么 Answer 不幸的是,标准的 JSON格式 不直接支持 NumPy 数组.JSON是一种用于存储和交换数据的文本格式,它有限的数据类型只包 ...

  9. 记录一下 简单udp和sni 代理 done

    由于之前借鉴 Kestrel 了非常多抽象和优化实现,对于后续的扩展非常便利, 实现 简单udp和sni 代理 两个功能比预期快了超多(当然也有偷懒因素) (PS 大家有空的话,能否在 GitHub ...

  10. javascript快速初始化数组

    编写代码中通常会有快速初始化数组的需求,例如我们需要一个类似matlab里的zeros函数,假如这里我们需要生成一个0-23的数组用于表示一天24小时. 最基本的做法如下: function(){ l ...