[Notes] Git|How to combine all the commits in the warehouse into one? aka, how to clear all git commit history? (A brief analysis of the git rebase mechanism is attached)

When open-sourcing the code, we often do not want the submission records during the code development process to be seen by others, because the submission process often covers some sensitive information. Therefore there will be 将仓库中所有 commit 合成一个a demand for .

Intuitively, rebase and squash or reset are often used, but I tried it and there is a problem, and there will still be two commits left in the end.

Next, I will share three available methods, and briefly introduce why not to use them rebase.

Method 1: git commit --amend (official recommendation)

This method means additional submission, which is most in line with the principle of using git and is also the lightest. I recommend using this method, which is also the official git recommended method.

git logFirst check the id of the first commit on the github page or use :

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

The meaning of these two lines of instructions is:

  1. Switch the state of the current branch to the first commit, and retain the local modifications and the settings of the temporary storage area;
  2. Amend the contents of the current staging area directly to the previous commit (referring to the first commit here).

After running these two lines of instructions, a new edit box will pop up, requiring you to fill in the commit message. The default commit message is your first commit message, if you need to modify it, just modify it.

insert image description here

Note that if you don't want to keep the author information of the first commit, you can add another parameter --reset-authorto wipe it out:

git commit --amend --reset-author

Method 2: Create a new local git warehouse

This method is the most intuitive and direct, and of course there is nothing left after the new one is created.
However, it is cumbersome to operate, and you need to delete the folder and adjust the current directory.

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

Method 3: Create a new blank sub-branch

This method is also very intuitive, that is, create a new blank sub-branch, and then directly name the sub-branch as the original main branch.
However, it is a bit evil when pushing, and it is easy to make mistakes if it is not done well. It is not recommended to use it, but it can be used to understand orphanthe parameters.

# 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

Note that the master branch may mainor may not be called master.

Why is rebase not recommended for this merge operation?

When rebase is used to compress commit, it often goes like this:

  1. git rebase -i HEAD~n, where nis the number of commits to be merged;
  2. A new editing window pops up, select (pick) a branch, compress (squash) other branches:
    pick commitid
    s commitid1
    s commitid2
    
  3. Save and exit.

The rebase git command only looks at the name, which probably means to reset the base commit. Therefore, when it is used, it needs a base commit, and its pick, squash and other operations are all based on this base.

Take the second step in the above-mentioned process to explain. In this step, the base commit is actually commitid. parent commitThe actual operation it does is to switch to the parent commit first, and then perform cherry-pickand squashoperate in the parent commit . Then resubmit.

And the reason why you can't use rebase to merge all commits in the warehouse is simply because of its mechanism:

  1. The original commit, which does not have its base commit. So you can't use rebase to pick the first commit.
  2. When you do not pick each commit, the compressed commit will not know which commit to save to.

So if you want to use the squash (compression) provided in rebase to compress all branches and compress them into a single commit, then during the rebase operation, either the base commit cannot be found and the command runs directly and an error occurs, or you do not know the commit after the compression is completed. Report the error to anyone.

And these error reports are difficult to understand for a person who just wants to simply submit a code when they are processed.

If you don't believe me, here is an example.

If there are 3 commits in total, the id of the first commit is d2d48778as follows:

insert image description here

When merging with rebase, only the last two commits can be operated.
If you force 3 operations, the following command is run:

git rebase -i HEAD~3

Then you will get an error result fatal: invalid upstream 'HEAD~3':

insert image description here

If you run git rebase -i HEAD~2then everything will work fine.

And if you find something is wrong, so just go directly to rebase the first commit, and run the following command:

git rebase -i d2d48778

Then you will not get an error, but you will get the following edit box, without the id of the first commit:

insert image description here

At this point, intuitively speaking, we will definitely change the pick to squash regardless, hoping for a miracle. But when we save and exit, we will find that there is an error error: cannot 'squash' without a previous commit, requiring that a previous commit must be selected as the commit stored as the result of compression:

insert image description here

That being the case, just add a new line manually, pickokay? Forcibly specify the first commit as the commit that stores squash results, as follows:

insert image description here

Actually, that doesn't work either. The reason is that the first commit does not have the previous commit and cannot be cherry-picked at all. If you do this, then you will get an error The previous cherry-pick is now empty, possibly due to conflict resolution., which is consistent with my description, as shown in the following figure:

insert image description here

You may have also noticed that git officially gave a solution, that is git commit --allow-empty, so, what is the result of its solution? After running this line of command, a new edit box pops up asking to enter the commit message, and then view the current git log, as shown in the following two figures:

insert image description here
insert image description here

You'd be surprised to find that there are still two commits.

What's even more frightening is that when you finally remember to check your git status, you will find that the operation log is gone, the rebase has not been executed, and the local modifications have disappeared. As shown below:

insert image description here

Although in fact, the local modification is actually still in the local commit file, but because you don’t know how to rebase, after all kinds of rebase failures, you may have forgotten the commitid of the latest code, or you have accidentally pushed and updated the remote The warehouse, or you have forgotten what you want to change, the final result may be a crash.

In fact git status, at , the git command line already shows all the solutions to this problem:

  1. You can modify your rebase operation, use git rebase --edit-todo, let it pick the second commit, based on the first commit, so that at least your code files can be preserved, but the first commit will be redundant.
  2. Instead of messing around with rebase like you do now, you can use git commit --amendoperations and just do simple appends. For details, please refer to Method 1 of this article .
  3. You can re-execute the rebase operation, using git rebase --continue, if you insist that you are correct. (Of course, doing so will only lead to continued error reporting)

To sum up, in order to clarify why I don’t use rebase when merging all commits, I simply thought about and described the principle and mechanism of rebase, hoping to help people who encounter this problem.

In addition, most of the mechanisms are directly seen or guessed through operations, only combined with git output information, not combined with official description documents. If there are any mistakes, please leave a message in the comment area to correct them.

All articles on this account are original, welcome to reprint, please indicate the source of the article: https://blog.csdn.net/qq_46106285/article/details/130459829 . Baidu and various collection sites are not trustworthy, please be careful when searching. Technical articles are generally time-sensitive. I am used to revising and updating my blog posts from time to time, so please visit the source to view the latest version of this article.

Guess you like

Origin blog.csdn.net/qq_46106285/article/details/130459829