use*_*427 1 git version-control
假设我有包含三个提交的主分支
A--B----C
Run Code Online (Sandbox Code Playgroud)
我创建新分支dev并在那里创建 3 个提交
A--B----C------C1------C2
\
E---F----G
Run Code Online (Sandbox Code Playgroud)
现在我像这样与主人合并
git merge dev --squash
现在我认为新图是这样的但不确定
A--B----C------C1------C2--------M----
\ /
E---F----G-----------/
Run Code Online (Sandbox Code Playgroud)
之后我需要将dev分支与 master 合并以获得提交 c1 和 c2
所以会是这样的
A--B----C------C1------C2--------M----
\ / \
E---F----G-----------/----m2 ---H--I
Run Code Online (Sandbox Code Playgroud)
dev并将master并行进行
我想知道
我想知道如果我必须使用 rebase 而不是合并,两个分支应该并行,那么图表会是什么
如果第一个问题的答案是肯定的,那么如果我使用 rebase 命令,单个历史提交会消失吗
让我用一些标签重新绘制第二张图:
\n\nA--B--C-----C1----C2 <-- master\n \\\n E--F----G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n(我假设C1和只是代表在while 、和 上C2发生的一些提交被添加到)。masterEFGdev
如果您现在启动master并运行git merge dev --squash(然后提交结果:--squash抑制最后的提交步骤),您会得到以下内容,这与您绘制的内容非常不同:
A--B--C-----C1----C2---M <-- master\n \\\n E--F----G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\ngit merge 如果你没有 运行,你就会得到你画的东西--squash。--squash引用文档,该标志将:
\n\n\n生成工作树和索引状态,就好像发生了真正的合并(合并信息除外),但实际上并不进行提交或移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD来导致下一个 git commit 命令用于创建合并提交。
\n
换句话说,挤压合并根本不是合并(这就是为什么我对 git 的一些术语有“问题”:-) ...有些签出是签出,有些则不是;有些合并是合并,有些则不是;分支只是分支提示,除非它们不是,等等!)。“挤压合并”确实使用底层合并代码来确定下一次提交的内容应该是什么,但是如果当您进行实际提交(M上面标记的那个)时,它只是一个普通的非合并提交,这需要完成的工作\xe2\x80\x94所做的更改\xe2\x80\x94提交E通过G并将这些更改复制到C2. 将其视为“有人向您发送差异,将版本C与版本进行比较G,然后您手动将所有这些更改插入版本C2并提交(可能应该调用它C3,但我们改为调用它M)”。
如果您想要真正的合并,请在不进行合并的情况下进行合并 --squash. 事实上,这会给你所画的内容,我将在这里重新绘制:
A--B--C-----C1----C2---M <-- master\n \\ /\n E--F----G----/ <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n(标签dev仍然指向 commitG。)
接下来,如果您想选取C1和中的更改C2并将其放在dev,您可以执行以下两种操作之一:
git checkout dev && git merge master\nRun Code Online (Sandbox Code Playgroud)\n\n或者:
\n\ngit checkout dev && git merge --no-ff master\nRun Code Online (Sandbox Code Playgroud)\n\n这里的区别在于你是否得到了m2你所绘制的提交。如果没有,git 会观察到和--no-ff的合并产生 commit ,并且只是将标签移动到指向devmasterMdevM:
A--B--C-----C1----C2---M <-- dev, master\n \\ /\n E--F----G----/\nRun Code Online (Sandbox Code Playgroud)\n\n但与--no-ff,合并必须产生一个新的、不同的合并提交(相同的树,但仍然是不同的提交,具有不同的父年龄):
A--B--C-----C1----C2---M <-- master\n \\ X\n E--F----G------m2 <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n这里 mergeM有C2作为它的第一个父级和G第二个父级。这表明它是G2(“非第一个”父级)到master(第一个父级)的合并。m2另一方面,MergeG作为其第一个父级,并且C2第二个父级。
换句话说,树(工作目录)是相同的,父级的集合(列表忽略顺序)是相同的,甚至提交消息和时间戳也可以是相同的:但是顺序父级的不同,仅此一点就足以保证这些将是不同的提交。
\n\n你的问题的标题是关于变基,而不是合并。Rebase 是完全不同的操作。假设您在分支上dev并运行git rebase master。
要进行变基,git 所做的是(本质上\xe2\x80\x94 应用了一些优化,以及一些合并提交的极端情况)简单地“挑选”沿某个分支的每个提交,然后应用这些“樱桃”到其他一些分支。让我们回到第一张图:
\n\nA--B--C--C1--C2 <-- master\n \\\n E--F--G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n这里的想法是“选择”提交E,然后F,然后G按顺序应用它们。让我们首先复制E到E\',应用到 之上C2:
E\'\n /\nA--B--C--C1--C2 <-- master\n \\\n E--F--G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n接下来我们复制F成F\'这样:
E\'--F\'\n /\nA--B--C--C1--C2 <-- master\n \\\n E--F--G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n还有一个提交要复制G到G\':
E\'--F\'--G\'\n /\nA--B--C--C1--C2 <-- master\n \\\n E--F--G <-- dev\nRun Code Online (Sandbox Code Playgroud)\n\n我们都完成了,除了一件事:我们需要一个新的提交链的标签。我们就这么称呼它吧dev!哎呀,等等,我们已经有一个标签了dev。好吧,让我们撕下旧dev标签,然后将其粘贴到新标签上G\':
E\'--F\'--G\' <-- dev\n /\nA--B--C--C1--C2 <-- master\n \\\n E--F--G\nRun Code Online (Sandbox Code Playgroud)\n\n瞧,git rebase完成了。这就是它的作用:将旧的提交复制到新的提交。
老人们会怎样?嗯,他们就是我所说的“被遗弃的”。它们仍然存在于您的存储库中,但它们的唯一标签仅存储在“reflogs”中。引用日志条目将在 30 天左右的默认过期超时时间内保留它们。(它是可配置的,并且实际上有两种不同的超时,但最好将其视为“一个月左右”。)因此,大约一个月后,git 将垃圾收集废弃的提交。
\n\n有时变基是“坏的”,因为它为共享你的 git 存储库的其他人创造了更多的工作(直接地,或更可能的是,在你将你的工作推送到的某个中央存储库中)。假设其他人已经E通过 进行了提交G,并且他们做了更多的工作并H在 之上进行了提交G。然后你去复制E通过G,并放弃原来的E通过G。您现在已经完成了他们的工作,提交,但还需要更多工作:例如,H他们可能必须H在您的基础上重新建立基础。G\'
如果没有其他人E通过您的提交G,您可以确定您没有为不存在的其他人做任何额外的工作。变基只会影响你,所以大部分“坏”都会消失。
--no-ff最后,对于 rebase 与 merge(以及如果合并,是否以及何时使用)与“压缩合并并放弃原始开发链”与任何其他你可以想到的方案没有单一的答案。在 git 中进行提交,并通过合并、挑选和变基等操作它们的整个想法是为了更容易维护工作。所有对提交图的摆弄都是毫无意义的,除非它使维护实际工作变得更容易。
| 归档时间: |
|
| 查看次数: |
59 次 |
| 最近记录: |