这个问题不仅涉及如何完成这项任务,而且还涉及使用Git这样做是好还是坏。
考虑到本地我在master分支上工作最多,但我创建了一个我称之为“topical_xFeature”的主题分支。在处理“topical_xFeature”并来回切换以在master分支上进行其他工作的过程中,事实证明我在“topical_xFeature”分支上进行了多次提交,但是在每次提交之间,我没有做过推。
首先,您会考虑这种不良做法吗?每次推送每个分支坚持一次提交是不是更明智?在什么情况下,在推送之前在分支上进行多次提交会很好?
第二次,如何才能最好地将topical_xFeature分支上的多次提交带入主分支进行推送?不担心它并且只是推动多个提交被推送的推动是否是令人讨厌的,或者以某种方式将提交合并为一个然后推送不那么烦人?再次,如何做到这一点?
答案 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 Campbell的answer。)
答案 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)
如果您是像我这样的初学者,但不知道合并将为您带来什么?
答案 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文件处理。因此该工具需要满足以下条件:
修改默认的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