在推之前将多个提交合并为一个

这个问题不仅关系到如何完成这个任务,还关系到这样做对 Git 来说是好还是坏。

考虑到我在本地对主分支做了大部分工作,但是我已经创建了一个名为“ topical _ xFeature”的主题分支。在处理“ topical _ xFeature”并在主分支上来回切换以完成其他工作的过程中,原来我在“ topical _ xFeature”分支上做了不止一次提交,但在每次提交之间,我没有做任何推送。

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

第二个问题 ,我应该如何最好地完成主题 _ xFeature 分支的多次提交,以便进行一次推送?不用担心这个问题,只是在多个提交被推送的情况下进行推送,或者以某种方式将提交合并成一个然后再推送,这样做是否不那么令人讨厌?再问一次,怎么做?

151099 次浏览

首先 : 没有任何东西告诉你每推一个分支只有一个提交: 推是一种发布机制,允许你在远程回购上发布本地历史记录(即提交的集合)。

第二个 : 在推 master之前,一个 git merge --no-ff topical_xFeature会记录在主页上,作为一个单独的提交你的主题作品。
(通过这种方式,您可以保留 topical_xFeature以备进一步发展,您可以在 master上将其记录为下一次合并时的单个新提交—— no-ff。
如果目标是摆脱 topical_xFeature,那么 git merge --squash就是正确的选择,详见 布莱恩 · 坎贝尔回答。)

对于你的第一个问题,不,一次推多个提交没有什么错。很多时候,您可能希望将您的工作分解成几个小的、符合逻辑的提交,但是只有在您觉得整个系列都准备好了的时候才将它们推上去。或者,您可能在断开连接时在本地进行了多次提交,一旦再次连接,就会推送所有提交。没有理由将自己限制在每次推送只提交一次。

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

如果您确实希望将多个提交压缩在一起,可以使用 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

你选哪个由你决定。一般来说,我不会担心有多个较小的提交,但有时你不想麻烦额外的小提交,所以你只是压缩成一个。

在推送代码之前,我通常采用这种方式将多个 Commit 合并为一个提交。

为此,我建议您使用 GIT 提供的“ 南瓜”概念。

按照以下步骤操作。

1) git rebase-i 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

当您保存它时,您只有一个提交,它将引入前三个提交的更改。

希望这个能帮到你。

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

git checkout master

git fetch这可能是必要的(取决于您的 git 配置) ,以接收更新的原点/主

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

  1. 首先选择哪个承诺,你希望一切都在之后。

    git reflog
    5976f2b HEAD@{0}: commit: Fix conflicts
    80e85a1 HEAD@{1}: commit: Add feature
    b860ddb HEAD@{2}: commit: Add something
    
  2. Reset to your selected head (I have chosen HEAD@{2})

    git reset b860ddb --soft
    
  3. git status (just to be sure)

  4. Add your new commit

    git commit -m "Add new commit"
    

Note: HEAD@{0} & HEAD@{1} Are now merged into 1 commit, this can be done for multiple commits also.

git reflog again should display:

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

将多次提交自动化为一次提交的工具

正如 Kondal Kolipaka 所说,使用“ git rebase-i”

“ git rebase”的逻辑

当使用“ git rebase-i”时,git 会在当前。Git/rebase-merge 目录,然后调用 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