修剪 Git 提交/压缩 Git 历史记录

发布于 2024-08-22 03:14:03 字数 169 浏览 5 评论 0原文

我每隔几分钟左右就会将我的代码检查到 Git 分支中,而评论最终会变成“一切都重新开始”之类的荒谬内容。

然后,每隔几分钟/几小时/几天,我就会认真提交一个真实的评论,例如“修复错误#22.55,第三次”。 如何区分这两个概念?我希望能够删除所有频繁提交,只留下严重的提交。

I check my code into a Git branch every few minutes or so, and the comments end up being things like "Everything broken starting again" and other absurdities.

Then every few minutes/hours/days I do a serious commit with a real comment like, "Fixed bug #22.55, 3rd time." How can I separate these two concepts? I would like to be able to remove all my frequent-commits and just leave the serious ones.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

っ左 2024-08-29 03:14:03

编辑答案现在(在本条目的后半部分)新的 Git1.7 修复! action 和 --autosquash 选项用于快速提交重新排序和消息编辑。


首先,经典的压缩过程,如 Git1.7 之前所做的那样。
(Git1.7 具有相同的过程,只是通过自动提交重新排序(而不是手动重新排序)的可能性以及通过更干净的压缩消息来加快速度)

我希望能够删除所有频繁签到的内容,只留下严重的签到。

这称为压缩提交
您在此 Git 准备就绪文章:
(注:rebase交互功能自 2007 年 9 月以来出现,并允许压缩、拆分、删除或重新排序提交:另请参阅 GitPro 页面)

警告一句:仅对尚未推送到外部存储库的提交执行此操作。如果其他人的工作基于您要删除的提交,则可能会发生大量冲突。如果您的历史记录已与他人共享,请不要重写。

“替代文本”

如果最后 4 次提交打包在一起会更愉快

$ git rebase -i HEAD~4

选择 01d1124 添加许可证
pick 6340aaa 将许可证移至其自己的文件中
pick ebfd367 Jekyll 已经有了自我意识。
pick 30e0ccb 也更改了二进制文件中的标语。

# 将 60709da..30e0ccb 重新设置为 60709da
#
# 命令:
# p, pick = 使用提交
# e, edit = 使用提交,但停止修改
# s, squash = 使用提交,但合并到之前的提交中
#
# 如果你在这里删除一行,那么提交将会丢失。
# 但是,如果删除所有内容,变基将会中止。
#

使用 HEADHEAD~4 所在位置的最后四次提交进行变基。
我们只是将所有内容压缩到一次提交中。
因此,将文件的前四行更改为此:

pick 01d1124 添加许可证
挤压 6340aaa 将许可证移至其自己的文件中
壁球 ebfd367 Jekyll 已经有了自我意识。
壁球 30e0ccb 也更改了二进制文件中的标语。

基本上,这告诉 Git 将所有四个提交合并到列表中的第一个提交中。完成并保存后,另一个编辑器会弹出以下内容:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   LICENSE
#   modified:   README.textile
#   modified:   Rakefile
#   modified:   bin/jekyll
#

由于我们合并了如此多的提交,Git 允许您根据该过程中涉及的其余提交来修改新提交的消息。根据需要编辑消息,然后保存并退出。
完成后,您的提交已成功压缩!

已创建提交 0fc4eea:创建许可证文件,并使 jekyll 具有自我意识。
 更改了 4 个文件,插入了 27 个(+),删除了 30 个(-)
  创建模式 100644 许可证
  成功地重新设定并更新了 refs/heads/master。

如果我们再次回顾历史......

“替代文本”


注意:为了“提交压缩”目的,Git1.7(2010 年 2 月)引入了 2 个新元素(如 达斯汀在评论中):

  • "git rebase -i”学习了新操作“fixup”,该操作会压缩更改但不会影响现有日志消息。
  • git rebase -i”还学习了 --autosquash 选项,该选项与新的“fixup”操作一起使用。


两者(修复操作和 --autosquash 选项)均在此 Thechnosorcery Networks 博客条目。自2009 年 6 月以来,这些功能一直在酝酿之中,并引发了进一步的争论去年 12 月

fixup 操作或指令用于压缩您在 rebase --interactive 的提交编辑列表中手动重新排序的提交,同时忽略第二个提交消息,这将使消息编辑步骤更快(您可以保存它:压缩的提交将仅包含第一个提交消息)
生成的提交消息将只是第一个提交消息。

  # s, squash = use commit, but meld into previous commit
  # f, fixup = like "squash", but discard this commit's log message

--autosquash 选项用于自动为您进行提交重新排序过程:

如果您知道要将某些内容压缩到哪个提交中,您可以使用“squash!”消息来提交它。 $other_commit_subject”。然后,如果您运行@git rebase --interactive --autosquash commitish@,该行将自动设置为squash,并放置在主题为$other_commit_subject的提交下方。

(实际上,squash! 只能使用另一个提交消息的开头

$ vim Foo.txt
$ git commit -am "Change all the 'Bar's to 'Foo's"
[topic 8374d8e] Change all the 'Bar's to 'Foo's
 1 files changed, 2 insertions(+), 2 deletions(-)
$ vim Bar.txt
$ git commit -am "Change all the 'Foo's to 'Bar's"
[topic 2d12ce8] Change all the 'Foo's to 'Bar's
 1 files changed, 1 insertions(+), 1 deletions(-)

$ vim Foo.txt
$ git commit -am "squash! Change all the 'Bar's"
[topic 259a7e6] squash! Change all the 'Bar's
 1 files changed, 2 insertions(+), 1 deletions(-)

看到了吗?这里第三提交仅使用第一提交消息的开头。
rebase --interactive --autosquash 会将压缩的提交移至相关提交下方:

pick 8374d8e Change all the 'Bar's to 'Foo's
squash 259a7e6 squash! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

消息版本为:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# This is the 2nd commit message:

squash! Change all the 'Bar's

这意味着默认情况下您将在提交消息中记录压缩操作。
但通过修复!指令,您可以在提交消息中保持压缩“不可见”,同时仍然受益于使用 --autosquash 选项的自动提交重新排序(事实上,您的第二个提交消息基于第一个提交消息)提交你想被压扁的)。

pick 8374d8e Change all the 'Bar's to 'Foo's
fixup cfc6e54 fixup! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

默认情况下的消息将是:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# The 2nd commit message will be skipped:

#    fixup! Change all the 'Bar's

请注意,fixup! 提交的消息已被注释掉。
您可以按原样保存消息,原始提交消息将被保留
当您意识到忘记添加早期提交的一部分时,非常方便地包含更改

现在,如果您想根据刚刚所做的先前提交进行修复或压缩,Jacob Helwig(Technosorcery Networks 博客条目的作者)建议使用以下别名

[alias]
    fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' -

:进行 rebase 交互,这总是受益于对要压缩的提交的自动重新排序:

[alias]
    ri = rebase --interactive --autosquash

Git 2.18 更新(2018 年第 2 季度):“git rebase -i”有时会留下中间“# This是 N 次提交的组合”消息供人类使用
在某些极端情况下的最终结果中,在编辑器内,
已修复。

请参阅 提交 15ef693提交 dc4b5bc, 提交e12a7ef提交 d5bc6f2(2018 年 4 月 27 日),作者:Johannes Schindelin (dscho)
(由 Junio C Hamano -- gitster -- 合并于 提交 4a3bf32,2018 年 5 月 23 日)

rebase --skip:修复/压缩失败后清理提交消息

在一系列修复/挤压命令期间,交互式变基构建
提交带有评论的消息。这将呈现给用户
如果这些命令中至少有一个是 squash,则编辑器。

无论如何,提交消息最​​终都会被清理,删除
所有这些中间评论,在这样的修复/挤压链的最后一步。

但是,如果此类链中的最后一个修复/挤压命令失败并显示
合并冲突,如果用户决定跳过它(或解决它
到一个干净的工作树,然后继续变基),当前代码
无法清理提交消息。

此提交修复了该行为。

修复过程比表面上看起来要复杂得多,因为它是
不仅仅是关于我们是否要git rebase --skip的问题
修复或挤压。它还涉及删除跳过的修复/挤压
来自累积提交消息的提交消息。这也是关于
我们是否应该让用户编辑最终提交的问题
是否有消息(“链中是否存在挤压,但不是
跳过了
?”)。

例如,在这种情况下,我们想要修复提交消息,但是
不在编辑器中打开它:

pick <- 成功
修复 <- 成功
squash <- 失败,将被跳过

这就是新引入的 current-fixups 文件真正发挥作用的地方
便利。快速查看一下,我们可以确定是否有不可跳过的
壁球。我们只需要确保使其保持最新状态
跳过修复/挤压命令。作为奖励,我们甚至可以避免做出承诺
不必要的,例如当只有一个修复失败时,以及
被跳过。

仅修复最终提交消息未清理的错误
正确地,但如果不修复其余部分,事情会更加复杂
而不是一次性解决所有问题,因此这个提交比
一个问题。


Git 2.19(2018 年第 3 季度)修复了一个错误:当“git rebase -i”被告知将两个或多个提交压缩为一个时,它会用其编号标记每个提交的日志消息。
它正确地将第一个称为“第一次提交”,但下一个是“commit #1”,这是一个偏差(!)。

请参阅 提交 dd2e36e(2018 年 8 月 15 日),作者:Phillip Wood (phillipwood)
(由 Junio C Hamano -- gitster -- 合并于 提交 36fd1e8,2018 年 8 月 20 日)

rebase -i:修复挤压消息中的编号

提交e12a7ef ("rebase -i:处理“ 提交的组合”
GETTEXT_POISON", 2018-04-27, Git 2.18) 改变了单独提交的方式
将提交压缩在一起时,消息会被标记。
在此过程中引入了回归,其中消息的编号减少了 1。此提交修复了该问题并添加了编号测试。


注意:“git rebase -i"( man) 进行了一系列的压缩/修复,当其中一个步骤因冲突而停止并最终被跳过时,没有处理累积的提交日志消息,这已通过 Git 2.42 (Q3 2023)。

请参阅 提交 6ce7afe(2023 年 8 月 3 日),作者:Phillip Wood (phillipwood)
(由 Junio C Hamano -- gitster -- 合并于 提交 e8c53ff,2023 年 8 月 9 日)

rebase --skip:修复提交消息跳过南瓜时清理

签字人:Phillip Wood

在一系列“fixup”和/或“squash”命令期间,交互式变基会从所有被压缩在一起的提交中累积提交消息。< br>
如果其中一个提交在被选择时发生冲突并且用户选择跳过该提交,那么我们需要从累积的消息中删除该提交的消息。

要执行此操作 15ef693 ("rebase --skip: 清理提交消息修复/挤压失败后”,2018-04-27,Git v2.18.0-rc0 -- 第 6 批 中列出的合并)已更新 commit_staged_changes() 当最后一个命令是“fixup”或“squash”并且没有分阶段的更改。
不幸的是,执行此操作的代码包含两个错误。

  1. 如果 parse_head() 失败,我们将无效的指针传递给
    unuse_commit_buffer()。

  2. 重建的消息使用 HEAD 中的整个提交缓冲区
    包括标头,而不仅仅是提交消息。

第一个问题已通过将“if”条件拆分为多个语句来解决,每个语句都有自己的错误处理。
通过使用 find_commit_subject() 在提交缓冲区中查找提交消息的开头来修复第二个问题。

修改了15ef693添加的现有测试以显示此错误的影响.
当跳过链中的第一个命令时会触发该错误(正如在此提交之前的测试一样),但效果是隐藏的,因为 opts->current_fixup_count 设置为零,这会导致 update_squash_messages( ) 从头开始​​重新创建挤压消息文件,覆盖由 commit_staged_changes() 创建的错误消息。
测试还更新为显式检查提交消息,而不是依赖 grep 来确保它们不包含任何杂散提交标头。

Edited answer with now (in the second half of this entry) the new Git1.7 fixup! action and --autosquash option for quick commit reordering and message editing.


First, the classic squashing process, as done before Git1.7.
(Git1.7 has the same process, only made faster by the possibility of automatic commit reordering as opposed to manual reordering, and by cleaner squashing messages)

I would like to be able to remove all my frequent-checkins and just leave the serious ones.

This is called squashing commits.
You have some good example of "comit cleaning" in this Git ready article:
(Note: the rebase interactive feature came along since September 2007, and allows for squashing or splitting or removing or reordering commits: see also the GitPro page)

A word of caution: Only do this on commits that haven’t been pushed an external repository. If others have based work off of the commits that you’re going to delete, plenty of conflicts can occur. Just don’t rewrite your history if it’s been shared with others.

alt text

The last 4 commits would be much happier if they were wrapped up together

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

rebase using the last four commits from where the HEAD is with HEAD~4.
We’re just going to squash everything into one commit.
So, changing the first four lines of the file to this will do the trick:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

Basically this tells Git to combine all four commits into the the first commit in the list. Once this is done and saved, another editor pops up with the following:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   LICENSE
#   modified:   README.textile
#   modified:   Rakefile
#   modified:   bin/jekyll
#

Since we’re combining so many commits, Git allows you to modify the new commit’s message based on the rest of the commits involved in the process. Edit the message as you see fit, then save and quit.
Once that’s done, your commits have been successfully squashed!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
  Successfully rebased and updated refs/heads/master.

And if we look at the history again…

alt text


Note: for "commit squashing" purposes, Git1.7 (February 2010) has introduced 2 new elements (as mentioned by Dustin in the comment):

  • "git rebase -i" learned new action "fixup" that squashes the change but does not affect existing log message.
  • "git rebase -i" also learned --autosquash option that is useful together with the new "fixup" action.

Both (fixup action and --autosquash option) are illustrated in this Thechnosorcery Networks blog entry. Those features have been cooking since last June 2009 and debated further last December.

The fixup action or directive is for squashing a commit you would have manually reordered in the commit edit list of a rebase --interactive, while ignoring the second commit message, which will make the message edition step faster (you can just save it: the squashed commit will have the first commit message only)
The resulting commit message will only be the first commit one.

  # s, squash = use commit, but meld into previous commit
  # f, fixup = like "squash", but discard this commit's log message

The --autosquash option is about making the commit reordering process automatically for you:

If you know what commit you want to squash something in to you can commit it with a message of “squash! $other_commit_subject”. Then if you run @git rebase --interactive --autosquash commitish@, the line will automatically be set as squash, and placed below the commit with the subject of $other_commit_subject.

(Actually, the squash! can only use the beginning of another commit message)

$ vim Foo.txt
$ git commit -am "Change all the 'Bar's to 'Foo's"
[topic 8374d8e] Change all the 'Bar's to 'Foo's
 1 files changed, 2 insertions(+), 2 deletions(-)
$ vim Bar.txt
$ git commit -am "Change all the 'Foo's to 'Bar's"
[topic 2d12ce8] Change all the 'Foo's to 'Bar's
 1 files changed, 1 insertions(+), 1 deletions(-)

$ vim Foo.txt
$ git commit -am "squash! Change all the 'Bar's"
[topic 259a7e6] squash! Change all the 'Bar's
 1 files changed, 2 insertions(+), 1 deletions(-)

See? Here the third commit uses only the beginning of the first commit message.
A rebase --interactive --autosquash will move the squashed commit below the relevant one:

pick 8374d8e Change all the 'Bar's to 'Foo's
squash 259a7e6 squash! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

The message edition would be:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# This is the 2nd commit message:

squash! Change all the 'Bar's

Meaning by default you would keep the squashing operation recorded in the commit message.
But with the fixup! directive, you could keep that squashing "invisible" in the commit message, while still benefiting from the automatic commit reordering with the --autosquash option (and the fact that your second commit message is based on the first commit you want to be squashed with).

pick 8374d8e Change all the 'Bar's to 'Foo's
fixup cfc6e54 fixup! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

The message by default will be:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# The 2nd commit message will be skipped:

#    fixup! Change all the 'Bar's

Notice that the fixup! commit’s message is already commented out.
You can just save out the message as-is, and your original commit message will be kept.
Very handy for including changes when you realize that you forgot to add part of an earlier commit.

Now if you want to fixup or squash based on the previous commit you just did, Jacob Helwig (the author of the Technosorcery Networks blog entry) recommends the following aliases:

[alias]
    fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' -

And for doing a rebase interactive which will always benefit from the automatic reordering of commits meant to be squashed:

[alias]
    ri = rebase --interactive --autosquash

Update for Git 2.18 (Q2 2018): "git rebase -i" sometimes left intermediate "# This is a combination of N commits" message meant for the human consumption
inside an editor in the final result in certain corner cases, which
has been fixed.

See commit 15ef693, commit dc4b5bc, commit e12a7ef, commit d5bc6f2 (27 Apr 2018) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit 4a3bf32, 23 May 2018)

rebase --skip: clean up commit message after a failed fixup/squash

During a series of fixup/squash commands, the interactive rebase builds
up a commit message with comments. This will be presented to the user in
the editor if at least one of those commands was a squash.

In any case, the commit message will be cleaned up eventually, removing
all those intermediate comments, in the final step of such a fixup/squash chain.

However, if the last fixup/squash command in such a chain fails with
merge conflicts, and if the user then decides to skip it (or resolve it
to a clean worktree and then continue the rebase), the current code
fails to clean up the commit message.

This commit fixes that behavior.

The fix is quite a bit more involved than meets the eye because it is
not only about the question whether we are git rebase --skiping a
fixup or squash. It is also about removing the skipped fixup/squash's
commit message from the accumulated commit message. And it is also about
the question whether we should let the user edit the final commit
message or not ("Was there a squash in the chain that was not
skipped
?").

For example, in this case we will want to fix the commit message, but
not open it in an editor:

pick  <- succeeds
fixup <- succeeds
squash    <- fails, will be skipped

This is where the newly-introduced current-fixups file comes in real
handy. A quick look and we can determine whether there was a non-skipped
squash. We only need to make sure to keep it up to date with respect to
skipped fixup/squash commands. As a bonus, we can even avoid committing
unnecessarily, e.g. when there was only one fixup, and it failed, and
was skipped.

To fix only the bug where the final commit message was not cleaned up
properly, but without fixing the rest, would have been more complicated
than fixing it all in one go, hence this commit lumps together more than
a single concern.


Git 2.19 (Q3 2018) fixes a bug: When "git rebase -i" is told to squash two or more commits into one, it labeled the log message for each commit with its number.
It correctly called the first one "1st commit", but the next one was "commit #1", which was off-by-one(!).

See commit dd2e36e (15 Aug 2018) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit 36fd1e8, 20 Aug 2018)

rebase -i: fix numbering in squash message

Commit e12a7ef ("rebase -i: Handle "combination of <n> commits" with
GETTEXT_POISON", 2018-04-27, Git 2.18) changed the way that individual commit
messages are labelled when squashing commits together.
In doing so a regression was introduced where the numbering of the messages is off by one. This commit fixes that and adds a test for the numbering.


Note: "git rebase -i"(man) with a series of squash/fixup, when one of the steps stopped in conflicts and ended up getting skipped, did not handle the accumulated commit log messages, which has been corrected with Git 2.42 (Q3 2023).

See commit 6ce7afe (03 Aug 2023) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit e8c53ff, 09 Aug 2023)

rebase --skip: fix commit message clean up when skipping squash

Signed-off-by: Phillip Wood

During a series of "fixup" and/or "squash" commands, the interactive rebase accumulates a commit message from all the commits that are being squashed together.
If one of the commits has conflicts when it is picked and the user chooses to skip that commit then we need to remove that commit's message from accumulated messages.

To do this 15ef693 ("rebase --skip: clean up commit message after a failed fixup/squash", 2018-04-27, Git v2.18.0-rc0 -- merge listed in batch #6) updated commit_staged_changes() to reset the accumulated message to the commit message of HEAD (which does not contain the message from the skipped commit) when the last command was "fixup" or "squash" and there are no staged changes.
Unfortunately the code to do this contains two bugs.

  1. If parse_head() fails we pass an invalid pointer to
    unuse_commit_buffer().

  2. The reconstructed message uses the entire commit buffer from HEAD
    including the headers, rather than just the commit message.

The first issue is fixed by splitting up the "if" condition into several statements each with its own error handling.
The second issue is fixed by finding the start of the commit message within the commit buffer using find_commit_subject().

The existing test added by 15ef693 is modified to show the effect of this bug.
The bug is triggered when skipping the first command in the chain (as the test does before this commit) but the effect is hidden because opts->current_fixup_count is set to zero which leads update_squash_messages() to recreate the squash message file from scratch overwriting the bad message created by commit_staged_changes().
The test is also updated to explicitly check the commit messages rather than relying on grep to ensure they do not contain any stray commit headers.

昨迟人 2024-08-29 03:14:03

使用软重置而不是 Rebase 来压缩 GIT 历史记录

我认为 VonC 答案的长度很能说明问题——从字面上看——关于 git rebase 有多么复杂是。这是我对我的问题的另一个答案的扩展。

  1. 您有一个从 master 分支的分支 ticket-201。您想假装 ticket-201 的所有提交从未发生过,但您一次性完成了所有工作。
  2. 使用 git reset --soft hash 软重置到分支点,其中 hash 应该是 ticket-201 日志中的提交哈希。
  3. 使用 add then commit 提交更改。现在分支历史记录将只有第一次提交和包含新内容的新提交。

根据不同分支中的任意提交创建历史记录

使用重置,您可以根据需要重写历史记录,尽管您的编辑将失去拥有正确时间戳的魅力。假设您不关心这一点(也许文件上的时间/日期就足够了?),或者如果您想随时修改提交,您可以按照以下步骤操作:

  1. commit0 (假装这是一个哈希): git checkout -b new-history commit0
  2. 现在您可以从 commit5 获取文件: git reset - -hard commit5
  3. 切换回索引点: git reset --soft commit0
  4. 提交,这将是分支中的第二次提交。

这个想法简单、有效、灵活。

Using Soft Reset Instead of Rebase to Squash GIT History

I think the length of VonC's answers speaks volumes -- literally -- about how complicated git rebase is. This is my extension of another answer to a question of mine.

  1. You have a branch ticket-201 that you branched from master. You want to pretend that all the commits from ticket-201 never happened, but that you did all the work in one shot.
  2. Soft reset to the branch point using git reset --soft hash where hash should be a commit hash that is in ticket-201's log.
  3. Commit your changes using add then commit. Now the branch history will only have the first commit and the new one with the new stuff.

Making Up Histories From Arbitrary Commits in Different Branches

Using resets you can rewrite the history as you see fit, though your edits will lose the charm of having the right timestamp. Assuming you don't care about that (the times/dates on your files will be enough, perhaps?), or if you want to fiddle with the commits as you go, you can follow these steps:

  1. Checkout a new branch at commit0 (pretend that's a hash): git checkout -b new-history commit0
  2. Now you can get the files from commit5: git reset --hard commit5
  3. Switch back to your index point: git reset --soft commit0
  4. Commit and this will be the second commit in the branch.

This idea is simple, effective and flexible.

渡你暖光 2024-08-29 03:14:03

改用 Squash

最近,我一直在另一个分支工作并使用 squash。另一个分支称为 temp,然后我使用 git merge temp --squash 将其带入推送到服务器的真实分支。

工作流程是这样的,假设我在 Ticket65252 中工作:

git branch -d temp #remove old temp bbranch
git checkout -b temp
# work work work, committing all the way
git checkout Ticket65252
git merge temp --squash
git commit -m "Some message here"

使用 rebase 的优点?方式没那么复杂。

与使用 reset --hard 然后使用 reset --soft 相比有何优势? 不易混淆且不易出错。

Using Squash Instead

Recently, I've been working in another branch and using squash. The other branch is called temp, and then I use git merge temp --squash to bring it into the real branch that gets pushed to the server.

Workflow is something like this, assuming I'm working in Ticket65252:

git branch -d temp #remove old temp bbranch
git checkout -b temp
# work work work, committing all the way
git checkout Ticket65252
git merge temp --squash
git commit -m "Some message here"

Advantages over using rebase? Way less complicated.

Advantages over using reset --hard and then reset --soft? Less confusing and slightly less error prone.

偏爱自由 2024-08-29 03:14:03

使用 git rebase -i 来选择并压缩您的提交。

Use git rebase -i to pick and squash your commits together.

扬花落满肩 2024-08-29 03:14:03

对于 git 版本 2.xx 及更高版本,简单的方法是使用 --深度 NN 将存储库克隆到新位置,使用比上次提交更高的数字用户可能已经提交了更改并将其推回。

刚刚保存的存储库将具有“初始提交”和 NN 提交。

此时您可以删除旧的存储库

With git version 2.xx and newer, the easy method is to clone the repo to a new location using --depth NN, use a number higher than the last commit your users may have, and then just, commit a change and push it back.

The just saved repo will have "Initial Commit" with NN commits in place.

At this point you can delete your old repo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文