【发布时间】:2013-09-16 22:46:02
【问题描述】:
this question 上的答案显示了如何选择性地推送本地提交,但似乎这些都是提示的本地提交。
如果我已经合并了来自源的新更改,使得它们与我的提交穿插在一起,(最后一次提交是“合并”消息,)我能做些什么来只推送其中一些提交吗?或者我是否需要在合并和重置/存储我想遗漏的提交之前进行分支?
【问题讨论】:
this question 上的答案显示了如何选择性地推送本地提交,但似乎这些都是提示的本地提交。
如果我已经合并了来自源的新更改,使得它们与我的提交穿插在一起,(最后一次提交是“合并”消息,)我能做些什么来只推送其中一些提交吗?或者我是否需要在合并和重置/存储我想遗漏的提交之前进行分支?
【问题讨论】:
您需要创建一个引用相关提交的 refspec,并推送该 refspec。
这背后的原因有点混乱。在push(或任何其他对象传输序列)中传输的实际对象集不一定限于您的想法。有时推送会推送“未使用”的 repo 对象,因为客户端(进行推送)和服务器(接收对象包)之间的同步是松散指定的。它保证所有 必需的 对象都会到达那里,但可能会推送一些不是必需的。实际上,要弄清楚“什么是必要的”可能需要更多的沟通,而不仅仅是推送所有内容,尤其是在发送/接收序列中进行所有压缩的情况下。
因此,“推送”内部发生的情况是客户端发送一个装满对象的大球(特别是“瘦包”),然后——在这些对象被安全地安置在服务器的存储库中之后——发送在一组“参考标签”上:
refs/heads/zorg = object 00ac1d1f1ab1ec0ffee5c01ec0idf1dd1edeedee
refs/tags/skin = object 5011d1f1ab1ebac1110515be11e5be111c05ed0e
等等。服务器通过 git pre-receive 和 update 挂钩运行这些 ref-updates 以验证它们是否正常,如果是,则将它们存储在服务器的 refs 中。 (如果需要,钩子可以检查这些对象。这让钩子可以检查标签是否“轻量级”,直接引用提交,或“注释”,引用 repo 中的标签对象,例如。)
我将在这里补充一点,我认为您的问题暗示了对分支实际工作方式的误解。分支是一种“隐含的”数据结构。 Git 有两个基本概念协调创建一个“分支”:它有分支提示标签,它命名一个单一的提交;它有提交,每个提交都带有零个或多个“父提交”ID。例如,使 master 成为分支的是分支提示名称 (refs/heads/master)。但这只会让你获得一次提交,即分支的尖端。要查找分支“上”的内容,您可以从那里开始查看该提交的父级或父级。在那一刻,每个父提交也“在”master 分支上,并且每个父级的父级都在它上面,依此类推。如果你有:
M1 -- M2 -- M3 -- M4 <-- master
\
B1 -- B2 -- B3 <-- branchB
\ /
D1 -- D2 <-- develB
然后提交B3 是“on”branchB 因为它是branchB 的尖端,并且D2 和B2 也都“on”分支因为B3 具有这两个提交作为它的父母。
如果您毕竟不想在branchB 上添加D2,但您确实想要在它上面添加D1,您必须做出一个新的(并且完全不同的)提交——让我们打电话它B4——它的父母有B2 和D1:
M1 -- M2 -- M3 -- M4 <-- master
\
| ------B4 <-- branchB
| / |
B1 -- B2 -- B3 | <-- branchB-old [or abandoned entirely]
\ / |
D1 -- D2 | <-- develB
\ /
----------
同样branchB 只是简单地命名了一个分支提交,但这与B3 不同。
push上面(B4的烂摊子)实际上可能会push commit B3到服务器,但只要没有标签,就不会有人看到,最终会被垃圾回收关闭服务器。
【讨论】:
gitk --all 或git log --graph --oneline --decorate --all 或类似的东西来查看您拥有什么),然后找出提交你想要的图表——白板或笔(cil)/纸在这里非常方便——然后才开始考虑运行git ...。这不是微不足道的,因为您正在接受“真正发生的”(实际历史)并想出一个更漂亮的“假装发生了”(新的“历史”)。