如何将所有 git 提交压缩为一个?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1657017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 07:17:49  来源:igfitidea点击:

How to squash all git commits into one?

gitrebasegit-rebasesquashgit-rewrite-history

提问by Verhogen

How do you squash your entire repository down to the first commit?

您如何将整个存储库压缩到第一次提交?

I can rebase to the first commit, but that would leave me with 2 commits. Is there a way to reference the commit before the first one?

我可以重新调整到第一次提交,但这会给我留下 2 次提交。有没有办法在第一个之前引用提交?

采纳答案by Pat Notz

Perhaps the easiest way is to just create a new repository with current state of the working copy. If you want to keep all the commit messages you could first do git log > original.logand then edit that for your initial commit message in the new repository:

也许最简单的方法是创建一个具有当前工作副本状态的新存储库。如果您想保留所有提交消息,您可以先做git log > original.log,然后在新存储库中为您的初始提交消息编辑它:

rm -rf .git
git init
git add .
git commit

or

或者

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log

回答by Jordan Lewis

As of git 1.6.2, you can use git rebase --root -i.

git 1.6.2 开始,您可以使用git rebase --root -i.

For each commit except the first, change pickto squash.

对于除第一个提交之外的每个提交,更改picksquash.

回答by ryenus

Update

更新

I've made an alias git squash-all.
Example usage: git squash-all "a brand new start".

我已经做了一个别名git squash-all
示例用法git squash-all "a brand new start"

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

Caveat: remember to provide a comment, otherwise the default commit message "A new start" would be used.

警告:记得提供注释,否则将使用默认提交消息“A new start”。

Or you can create the alias with the following command:

或者您可以使用以下命令创建别名:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'


One Liner

一个班轮

git reset $(git commit-tree HEAD^{tree} -m "A new start")

Note: here "A new start" is just an example, feel free to use your own language.

注意:这里的“ A new start”只是一个例子,请随意使用您自己的语言。

TL;DR

TL; 博士

No need to squash, use git commit-treeto create an orphan commit and go with it.

无需压缩,用于git commit-tree创建孤立提交并使用它。

Explain

解释

  1. create a single commit via git commit-tree

    What git commit-tree HEAD^{tree} -m "A new start"does is:

    Creates a new commit object based on the provided tree object and emits the new commit object id on stdout. The log message is read from the standard input, unless -m or -F options are given.

    The expression HEAD^{tree}means the tree object corresponding to HEAD, namely the tip of your current branch. see Tree-Objectsand Commit-Objects.

  2. reset the current branch to the new commit

    Then git resetsimply reset the current branch to the newly created commit object.

  1. 通过创建单个提交 git commit-tree

    什么git commit-tree HEAD^{tree} -m "A new start"是:

    基于提供的树对象创建一个新的提交对象,并在标准输出上发出新的提交对象 ID。日志消息是从标准输入读取的,除非给出 -m 或 -F 选项。

    表达式HEAD^{tree}表示对应于 的树对象HEAD,即您当前分支的尖端。请参阅树对象提交对象

  2. 将当前分支重置为新的提交

    然后git reset简单地将当前分支重置为新创建的提交对象。

This way, nothing in the workspace is touched, nor there's need for rebase/squash, which makes it really fast. And the time needed is irrelevant to the repository size or history depth.

这样,工作区中的任何内容都不会被触及,也不需要 rebase/squash,这使得它非常快。所需的时间与存储库大小或历史深度无关。

Variation: New Repo from a Project Template

变化:来自项目模板的新回购

This is useful to create the "initial commit" in a new project using another repository as the template/archetype/seed/skeleton. For example:

这对于使用另一个存储库作为模板/原型/种子/骨架在新项目中创建“初始提交”很有用。例如:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

This avoids adding the template repo as a remote (originor otherwise) and collapses the template repo's history into your initial commit.

这避免了将模板存储库添加为远程(origin或其他)并将模板存储库的历史记录折叠到您的初始提交中。

回答by ryenus

If all you want to do is squash all of your commits down to the root commit, then while

如果您只想将所有提交压缩到根提交,那么同时

git rebase --interactive --root

can work, it's impractical for a large number of commits (for example, hundreds of commits), because the rebase operation will probably run very slowly to generate the interactive rebase editor commit list, as well as run the rebase itself.

可以工作,对于大量提交(例如数百次提交)是不切实际的,因为 rebase 操作可能会运行得很慢,以生成交互式 rebase 编辑器提交列表,以及运行 rebase 本身。

Here are two quicker and more efficient solutions when you're squashing a large number of commits:

当您压缩大量提交时,这里有两个更快、更有效的解决方案:

Alternative solution #1: orphan branches

替代解决方案 #1:孤立分支

You can simply create a new orphan branch at the tip (i.e. the most recent commit) of your current branch. This orphan branch forms the initial root commit of an entirely new and separate commit history tree, which is effectively equivalent to squashing all of your commits:

您可以简单地在当前分支的尖端(即最近的提交)创建一个新的孤立分支。这个孤立分支形成了一个全新的、独立的提交历史树的初始根提交,这实际上等同于压缩所有提交:

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

Documentation:

文档:

Alternative solution #2: soft reset

替代解决方案#2:软复位

Another efficient solution is to simply use a mixed or soft reset to the root commit <root>:

另一个有效的解决方案是简单地对根提交使用混合或软重置<root>

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

Documentation:

文档:

回答by kusma

echo "message" | git commit-tree HEAD^{tree}

This will create an orphaned commit with the tree of HEAD, and output it's name (SHA-1) on stdout. Then just reset your branch there.

这将创建一个带有 HEAD 树的孤立提交,并在标准输出上输出它的名称(SHA-1)。然后只需在那里重置您的分支。

git reset SHA-1

回答by Logan

Here's how I ended up doing this, just in case it works for someone else:

这是我最终这样做的方式,以防万一它适用于其他人:

Remember that there's always risk in doing things like this, and its never a bad idea to create a save branch before starting.

请记住,做这样的事情总是有风险的,在开始之前创建一个保存分支从来都不是一个坏主意。

Start by logging

从记录开始

git log --oneline

Scroll to first commit, copy SHA

滚动到第一次提交,复制 SHA

git reset --soft <#sha#>

Replace <#sha#>w/ the SHA copied from the log

使用<#sha#>从日志中复制的 SHA替换

git status

Make sure everything's green, otherwise run git add -A

确保一切都是绿色的,否则运行 git add -A

git commit --amend

Amend all current changes to current first commit

将所有当前更改修改为当前第一次提交

Now force push this branch and it will overwrite what's there.

现在强制推送这个分支,它将覆盖那里的内容。

回答by R. Martinho Fernandes

I read something about using grafts but never investigated it much.

我读过一些关于使用移植物的文章,但从未对其进行过多研究。

Anyway, you can squash those last 2 commits manually with something like this:

无论如何,您可以使用以下内容手动压缩最后 2 个提交:

git reset HEAD~1
git add -A
git commit --amend

回答by CB Bailey

The easiest way is to use the 'plumbing' command update-refto delete the current branch.

最简单的方法是使用“管道”命令update-ref删除当前分支。

You can't use git branch -Das it has a safety valve to stop you deleting the current branch.

您不能使用,git branch -D因为它有一个安全阀来阻止您删除当前分支。

This puts you back into the 'initial commit' state where you can start with a fresh initial commit.

这使您回到“初始提交”状态,您可以在其中开始新的初始提交。

git update-ref -d refs/heads/master
git commit -m "New initial commit"

回答by Frerich Raabe

First, squash all your commits into a single commit using git rebase --interactive. Now you're left with two commits to squash. To do so, read any of

首先,使用git rebase --interactive. 现在你只剩下两次提交来压缩了。为此,请阅读任何

回答by kyb

In one line of 6 words

一行6个字

git checkout --orphan new_root_branch  &&  git commit