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

使用Git压缩我的最后一个X提交,git,rebase,squash,git-squash,Git,Rebase,Squash,Git Squash,如何使用Git将最后的X次提交压缩为一次提交?使用Git-rebase-I 在本例中,是SHA1散列或当前分支头的相对位置,从中可以分析rebase命令的提交。例如,如果用户希望查看过去来自当前头部的5次提交,则命令为git rebase-i HEAD~5 您可以使用git merge--squash,这比git rebase-i稍微优雅一些。假设您在master上,希望将最后12次提交压缩为一次提交 警告:首先确保您提交了您的工作,检查git状态是否干净(因为git reset--hard将丢

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

使用Git-rebase-I


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

您可以使用
git merge--squash
,这比
git rebase-i
稍微优雅一些。假设您在master上,希望将最后12次提交压缩为一次提交

警告:首先确保您提交了您的工作,检查
git状态
是否干净(因为
git reset--hard
将丢弃暂存和未暂存的更改)

然后:

更详细地描述了
--squash
选项



更新:与Chris Johnsen在年提出的更简单的
git重置--soft HEAD~12&&git commit
相比,这种方法的唯一真正优势在于,您可以在提交消息中预先填充您正在压扁的每一条提交消息。

这是一种超级重复的拙劣行为,但方式很酷,因此我将它扔进拳击场:

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
(交互式rebase提示符)将除第一个“pick”之外的所有内容都更改为“squash”,否则会生成vim,这样当提示您编辑压缩的提交消息时,您就会得到vim。(很明显,我在branch foo上压缩了最后五次提交,但你可以随意更改。)


不过,我可能会这样做。

您可以非常轻松地完成这项工作,而无需
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})"
这两种方法都以相同的方式将最后三次提交压缩为一次新提交。软重置只是将头部重新指向您不想挤压的最后一次提交。软重置既不会触动索引,也不会触动工作树,从而使索引处于新提交所需的状态(即,它已经具有您将要“丢弃”的提交的所有更改)。

基于

从bash(或Windows上的Git bash)添加全局“挤压”别名

。。。或使用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"

用法:

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


注意:结果提交消息按顺序是所有压缩提交的组合。如果对此不满意,您可以始终
git commit--amend
手动修改它。(或者,编辑别名以符合您的喜好。)

我建议尽可能避免git重置,尤其是对于git新手。除非您真的需要基于大量提交来自动化流程,否则有一种不那么奇特的方法

  • 将要压缩的提交放在一个工作分支上(如果它们还没有)——为此使用gitk
  • 查看目标分支(例如“主分支”)
  • git合并——挤压(工作分支名称)
  • git提交
  • 提交消息将基于压缩预填充。

    基于我发现这种方法更适合我的用例

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

    在推动更改之前,我想将这些承诺压缩为一个。我更倾向于将分支重置为“origin/dev”状态(这将保留96次提交的所有更改未显示),然后立即提交更改:

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

    我发现一个更通用的解决方案不是指定'N'提交,而是指定要压扁的分支/提交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用户对此应该没问题。)

    如果您在一个远程分支(称为
    功能分支
    )上,该分支是从黄金存储库(
    黄金回购名称
    )克隆而来的,那么下面是将您的提交压缩为一个的技术:

  • 结帐黄金回购

    git checkout golden_repo_name
    
  • 从中创建一个新分支(黄金回购),如下所示

    git checkout -b dev-branch
    
  • 挤压合并到您已经创建的本地分支

    git merge --squash feature-branch
    
  • 提交您的更改(这将是在dev分支中进行的唯一提交)

  • 将分支推送到本地存储库

    git push origin dev-branch
    

  • 如果使用Ortoisegit,则可以将函数
    组合为一个提交

    git reset --soft HEAD~3 && 
    git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
    
  • 打开龟甲上下文菜单
  • 选择
    Show Log
  • 在日志视图中标记相关提交
  • 从关联菜单中选择“合并到一个提交”
  • 此函数自动执行所有必要的操作
    git merge --squash feature-branch
    
    git commit -m "My feature complete"
    
    git push origin dev-branch
    
    git rebase -i HEAD~3
    
    git checkout --orphan <new-branch>
    git commit
    
     git rebase -i HEAD~n
    
    pick 01d1124 Message....
    pick 6340aaa Message....
    pick ebfd367 Message....
    pick 30e0ccb Message....
    
    p 01d1124 Message....
    s 6340aaa Message....
    s ebfd367 Message....
    s 30e0ccb Message....
    
    git reset d43e15
    git commit -am 'new commit name'
    
    # git log --pretty=oneline --abbrev-commit
    abcd1234 Update to Fix for issue B
    cdababcd Fix issue B
    deab3412 Fix issue A
    ....
    
    # git rebase -i deab3412 
    
    ....
    pick cdababcd Fix issue B
    pick abcd1234 Update to Fix for issue B
    ....
    
    ....
    pick cdababcd Fix issue B
    squash abcd1234 Update to Fix for issue B
    ....
    
    # git log --pretty=oneline --abbrev-commit
    1122abcd Fix issue B
    deab3412 Fix issue A
    ....
    
    # git push origin +master
    
    git add <files>
    
    git commit --fixup=OLDCOMMIT
    
    git rebase --interactive --autosquash OLDCOMMIT^
    
        # 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
        ....  
    
    git rebase -i HEAD^^
    
    git checkout master
    git checkout -b feature_branch_squashed
    git merge --squash feature_branch
    
    $ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
    
    git rebase -i HEAD~(n number of commits back to review)
    
    git rebase -i HEAD~1
    
    git rebase --continue
    
    git reset --soft HEAD~10 && git commit -m "squashed commit"
    
    git push -f
    
      (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)              
    
    git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}
    
    git reset --mixed <commit-hash-into-which-you-want-to-squash>
    git commit -a --amend
    
    git rebase -i HEAD~X
    
    pick 1bffc15c My earlier commit
    pick 474bf0c2 My recent commit
    
    # ...
    
    pick 1bffc15c My earlier commit
    fixup 474bf0c2 My recent commit
    
    # ...