在推送之前将多个提交组合成一个

时间:2011-04-19 19:26:07

标签: git workflow

这个问题不仅涉及如何完成这项任务,而且还涉及使用Git这样做是好还是坏。

考虑到本地我在master分支上工作最多,但我创建了一个我称之为“topical_xFeature”的主题分支。在处理“topical_xFeature”并来回切换以在master分支上进行其他工作的过程中,事实证明我在“topical_xFeature”分支上进行了多次提交,但是在每次提交之间,我没有做过推。

首先,您会考虑这种不良做法吗?每次推送每个分支坚持一次提交是不是更明智?在什么情况下,在推送之前在分支上进行多次提交会很好?

第二次,如何才能最好地将topical_xFeature分支上的多次提交带入主分支进行推送?不担心它并且只是推动多个提交被推送的推动是否是令人讨厌的,或者以某种方式将提交合并为一个然后推送不那么烦人?再次,如何做到这一点?

7 个答案:

答案 0 :(得分:126)

对于你的第一个问题,不,一次推送多次提交没有错。很多时候,您可能希望将您的工作分解为一些小的逻辑提交,但只有在您觉得整个系列准备就绪时才会将它们推迟。或者您可能在断开连接时在本地进行多次提交,并在再次连接后将其全部推送。没有理由限制每次推送一次提交。

我通常发现,保持每个提交都是单一的,逻辑的,连贯的更改,包括它需要工作的所有内容(因此,它不会使您的代码处于损坏状态)是一个好主意。如果你有两个提交,但如果你只应用第一个提交会导致代码被破坏,那么将第二个提交压缩到第一个提交可能是个好主意。但是如果你有两个提交,每个提交做出一个合理的改变,将它们作为单独的提交推送就可以了。

如果您确实希望将多个提交压缩在一起,则可以使用git rebase -i。如果您在分支topical_xFeature上,则会运行git rebase -i master。这将打开一个编辑器窗口,其中列出了一系列以pick为前缀的提交。您可以将除第一个之外的所有内容更改为squash,这将告诉Git保留所有这些更改,但将它们压缩到第一个提交中。完成后,请查看master并合并您的功能分支:

git checkout topical_xFeature
git rebase -i master
git checkout master
git merge topical_xFeature

或者,如果您只想将topical_xFeature中的所有内容压缩到master,您可以执行以下操作:

git checkout master
git merge --squash topical_xFeature
git commit

您选择哪一个取决于您。一般来说,我不担心有多个较小的提交,但有时你不想打扰额外的小提交,所以你只需将它们压成一个。

答案 1 :(得分:62)

这是我在推送代码之前将多个Commits组合成单个提交的方式。

为实现这一目标,我建议您使用GIT提供的“壁球”概念。

按照以下步骤操作。

1)git rebase -i master (而不是 master 你也可以使用特定的提交)

打开rebase交互式编辑器,它将显示所有提交。基本上,您需要识别要合并到单个提交中的提交。

想象一下这些是你的提交,并在编辑器中显示如下内容。

pick f7f3f6d changed my name a bit    
pick 310154e updated README formatting and added blame   
pick a5f4a0d added cat-file  

请务必注意,这些提交的顺序与您通常使用log命令看到的顺序相反。意味着,旧的提交将首先显示。

2)将“挑选”更改为“压缩”以用于上次提交的更改。如下所示的东西。这样做,你的最后2次提交将与第一次提交合并。

pick f7f3f6d changed my name a bit         
squash 310154e updated README formatting and added blame   
squash a5f4a0d added cat-file

如果你有许多提交需要合并,你也可以使用简短形式:

p f7f3f6d changed my name a bit         
s 310154e updated README formatting and added blame   
s a5f4a0d added cat-file

编辑使用'i',它将启用编辑器插入。请记住,最先(最旧)的提交不能被压扁,因为之前没有提交要提交。所以必须选择或'p'。使用'Esc'退出插入模式。

3)现在,使用以下命令保存编辑器。 的:WQ

保存时,您只有一个提交,它会引入所有三个提交的更改。

希望这会对你有所帮助。

答案 2 :(得分:11)

首先:没有任何事情告诉您每次推送每个分支只有一个提交:推送是一种发布机制,允许您在远程仓库上发布本地历史记录(即提交集合)。

第二次:在推送git merge --no-ff topical_xFeature之前,master会在主设备上记录您的主题作业。 (这样,您可以保留topical_xFeature以进行进一步的演变,您可以在master上记录下一次合并时的单个新提交--no-ff。 如果取消topical_xFeature是目标,则git merge --squash是正确的选项,详见Brian Campbellanswer。)

答案 3 :(得分:8)

切换到主分支并确保您是最新的。

git checkout master

git fetch这可能是必要的(取决于你的git配置)来接收关于origin / master的更新

git pull

将功能分支合并到主分支中。

git merge feature_branch

将主分支重置为原始状态。

git reset origin/master

Git现在将所有更改视为未分级更改。 我们可以将这些更改添加为一次提交。 添加。还会添加未跟踪的文件。

git add --all

git commit

参考:https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit

答案 4 :(得分:2)

1)首先选择您希望所有内容都遵循的提交。

git reflog
5976f2b HEAD@{0}: commit: Fix conflicts
80e85a1 HEAD@{1}: commit: Add feature
b860ddb HEAD@{2}: commit: Add something

2)重置为您选择的头(我已经选择HEAD @ {2})

git reset b860ddb --soft

3)git状态(请确定)

4)添加新的提交

git commit -m "Add new commit"

注意:HEAD@{0}HEAD@{1}现在已合并为1个提交,这也可以用于多个提交。

git reflog再次应显示:

git reflog
5976f2b HEAD@{0}: commit: Add new commit
b860ddb HEAD@{1}: commit: Add something

答案 5 :(得分:0)

如果您是像我这样的初学者,但不知道合并将为您带来什么?

Simplest Description On How to Squash in Git

答案 6 :(得分:-1)

一种自动将多个提交合并为一个的工具

as Kondal Kolipaka says。使用“ git rebase -i”

“ git rebase”的逻辑

使用“ git rebase -i”时,git在当前.git / rebase-merge目录中生成git-rebase-todo文件,然后调用git编辑器以使用户可以编辑git-rebase-todo文件处理。因此该工具需要满足以下条件:

  1. 将git编辑器修改为我们提供的工具;
  2. 该工具处理git-rebase-todo文件。

修改默认的git编辑器

git config core.editor #show current default git editor
git config --local --replace-all  core.editor NEW_EDITOR # set the local branch using NEW_EDITOR as git editor

因此,该工具需要更改git编辑器并处理git-rebase-todo文件。 下面使用python的工具:

#!/usr/bin/env python3
#encoding: UTF-8

import os
import sys

def change_editor(current_file):
    os.system("git config --local --replace-all  core.editor " + current_file) # Set current_file as git editor
    os.system("git rebase -i") # execute the "git rebase -i" and will invoke the python file later with git-rebase-todo file as argument
    os.system("git config --local --replace-all core.editor vim") # after work reset the git editor to default

def rebase_commits(todo_file):
    with open(todo_file, "r+") as f:
        contents = f.read() # read git-rebase-todo's content
        contents = contents.split("\n")
        first_commit = True
        f.truncate()
        f.seek(0)
        for content in contents:
            if content.startswith("pick"):
                if first_commit:
                    first_commit = False
                else:
                    content = content.replace("pick", "squash") # replace the pick to squash except for the first pick
            f.write(content + "\n")

def main(args):
    if len(args) == 2:
        rebase_commits(args[1]) # process the git-rebase-todo
    else:
        change_editor(os.path.abspath(args[0])) # set git editor

if __name__ == "__main__":
    main(sys.argv)

参考:https://liwugang.github.io/2019/12/30/git_commits_en.html