Git 从主服务器获取当前差异,并将其转换为单个提交,而无需将每个提交应用到彼此之上

Git 从主服务器获取当前差异,并将其转换为单个提交,而无需将每个提交应用到彼此之上,git,Git,我想在master之前进行一些分支,即X提交,基本上快照当前的差异,并从中创建一个提交 通常我使用git-rebase-I,压缩除最新提交之外的所有提交,这样就可以了 然而,如果在修复过程中出现了与重定基础的冲突或问题,我必须手动处理。我不一定要在每个提交的基础上应用每个提交—相反,我希望在分支负责人和主节点之间获得当前的差异,并从中创建一个提交 我已经通过手动区分我的整个分支和主分支,创建mychanges.diff,然后将其应用到一个干净的分支,但是感觉git中应该有一种本地的干净方法,通过

我想在master之前进行一些分支,即X提交,基本上快照当前的差异,并从中创建一个提交

通常我使用
git-rebase-I
,压缩除最新提交之外的所有提交,这样就可以了

然而,如果在修复过程中出现了与重定基础的冲突或问题,我必须手动处理。我不一定要在每个提交的基础上应用每个提交—相反,我希望在分支负责人和主节点之间获得当前的差异,并从中创建一个提交


我已经通过手动区分我的整个分支和主分支,创建
mychanges.diff
,然后将其应用到一个干净的分支,但是感觉git中应该有一种本地的干净方法,通过应用每个提交来不重新基定,而是快照当前状态并创建一个与master不同的提交。

我相信您想要的是
git merge--squash

git checkout master
git merge --squash otherbranch

[resolve any conflicts if necessary, then]

git diff --cached     # to see what you're about to commit
git commit            # to make a single non-merge commit on master
比较长的 差异不是快照,因此这里有一个基本的不匹配。让我试试古老的温度类比。假设我告诉你今天这里比昨天暖和十度。(虽然实际上差不多:-)现在我有一个问题要问你:今天的温度是多少?或者,相当于,昨天的温度是多少

快照是绝对的。如果我告诉你温度是68˚F/20˚C,或者比昨天高10˚F,或者昨天是58˚F,那么这两条信息就足够了。一个快照或一个差异是不够的:您需要两个快照,或者一个快照和一个差异。(请注意,无限多的差异永远不够:您始终需要序列中的某个位置至少有一个快照。否则,可能会有一些东西在开始时是什么样子,从未更改过,您根本看不到它。)

不过,我认为你所描述的情况是这样的:

           C--D--E--F--G   <-- branch
          /
....--A--B--H   <-- master
但是如果
H
确实存在,那么您可能希望将
B
-vs-
G
的更改与
B
-vs-
H
的更改结合起来,这样您就不会消除在一开始进行
H
时所做更改的影响。组合这些更改的命令是
git merge

一个普通的完全合并,你可以通过git checkout master得到它;git合并分支机构将:

  • 查找合并基,在本例中为commit
    B
  • 将合并基提交与当前分支tip
    H
    区分,以查找“我们的”更改
  • 将相同的合并基础提交与“他们的”(仍然是我们的,但在合并期间
    --theres
    )提交
    G
    ,以查找“他们的”更改;及
  • 尝试合并这些更改
如果存在合并冲突,此正常合并将停止并使您完成作业。如果不是,此正常合并将与两个父级进行新提交:

M
S
之间的关键区别在于
S
只指向提交
H
,而根本不指向提交
G
。(
S
的默认提交消息文本也不同,但由于在
git commit
打开提交消息编辑器时有机会替换此文本,因此这种差异并不重要。)

如果commit
H
不存在,那么
git merge--squash
操作仍然执行完全相同的过程。合并基仍然是提交
B

           C--D--E--F--G   <-- branch
          /
....--A--B   <-- master (HEAD)
注意,在像这样使用
gitmerge--squash
之后,分支
branch
几乎肯定会被完全删除。除非您将commit
S
master
剥离,否则不应返回到它并进行更多的提交

(您可能想知道为什么
git merge--squash
会首先停止。唯一合理的答案是,这是一次历史事故,其行为从那时起一直保持不变。如果它在默认情况下没有停止,您可以随时运行
git merge--squash--no commit
,只要您希望它停止。但是squash merge的第一个实现是有效的通过让
git merge
在它运行自己的内部
git commit
之前提前退出,这样编码就更容易了。冲突的merge和
--no commit
案例执行另一个步骤,即在内部状态文件中记录合并正在进行;然后它们退出。当运行
git commit
时,G它要么注意到“正在合并”状态文件,要么不注意,这取决于
git merge
是否创建了它。然后,它要么因为没有记录状态而进行正常的非合并提交,要么因为有记录的合并状态而进行合并提交。)


1有多个Git命令可以实现此结果。没有一个命令可以一步完成此操作:至少需要两个Git命令才能完成此操作。即使使用
Git merge--squash
,情况也是如此

           C--D--E--F--G   <-- branch
          /
....--A--B--G'  <-- master (HEAD)
           C--D--E--F--G   <-- branch
          /             \
....--A--B--H------------M   <-- master (HEAD)
           C--D--E--F--G   <-- branch
          /
....--A--B--H------------S   <-- master (HEAD)
           C--D--E--F--G   <-- branch
          /
....--A--B   <-- master (HEAD)
           C--D--E--F--G   <-- branch
          /
....--A--B--S   <-- master (HEAD)