使用Git将我的最后一个X提交一起压缩


3585

如何使用Git将最后的X个提交一起压缩为一个提交?




2
@matt TortoiseGit是您的工具。它提供了一个单一功能“ Combine to a commit”,它将在后台自动调用所有步骤。不幸的是,仅适用于Windows。请参阅下面的答案。
Matthias M

1
对于高达挤压第一次提交看到这- stackoverflow.com/questions/1657017/...
goelakash

1
后壁球一个需要做的推推stackoverflow.com/questions/10298291/…–
vikramvi

Answers:


2091

git rebase -i <after-this-commit>本手册所述,第二次及以后的提交中使用“ pick”并将其替换为“ squash”或“ fixup”

在此示例中,<after-this-commit>是SHA1哈希或当前分支的HEAD中的相对位置,从该分支中​​分析提交的rebase命令。例如,如果用户过去希望查看当前HEAD的5个提交,则命令为git rebase -i HEAD~5


260
我认为,这可以更好地回答这个问题stackoverflow.com/a/5201642/295797
Roy Truelove

92
什么意思<after-this-commit>
2540625 '11

43
<after-this-commit>是提交X + 1,即您要压榨的最老提交的父级。
joozek 2014年

338
我发现此回复过于简洁,无法明确理解。一个例子会有所帮助。
伊恩·奥尔曼

53
rebase -i方法与的区别reset --soft是,rebase -i允许我保留提交作者,而reset --soft允许我重新提交。有时,我需要压缩请求请求的提交,同时保持作者信息。有时我需要根据自己的提交重设软件。无论如何都支持两个很好的答案。
zionyx

3825

如果没有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重新指向您不想挤压的最后一次提交。软复位既不会触及索引也不会影响工作树,从而使索引处于新提交所需的状态(即,它已经具有您要“丢弃”的提交中的所有更改)。


163
哈!我喜欢这种方法。这是贴近问题精神的人。可惜它需要那么多伏都教徒。应该将这样的东西添加到基本命令之一中。git rebase --squash-recent甚至可能git commit --amend-many
Adrian Ratnapala

13
@ABB:如果您的分支设置为“上游”,则可以使用branch@{upstream}(或仅@{upstream}用于当前分支;在两种情况下,最后一部分都可以缩写为@{u};请参见gitrevisions)。这可能与您的 “上次推送的提交” 有所不同(例如,如果其他人推送了在您最近的推送之上构建的内容,然后您又获取了该内容),但看起来可能接近您想要的内容。
克里斯·约翰森

104
这个有点儿需要我,push -f但否则很可爱,谢谢。
2rs2ts 2014年

39
@ 2rs2ts git push -f听起来很危险。注意只压缩本地提交。切勿触摸推送的提交!
马提亚斯M

20
之后我还需要使用git push --force它,以便进行提交
Zach Saucier

738

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

警告:首先,请确保您已完成工作-检查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

文档git merge--squash更详细地描述了该选项。


更新:git reset --soft HEAD~12 && git commitChris Johnsen在他的答案中提出的更简单的建议相比,此方法的唯一真正优势是,您将得到的提交消息中都包含您要压缩的每个提交消息。


16
您说的比“”更“优雅” git rebase -i,但是您没有给出原因。暂时将其设为-1,因为在我看来,实际上相反的说法是正确的,这是骇客。您不是为了强制git merge执行git rebase专门设计的功能之一而执行了超出必要数量的命令吗?
Mark Amery

76
@Mark Amery:我说这比较优雅有多种原因。例如,它不涉及不必要地生成编辑器,然后在“待办事项”文件中搜索并替换字符串。使用git merge --squash脚本也更容易。从本质上讲,这样做的理由是您根本不需要“交互性” git rebase -i
马克·隆air13年

12
另一个优点是,git merge --squash与重定基础相比,面对移动/删除/重命名的可能性较小,特别是在从本地分支进行合并时。(免责声明:仅凭一种经验,如果在一般情况下不正确,请纠正我!)
Cheezmeister 2014年

2
我总是很勉强,当涉及到硬复位-我会使用一个时间标签,而不是HEAD@{1}只是为了安全起见例如,当您的工作流程是由停电等中断了一个小时
托比亚斯Kienzler

8
@BT:销毁了您的提交?:(我不确定您的意思是什么。您提交的任何内容都可以轻松从git的reflog中恢复。如果您有未提交的工作,但是文件已暂存,则您仍然应该能够他们的内容回来了,尽管那将是更多的工作。但是,如果您的工作甚至还没有上演,恐怕就无能为力了;这就是为什么答案会预先说:“首先检查git状态是否干净(因为git reset --hard会丢弃暂存的和未暂存的更改)。”
Mark Longair

218

我建议git reset尽可能避免使用-特别是对于Git-novices。除非您真的需要基于多个提交使流程自动化,否则会有一种不太常见的方式...

  1. 将要压缩的提交放在工作分支上(如果尚未提交)-为此使用gitk
  2. 签出目标分支(例如“ master”)
  3. git merge --squash (working branch name)
  4. git commit

提交消息将根据壁球预先填充。


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

14
如果您对(1)进行扩展,那将很棒。
亚当

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

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

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

132

根据克里斯·约翰森的回答

从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手动进行修改。(或者,编辑别名以符合您的口味。)


6
有趣,但是我宁愿自己键入压缩的提交消息作为我多次提交的描述性摘要,而不是为我自动输入。因此,我宁愿指定git squash -m "New summary."N自动确定未推动的提交数。
Acumenus

1
@ABB,这听起来像一个单独的问题。(我不认为这正是OP的要求;在我的git squash工作流程中,我从未感到过需要它。)
EthanB 2014年

3
这真是太好了。我个人想要一个使用第一次压缩提交中的提交消息的版本。对于诸如空格调整之类的事情将是有益的。
funroll

@funroll同意。只是放弃最后一次提交味精对我来说是一种超常见的需求。我们应该能够设计出……
史蒂夫·克莱

2
@ABB可以git commit --amend用来进一步更改消息,但是该别名使您可以很好地了解提交消息中的内容。
破事2016年

131

感谢这篇方便的博客文章,我发现您可以使用此命令来压缩最近的3次提交:

git rebase -i HEAD~3

这很方便,因为即使您在没有跟踪信息/远程回购的本地分支机构中也可以使用。

该命令将打开交互式rebase编辑器,该编辑器随后将允许您按常规重新排序,压缩,重新编写单词等。


使用交互式基础编辑器:

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

最新提交,HEAD首先显示在第1行。以a开头的行#是注释/文档。

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

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

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

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

交互式基础编辑器


一个实际的日常例子

我最近提交了一项新功能。从那时起,我已提交了两个错误修复程序。但是现在我发现了我所承诺的新功能中的一个错误(或者可能只是拼写错误)。真烦人!我不要新的提交污染我的提交历史!

我要做的第一件事是纠正错误,并使用注释重新提交squash this into my new feature!

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

接下来,使用调出交互式rebase编辑器git rebase -i 1ff9460~。在~后提交SHA告诉编辑器,包括编辑,就提交。

接下来,将包含修订(fe7f1e0)的提交移动到功能提交的下方,并更改pickfixup

关闭编辑器时,修复程序将被压缩到功能提交中,而我的提交历史记录将变得干净整洁!

当所有提交都在本地时,这很好用,但是如果您尝试更改已经推送到远程的任何提交,则对于其他签出同一分支的开发人员确实会造成问题!

在此处输入图片说明


5
您是否必须选择最上面的一个并压榨其余的?您应该编辑答案以更详细地说明如何使用交互式资源库编辑器
Kolob Canyon

2
是的,pick在第1行离开。如果您选择squashfixup在第1行进行提交,则git将显示一条消息,指出“错误:如果没有先前的提交,则无法'修复'”。然后,它将为您提供修复的选项:“您可以使用'git rebase --edit-todo'进行修复,然后运行'git rebase --continue'。” 或者,您也可以中止然后重新开始:“或者,您可以使用'git rebase --abort'中止该基础。”。
br3nt

56

如果使用TortoiseGit,则可以执行以下功能Combine to one commit

  1. 打开TortoiseGit上下文菜单
  2. 选择 Show Log
  3. 在日志视图中标记相关的提交
  4. 选择Combine to one commit从上下文菜单

合并提交

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


据我所知,这不适用于合并提交。
Thorkil Holm-Jacobsen

1
尽管没有其他人评论,但这甚至适用于不在HEAD的提交。例如,在推送之前,我需要用更合理的描述来压缩一些我所做的WIP提交。做工精美。当然,我仍然希望我可以通过命令学习如何做。
查尔斯·罗伯托·卡纳托

55

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

 git rebase -i HEAD~n

n(此处为4)是最后提交的次数。然后您有以下选择,

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....

有关详细信息,请单击链接


48

根据本文,我发现此方法对我的用例更容易。

我的'dev'分支比'origin / dev'提前了96次提交(因此这些提交尚未推送到远程)。

我想将这些提交压缩为一,然后再进行更改。我更喜欢将分支重置为“ origin / dev”状态(这将取消暂存96次提交中的所有更改),然后立即提交更改:

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

1
正是我所需要的。从我的功能分支中压缩提交,然后我将这些提交混入我的母版中。
大卫·维克多

1
这不会压缩先前的提交!
IgorGanapolsky

您能否进一步说明@igorGanapolsky吗?
trudolf

3
@trudolf这不是真正的压榨(指个人对压榨的压榨)。这更多是一次提交所有更改。
IgorGanapolsky

15
是的,因此它将所有提交压缩为一个。恭喜你!
trudolf 2015年

45

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

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

例:

git rebase -i HEAD~1

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

p,选择=使用提交

s,squash =使用提交,但可以合并到先前的提交中

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

然后继续进行变基:

git rebase --continue

有关此方法以及重写提交历史记录的其他方法的更多信息,请参见此有用的帖子


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

git add在您对文件中的正确配置进行了正确的配置之后,git rebase --continue用于迁移到下一个提交并开始合并的重组会在分支上的提交过程中以块为单位进行。 :x是一个命令,将使用vim时看到保存文件的改变
aabiro

32

异常答案是好的,但是我对此感到不安全,所以我决定添加一些屏幕截图。

步骤0:git log

看看你在哪里git log。最重要的是,找到您不想压榨的第一个提交的提交哈希。所以只有:

在此处输入图片说明

步骤1:git rebase

git rebase -i [your hash]在我的情况下执行:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

第2步:选择/挤压您想要的东西

就我而言,我想压缩第一次提交中的所有内容。顺序是从头到尾,因此与中完全相反git log。就我而言,我想要:

在此处输入图片说明

步骤3:调整讯息

如果您只选择了一个提交,而将其余提交压缩,则可以调整一个提交消息:

在此处输入图片说明

而已。保存后(:wq)后,就完成了。一起看一下git log


2
很高兴看到最终结果,例如git log
Timothy LJ Stewart

2
不用了,谢谢。这正是我忘记我的承诺的方式。
Axalix

@Axalix是否删除了所有行?这就是您丢失提交的方式。
a3y3

31

程序1

1)确定提交短哈希

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

这里甚至git log --oneline还可以用来获取短哈希。

2)如果您要压缩(合并)最后两次提交

# git rebase -i deab3412 

3)这将打开一个nano用于合并的编辑器。它看起来像下面

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4)重命名字picksquash其之前存在abcd1234。重命名后,应如下所示。

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5)现在保存并关闭nano编辑器。按ctrl + o,然后按Enter保存。然后按ctrl + x退出编辑器。

6)然后 nano编辑器再次打开以更新注释,必要时对其进行更新。

7)现在已成功将其压扁,您可以通过检查日志进行验证。

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8)现在按回购。注意+在分支名称之前添加符号。这意味着强制推动。

# git push origin +master

注意:这是基于在ubuntushell 上使用git的基础。如果您使用不同的os(WindowsMac),则除了编辑器外,上述命令相同。您可能会获得不同的编辑器。

程序2

  1. 首先添加所需的提交文件
git add <files>
  1. 然后使用--fixupoption 提交,并且OLDCOMMIT应该在该目录上合并(挤压)此提交。
git commit --fixup=OLDCOMMIT

现在,使用会在HEAD顶部创建一个新提交fixup1 <OLDCOMMIT_MSG>

  1. 然后执行以下命令以合并(压缩)对的新提交OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

此处^表示先前对的提交OLDCOMMIT。该rebase命令在编辑器(vim或nano)上打开交互式窗口,在该窗口上,我们只需保存并退出即可,无需执行任何操作。因为传递给此选项的选项将自动将最新提交移至旧提交旁边,并将操作更改为fixup(相当于squash)。然后变基继续并完成。

程序3

  1. 如果需要在最后一次提交中添加新的更改,则--amend可以与一起使用git-commit
    # git log --pretty=oneline --abbrev-commit
    cdababcd Fix issue B
    deab3412 Fix issue A
    ....
    # git add <files> # New changes
    # git commit --amend
    # git log --pretty=oneline --abbrev-commit
    1d4ab2e1 Fix issue B
    deab3412 Fix issue A
    ....  

这里--amend将新的更改合并到最后的提交,cdababcd并生成新的提交ID1d4ab2e1

结论

  • 第一个过程的优点是可以压缩多个提交并重新排序。但是,如果我们需要将修订合并到非常旧的提交中,则此过程将很困难。
  • 因此,第二个过程有助于轻松地将提交合并到非常老的提交中。
  • 在压制新更改以最后提交的情况下,第三个过程很有用。

即使我重置为最后一次提交的提交ID,它也只会更新最后两个提交,不知道为什么
卡洛斯·刘

即使您可以重新排列提交顺序。工作正常。
rashok

29

要将最后10次提交压缩为1次单次提交:

git reset --soft HEAD~10 && git commit -m "squashed commit"

如果您还想使用压缩的提交来更新远程分支:

git push -f

当多个人在一个共享分支上工作时,--force十分危险,因为它会盲目地用本地副本更新远程分支。--force-with-lease可能更好,因为它可以确保自您上次获取远程以来,远程没有其他任何提交。
bharath

27

如果您位于feature-branch从Golden Repository()克隆的远程分支(称为)上golden_repo_name,那么以下是将提交压缩为一个的技术:

  1. 签出黄金仓库

    git checkout golden_repo_name
    
  2. 从其创建一个新分支(黄金仓库),如下所示

    git checkout -b dev-branch
    
  3. 壁球与您已经拥有的本地分支合并

    git merge --squash feature-branch
    
  4. 提交更改(这将是在开发分支中进行的唯一提交)

    git commit -m "My feature complete"
    
  5. 将分支推送到本地存储库

    git push origin dev-branch
    

由于我只压缩了约100个提交(用于通过git-svn同步svn分支),所以这比交互式重新设置要快得多!
2015年

1
读下来,我看到了@Chris的评论,这是我曾经做过的事情(rebase --soft ...)-太可惜了,stackoverflow不再将数百个赞誉的答案放在顶部...
sage

1
同意您的@sage,希望他们将来有机会这样做
Sandesh Kumar

这是正确的方法。Rebase方法是好的,但是只能将南瓜用作最后的解决方案。
Axalix

20

真正方便的方法是:
说出要压缩的提交哈希d43e15

现在使用

git reset d43e15
git commit -am 'new commit name'

2
这个。为什么没有更多的人使用它?它比重新整理和压缩单个提交要快得多。
3

17

这是超级骗子的迷糊,但是以一种很酷的方式,所以我将它扔进去:

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

翻译:为git提供一个新的“编辑器”,如果要编辑的文件名是 git-rebase-todo(交互式变基提示),则将除第一个“ pick”外的所有内容都更改为“ squash”,否则生成vim-以便在出现提示时编辑压缩的提交消息,您将获得vim。(很明显,我压缩了分支foo上的最后五个commit,但是您可以根据需要更改它。)

我可能会做Mark Longair的建议


7
+1:这很有趣且很有启发性,因为对我来说,您可以在GIT_EDITOR环境变量中添加比程序名称更复杂的东西对我来说一点都不明显。
Mark Longair 2011年

16

如果要将每个提交压缩为单个提交(例如,首次公开发布项目时),请尝试:

git checkout --orphan <new-branch>
git commit

14

我认为最简单的方法是从master分支中创建一个新分支,然后对feature分支进行merge --squash。

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

然后,您已准备好所有更改。


14

2020年,无需重新设置基础的简单解决方案:

git reset --soft HEAD~2

git commit -m "new commit message"

git push --force

2表示将压缩最后两个提交。您可以用任何数字代替


12

假设您当前位于要压榨的分支上,简单的单线始终有效,master是它的起源分支,而最新的commit包含您希望使用的提交消息和作者:

git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}

4
我对压缩提交及其令人惊讶的复杂性感到无比沮丧-仅使用最后一条消息并将它们全部压缩为一次提交!为什么这么难???这支班轮为我做到了。衷心感谢您。
Locane

12

例如,如果您想将最后3次提交压缩为分支机构(远程存储库)中的单个提交,例如:https : //bitbucket.org

我所做的是

  1. git reset --soft Head〜3 &&
  2. git提交
  3. git push origin(branch_name)--force

3
请注意,由于您使用了武力,因此删除
后便

12

⚠️警告:“我最近的X次提交”可能是模棱两可的。

  (MASTER)  
Fleetwood Mac            Fritz
      ║                    ║
  Add Danny  Lindsey     Stevie       
    Kirwan  Buckingham    Nicks                                              
      ║         ╚═══╦══════╝     
Add Christine       ║          
   Perfect      Buckingham
      ║           Nicks            
    LA1974══════════╝                                    
      ║                  
      ║                  
    Bill <══════ YOU ARE EDITING HERE
  Clinton        (CHECKED OUT, CURRENT WORKING DIRECTORY)              

https://github.com/fleetwood-mac/band-history存储库的这段非常简短的历史记录中,您已经打开了pull请求,以将Bill Clinton提交合并到原始(MASTER)Fleetwood Mac提交中。

您打开了一个拉取请求,并在GitHub上看到以下内容:

四次提交:

  • 添加丹尼·基万(Danny Kirwan)
  • 添加克里斯汀完美
  • LA1974
  • 比尔·克林顿

认为没有人会愿意阅读完整的存储库历史记录。(实际上有一个存储库,单击上面的链接!)您决定压缩这些提交。所以你去跑步git reset --soft HEAD~4 && git commit。然后你git push --force其放到GitHub上以清理您的PR。

那会发生什么呢?您刚刚完成了一次从Fritz到Bill Clinton的提交。因为您忘记了昨天您正在从事该项目的白金汉尼克斯版本。和git log与您在GitHub上看到的不符。

🐻故事的道德

  1. 找到你要得到确切的文件,和git checkout他们
  2. 找到您想要保留在历史记录中的确切先前提交,并 git reset --soft
  3. 做一个git commit直接从该经线

1
这是100%做到这一点的最简单方法。如果您当前的HEAD 您想要的正确状态,则可以跳过#1。
Stan,

我知道这是唯一允许重写第一个提交历史记录的方法。
Vadorequest '19

9

如果您不关心中间提交的提交消息,则可以使用

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend

7

如果您使用的是GitLab,则只需单击Merge Request中的Squash选项,如下所示。提交消息将成为合并请求的标题。

在此处输入图片说明



6

除了其他出色的答案外,我想补充一下如何git rebase -i总是使我对提交顺序感到困惑-从旧到新,反之亦然?这是我的工作流程:

  1. git rebase -i HEAD~[N],其中N是我要加入的提交数,从最近一次开始。因此git rebase -i HEAD~5意味着“将最后5次提交压缩为新的提交”;
  2. 编辑器弹出,显示我要合并的提交列表。现在,它们以相反的顺序显示:较早的提交位于顶部。将其中的所有提交标记为“ squash”或“ s” ,第一个/较旧的除外:它将用作起点。保存并关闭编辑器;
  3. 编辑器会再次弹出,并带有新提交的默认消息:根据您的需要进行更改,保存并关闭。壁球完成!

来源和其他读物:#1#2


6

与这样的工作流程有关的问题的答案呢?

  1. 许多本地提交,与来自主的多个合并混合在一起
  2. 最终推向远程
  3. 公关并由审稿人合并为硕士。(是的,对于开发人员而言,merge --squash进行PR 会更容易,但是团队认为这样做会拖慢过程。)

我在此页面上没有看到这样的工作流程。(可能是我的眼睛。)如果我理解rebase正确,那么多次合并将需要多种冲突解决方案。我什至不想考虑!

因此,这似乎对我们有用。

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. 在本地编辑和提交大量内容,定期合并母版
  5. git checkout new-branch
  6. git merge --squash new-branch-temp //将所有更改置于阶段
  7. git commit 'one message to rule them all'
  8. git push
  9. 审阅者执行PR并合并到母版。

从许多意见来看,我喜欢您的方法。非常方便,快捷
Artem Solovev

5

我发现一个更通用的解决方案不是指定“ N”个提交,而是要在其上方压入的branch / commit-id。与将提交计数到特定提交相比,这种方法更不容易出错-只需直接指定标签,或者如果您真的要计数,则可以指定HEAD〜N。

在我的工作流程中,我启动了一个分支,我对该分支的第一次提交总结了目标(即通常是我将其作为功能的“最终”消息推送到公共存储库的内容。)我想做的是git squash master回到第一个消息,然后我准备推送。

我使用别名:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

这将在此之前转储被压缩的历史记录,这使您有机会通过还原控制台中的旧提交ID来进行恢复。(Solaris用户注意到它使用了GNU sed -i选项,Mac和Linux用户应该对此感到满意。)


我尝试了别名,但不确定sed替换是否有效。他们该怎么办?
2015年

第一个sed仅将历史记录转储到控制台。第二个sed将所有'pick'替换为'f'(fixup),并就地重写编辑器文件(-i选项)。因此,第二个完成所有工作。
伊桑(Ethan)2015年

没错,计算N次特定的提交非常容易出错。它使我搞砸了好几次,并浪费了数小时试图撤消该基准。
IgorGanapolsky

嗨,Ethan,我想知道此工作流程是否会隐藏合并中的可能冲突。因此,请考虑您是否有两个分支master和slave。如果从属设备与主机存在冲突,则git squash master在从属设备上签出时使用。会发生什么?我们会隐藏冲突吗?
塞尔吉奥·比洛洛

@Sergio这是重写历史的一种情况,因此如果您压缩已经被推送的提交,然后尝试合并/重新设置压缩后的版本,则可能会有冲突。(一些琐碎的案件可能会解决这个问题。)
Ethan

5

有问题的是,“最后”的含义可能是模棱两可的。

例如git log --graph输出以下(简体):

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|

然后按时间的最后提交是H0,合并,B0。要压缩它们,您将必须基于提交H1重新建立合并的分支。

问题在于H0包含H1和H2(通常在合并之前和分支之后会有更多提交),而B0则没有。因此,您至少必须管理来自H0,合并,H1,H2,B0的更改。

可以使用rebase,但使用的方式与其他提到的答案不同:

rebase -i HEAD~2

这将为您显示选择选项(如其他答案中所述):

pick B1
pick B0
pick H0

将壁球而不是接球放到H0:

pick B1
pick B0
s H0

保存并退出rebase之后,将在H1之后依次应用提交。这意味着它将要求您再次解决冲突(其中HEAD首先为H1,然后在应用提交时累积提交)。

重置完成后,您可以选择压缩的H0和B0消息:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|

PS:如果您只是对BO进行一些重置:(例如,使用reset --mixed该重置的详细信息,参见https://stackoverflow.com/a/18690845/2405850):

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'

那么您将压倒H0,H1,H2的B0更改(在分支之后和合并之前完全丢失更改的提交)。


4

1)git reset --soft HEAD〜n

n-提交数量,需要压扁

2)git commit -m“新提交消息”

3)git push origin branch_name --force

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.