我如何将最后的 N 次提交压缩在一起?

问题描述:

如何将我最后的 N 个提交压缩为一个提交?

解决方案1:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

无需 git rebase 或 git merge --squash 即可轻松完成此操作。在此示例中,我们将压缩最后 3 次提交。

如果您想从头开始编写新的提交消息,这就足够了:

git reset --soft HEAD~3 &&
git commit

如果您想开始编辑带有现有提交消息的串联的新提交消息(即类似于 pick/squash/squash/…/squash git rebase -i 指令列表将开始您的内容),那么您需要提取那些消息并将它们传递给 git commit:

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

这两种方法都以相同的方式将最后三个提交压缩成一个新的提交。软重置只是将 HEAD 重新指向您不想压缩的最后一个提交。软重置不会触及索引和工作树,从而使索引处于新提交所需的状态(即,它已经包含了您即将“丢弃”的提交的所有更改)。

哈!我喜欢这种方法。这是一个接近问题的精神。可惜它需要这么多巫术。应该将这样的内容添加到基本命令之一中。可能是 git rebase --squash-recent,甚至是 git commit --amend-many。

@ABB:如果您的分支有“上游”集,那么您可以使用 branch@{upstream} (或仅 @{upstream} 用于当前分支;在这两种情况下,最后一部分都可以缩写为 @{u};请参阅gitrevisions)。这可能与您的“上次推送的提交”不同(例如,如果其他人推送了构建在您最近推送之上的内容,然后您获取了该内容),但似乎它可能接近您想要的。

这有点要求我push -f,否则它很可爱,谢谢。

@2rs2ts git push -f 听起来很危险。注意只压缩本地提交。永远不要触摸推送的提交!

之后我还需要使用 git push --force 以便它接受提交

解决方案2:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

使用 git rebase -i 并将第二次和后续提交中的“pick”替换为“squash”或“fixup”,如 the manual 中所述。

在此示例中, 是 SHA1 散列或与当前分支的 HEAD 的相对位置,从该分支中分析 rebase 命令的提交。例如,如果用户希望查看当前 HEAD 过去的 5 次提交,则命令为 git rebase -i HEAD~5。

是什么意思?

是提交 X+1,即您要压缩的最早提交的父级。

如果您已经推送了提交,则需要推送 -f 以强制将远程分支移动到新提交。不过,这会让任何在旧提交之上工作的人感到不安。

这种 rebase -i 方法与 reset --soft 的区别在于,rebase -i 允许我保留提交作者,而 reset --soft 允许我重新提交。有时我需要压缩拉取请求的提交,同时维护作者信息。有时我需要在自己的提交上重置软。无论如何都对这两个很好的答案表示赞成。

Use git rebase -i and replace "pick" on the second and subsequent commits with "squash" or "fixup", as described in the manual. 呃呃呃呃呃呃呃?

解决方案3:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

为此,您可以使用 git merge --squash,它比 git rebase -i 稍微优雅一些。假设您在 master 上,并且想要将最后 12 个提交压缩为一个。

警告:首先确保您提交您的工作 - 检查 git status 是否干净(因为 git reset --hard 将丢弃分阶段和非分阶段的更改)

然后:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

documentation for git merge 更详细地描述了 --squash 选项。

更新:与 Chris Johnsen 在 his answer 中建议的更简单的 git reset --soft HEAD~12 && git commit 相比,此方法的唯一真正优势是,您可以在提交消息中预先填充您要压缩的每条提交消息。

@Mark Amery:我说这更优雅的原因有很多。例如,它不涉及不必要地生成编辑器,然后在“待办事项”文件中搜索和替换字符串。使用 git merge --squash 也更易于在脚本中使用。本质上,原因是您根本不需要 git rebase -i 的“交互性”。

尽管我很欣赏这样的重大更改具有详细提交消息的优势,但与 Chris 相比,此方法还有一个真正的缺点:进行 hard 重置({ 1}) 涉及更多文件。例如,如果您使用 Unity3D,您会喜欢更少的文件被触摸。

另一个优点是,与变基相比,git merge --squash 在面对移动/删除/重命名时不太可能产生合并冲突,尤其是当您从本地分支合并时。 (免责声明:仅基于一次经验,如果在一般情况下这不是真的,请纠正我!)

当涉及到硬重置时,我总是非常不情愿 - 我会使用临时标签而不是 HEAD@{1} 只是为了安全起见,例如当您的工作流程因停电等而中断一个小时时。

@BT:破坏了你的承诺? :( 我不确定你的意思。你提交的任何内容都可以很容易地从 git 的 reflog 中恢复。如果你有未提交的工作,但文件是暂存的,你应该仍然能够得到他们的内容回来了,although that will be more work。但是,如果您的工作甚至没有上演,恐怕没有什么可以做的;这就是为什么答案预先说:“首先检查 git status 是否干净(因为 git reset --hard 将丢弃分阶段和非分阶段的更改)”。

解决方案4:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

我建议尽可能避免使用 git reset ——尤其是对于 Git 新手。除非您真的需要基于提交的 number 次自动化流程,否则还有一种不那么奇特的方式…

将要被压缩的提交放在工作分支上(如果它们还没有的话)——为此使用 gitk 检查目标分支(例如“master”) git merge --squash (工作分支名称) git commit

提交消息将基于壁球预先填充。

这是最安全的方法:不使用重置软/硬(!!),或使用 reflog!

如果您在 (1) 上进行扩展,那就太好了。

@Adam:基本上,这意味着使用 gitk 的 GUI 界面来标记要压缩的代码行,并标记要压缩到的基础。在正常情况下,这两个标签都已经存在,因此可以跳过步骤(1)。

请注意,此方法不会将工作分支标记为完全合并,因此删除它需要强制删除。 :(

对于 (1),我发现 git branch your-feature && git reset --hard HEAD~N 是最方便的方式。但是,它确实再次涉及 git reset ,这个答案试图避免。

解决方案5:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

感谢 this handy blog post,我发现您可以使用此命令来压缩最后 3 次提交:

git rebase -i HEAD~3

这很方便,因为即使您在没有跟踪信息/远程仓库的本地分支上也可以使用。

该命令将打开交互式 rebase 编辑器,然后您可以按照正常方式重新排序、压缩、改写等。

使用交互式变基编辑器:

交互式变基编辑器显示最后三个提交。此约束由 HEAD~3 在运行命令 git rebase -i HEAD~3 时确定。

最近的提交 HEAD 首先显示在第 1 行。以 # 开头的行是评论/文档。

显示的文档非常清晰。在任何给定的行上,您都可以将命令从 pick 更改为您选择的命令。

我更喜欢使用命令 fixup 因为这会将提交的更改“压缩”到上一行的提交中并丢弃提交的消息。

由于第 1 行的提交是 HEAD,因此在大多数情况下,您会将其保留为 pick。您不能使用 squash 或 fixup,因为没有其他提交可以将提交压缩到。

您还可以更改提交的顺序。这使您可以压缩或修复按时间顺序不相邻的提交。

https://i.stack.imgur.com/JYUt2.png

一个实用的日常示例

我最近提交了一个新功能。从那时起,我已经提交了两个错误修复。但是现在我在我提交的新功能中发现了一个错误(或者可能只是一个拼写错误)。多么烦人!我不希望新的提交污染我的提交历史!

我要做的第一件事是修复错误并使用注释 squash this into my new feature! 进行新的提交。

然后我运行 git log 或 gitk 并获取新功能的提交 SHA(在本例中为 1ff9460)。

接下来,我使用 git rebase -i 1ff9460~ 调出交互式变基编辑器。提交 SHA 后的 ~ 告诉编辑器将该提交包含在编辑器中。

接下来,我将包含修复 (fe7f1e0) 的提交移动到功能提交下方,并将 pick 更改为 fixup。

关闭编辑器时,修复将被压缩到功能提交中,我的提交历史看起来很干净!

当所有提交都是本地的时,这很有效,但是如果您尝试更改已推送到远程的任何提交,您真的会给签出同一分支的其他开发人员带来问题!

https://i.stack.imgur.com/vzlVd.png

你必须选择最上面的一个,然后把剩下的压扁吗?您应该编辑您的答案以更详细地解释如何使用交互式变基编辑器

是的,在第 1 行保留 pick。如果您在第 1 行的提交中选择 squash 或 fixup,git 将显示一条消息“错误:在没有先前提交的情况下无法 'fixup'”。然后它会给你修复它的选项:“你可以用'git rebase --edit-todo'修复它,然后运行'git rebase --continue'。”或者您可以中止并重新开始:“或者您可以使用 'git rebase --abort' 中止 rebase。”。

我一直在使用这个命令。我建议添加一个名为 gr3 的别名:alias gr3='git rebase -i HEAD~3'

@Timo,正确。最旧的在顶部,最新的在底部。这就是您需要 pick 第一行的原因。当您在一行中选择 squash 或 fixup 时,它会将更改放入上一行的提交中。

当您知道要压缩一定数量的提交或至少看到可以通过输入任意数字压缩的提交时,这感觉就像是最好的答案。一般来说,我使用这个 .

解决方案6:

huntsbot.com – 高效赚钱,自由工作

2020 年没有变基的简单解决方案:

git reset --soft HEAD~2 
git commit -m "new commit message"
git push -f

2 意味着最后两次提交将被压缩。您可以用任何数字替换它

不应该鼓励这种解决方案。在 push 中使用 -f (force) 选项是一种危险的做法,尤其是当您推送到共享存储库(即公共历史记录)时,这会使贡献者的生活变得困难

如果目标是将此新提交添加到 master 作为正在进行的 pr 的一部分,您可以使用 git reset --soft $(git merge-base feature master),然后使用 git commit。

@FXQuantTrader:如果每个人都强制推动,情况恰恰相反。几乎总是需要使用 --force 进行推送。这样做可以使您与团队的其他成员和不同的远程位置保持一致,因为您知道发生了什么。你也知道历史的哪一部分已经稳定了。没必要隐瞒。

我认为实际上应该鼓励使用 force 推送,因为这种方法的影响非常好——强制推送与 rebase 和工作同步齐头并进,所以它更好,在我的拙见,更多的人知道这个动作的效果,而不是成为人们害怕使用的公开命令。

同意 Matheus 的观点,强制推送到特性分支很好,应该鼓励使用 rebase。无论如何,直接推送到 main 应该始终受到限制。

解决方案7:

huntsbot.com – 高效赚钱,自由工作

基于 Chris Johnsen’s answer,

从 bash 添加一个全局“squash”别名:(或 Windows 上的 Git Bash)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'

…或使用 Windows 的命令提示符:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"

您的 ~/.gitconfig 现在应该包含此别名:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"

用法:

git squash N

…它会自动将最后的 N 提交压缩在一起,包括在内。

注意:生成的提交消息是所有压缩提交的组合,按顺序排列。如果您对此不满意,您可以随时git commit --amend手动修改它。 (或者,编辑别名以符合您的口味。)

有趣,但我更愿意自己键入压缩的提交消息,作为我多次提交的描述性摘要,而不是为我自动输入它。所以我宁愿指定 git squash -m "New summary." 并将 N 自动确定为未推送提交的数量。

@ABB,这听起来像是一个单独的问题。 (我不认为这正是 OP 所要求的;我从来没有觉得在我的 git squash 工作流程中需要它。)

这很甜蜜。就我个人而言,我想要一个使用来自第一个压在一起的提交的提交消息的版本。对于空格调整之类的东西会很好。

@funroll 同意。只是删除最后一次提交消息对我来说是一个非常普遍的需求。我们应该能够设计...

@ABB,您可以使用 git commit --amend 进一步更改消息,但此别名可让您对提交消息中的内容有一个良好的开端。

解决方案8:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

在您想要合并提交的分支中,运行:

git rebase -i HEAD~(n number of commits back to review)

例子:

git rebase -i HEAD~2

这将打开文本编辑器,如果您希望将这些提交合并在一起,则必须将每个提交前面的“pick”切换为“squash”。从文档:

p, 选择 = 使用提交

s, squash = 使用提交,但融合到之前的提交中

例如,如果您希望将所有提交合并为一个,则“pick”是您所做的第一个提交,所有未来的提交(位于第一个下方)都应设置为“squash”。如果使用 vim,请在插入模式下使用 :x 保存并退出编辑器。

然后继续变基:

git add .

git rebase --continue

有关重写提交历史记录的此方法和其他方法的更多信息,请参阅this helpful post

还请解释 --continue 和 vim :x 的作用。

在您使用 git add 文件中的正确配置之后,您使用 git rebase --continue 移动到下一个提交并开始合并,rebase 将在通过您的分支上的提交时以块的形式发生。 :x 是使用 vim 时保存文件更改的命令,请参阅 this

解决方案9:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

为此,您可以使用以下 git 命令。

 git rebase -i HEAD~n

n(=4 here) 是最后一次提交的次数。然后你有以下选项,

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....

像下面这样更新 pick 一个提交,squash 其他提交到最新的,

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....

详情请点击Link

有关 git rebase -interactive here 上的 SO 的更多详细信息

解决方案10:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

如果您使用 TortoiseGit,您可以使用函数 Combine to one commit:

打开 TortoiseGit 上下文菜单 选择显示日志 在日志视图中标记相关提交 从上下文菜单中选择合并到一个提交

https://i.stack.imgur.com/IPL9i.png

此功能自动执行所有必要的单个 git 步骤。不幸的是,仅适用于 Windows。

据我所知,这不适用于合并提交。

虽然它没有被任何其他人评论,但这甚至适用于不在 HEAD 的提交。例如,我需要在推送之前用更合理的描述来压缩我所做的一些 WIP 提交。工作得很漂亮。当然,我还是希望能通过命令来学习。

这太棒了!只需单击几下鼠标即可完成所有操作,我可以在归档之前合并 200 个旧仓库的提交!谢谢。使分支树干净并立即轻松查看代码更改非常有用。

解决方案11:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

根据 this article,我发现这种方法更适合我的用例。

我的 ‘dev’ 分支领先于 ‘origin/dev’ 96 次提交(因此这些提交尚未推送到远程)。

在推动更改之前,我想将这些提交压缩为一个。我更喜欢将分支重置为 ‘origin/dev’ 的状态(这将使 96 次提交的所有更改都未暂存),然后立即提交更改:

git reset origin/dev
git add --all
git commit -m 'my commit message'

正是我需要的。从我的功能分支中压缩提交,然后我 git cherry 选择该提交到我的 master 中。

这不会压缩以前的提交!

你能详细说明一下@igorGanapolsky 吗?

@trudolf这并不是真正的挤压(挑选个人提交挤压)。这更像是一次提交所有更改。

是的,因此它将您的所有提交压缩为一个。恭喜!

原文链接:https://www.huntsbot.com/qa/5DdM/how-do-i-squash-my-last-n-commits-together?lang=zh_CN

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

你可能感兴趣的:(git,github,hbase,bash)