当前位置:首页 > 科技  > 软件

Git 的遴选和撤销操作是如何利用三路合并的

来源: 责编: 时间:2023-11-14 17:09:48 456观看
导读大家好!几天前,我尝试向其他人解释 Git 遴选(git cherry-pick)的工作原理,结果发现自己反而更混淆了。我原先以为 Git 遴选是简单地应用一个补丁,但当我真正这样尝试时,却未能成功!因此,接下来我们将谈论我原来以为的遴选操作(

HWL28资讯网——每日最新资讯28at.com

大家好!几天前,我尝试向其他人解释 Git 遴选(git cherry-pick)的工作原理,结果发现自己反而更混淆了。HWL28资讯网——每日最新资讯28at.com

我原先以为 Git 遴选是简单地应用一个补丁,但当我真正这样尝试时,却未能成功!HWL28资讯网——每日最新资讯28at.com

因此,接下来我们将谈论我原来以为的遴选操作(即应用一个补丁),这个理解为何不准确,以及实际上它是如何执行的(进行“三路合并”)。HWL28资讯网——每日最新资讯28at.com

尽管本文的内容有些深入,但你并不需要全部理解才能有效地使用 Git。不过,如果你(和我一样)对 Git 的内部运作感到好奇,那就跟我一起深入探讨一下吧!HWL28资讯网——每日最新资讯28at.com

遴选操作并不只是应用一个补丁

我先前理解的 git cherry-pick COMMIT_ID 的步骤如下:HWL28资讯网——每日最新资讯28at.com

  • 首先是计算 COMMIT_ID 的差异,就如同执行 git show COMMIT_ID --patch > out.patch 这个命令
  • 然后是将补丁应用到当前分支,就如同执行 git apply out.patch 这个命令

在我们详细讨论之前,我想指出的是,虽然大部分情况下这个模型是正确的,如果这是你的认知模型,那就没有问题。但是在一些细微的地方,它可能会错,我觉得这个疑惑挺有意思的,所以我们来看看它究竟是如何运作的。HWL28资讯网——每日最新资讯28at.com

如果我在存在合并冲突的情况下尝试进行“计算差异并应用补丁”的操作,下面我们就看看具体会发生什么情况:HWL28资讯网——每日最新资讯28at.com

$ git show 10e96e46 --patch > out.patch$ git apply out.patcherror: patch failed: content/post/2023-07-28-why-is-dns-still-hard-to-learn-.markdown:17error: content/post/2023-07-28-why-is-dns-still-hard-to-learn-.markdown: patch does not apply

这一过程无法成功完成,它并未提供任何解决冲突或处理问题的方案。HWL28资讯网——每日最新资讯28at.com

而真正运行 git cherry-pick 时的实际情况却大为不同,我遭遇到了一处合并冲突:HWL28资讯网——每日最新资讯28at.com

$ git cherry-pick 10e96e46error: could not apply 10e96e46... wiphint: After resolving the conflicts, mark them withhint: "git add/rm <pathspec>", then runhint: "git cherry-pick --continue".

因此,看起来 “Git 正在应用一个补丁”这样的理解方式并不十分准确。但这里的错误信息确实标明了 “无法应用 10e96e46”,这么看来,这种理解又不完全是错的。这到底是怎么回事呢?HWL28资讯网——每日最新资讯28at.com

那么,遴选到底是怎么执行的呢?

我深入研究了 Git 的源代码,主要是想了解 cherry-pick 是如何工作的,最终我找到了 这一行代码:HWL28资讯网——每日最新资讯28at.com

res = do_recursive_merge(r, base, next, base_label, next_label, &head, &msgbuf, opts);

所以,遴选实际上就是一种……合并操作?这有些出乎意料。那具体都合并了什么内容?如何执行这个合并操作的呢?HWL28资讯网——每日最新资讯28at.com

我意识到我对 Git 的合并操作并不是特别理解,于是我上网搜索了一下。结果发现 Git 实际上采用了一种被称为 “三路合并” 的合并方式。那这到底是什么含义呢?HWL28资讯网——每日最新资讯28at.com

Git 的合并策略:三路合并

假设我要合并下面两个文件,我们将其分别命名为 v1.py 和 v2.pyHWL28资讯网——每日最新资讯28at.com

def greet():    greeting = "hello"    name = "julia"    return greeting + " " + name
def say_hello():    greeting = "hello"    name = "aanya"    return greeting + " " + name

在这两个文件间,存在两处不同:HWL28资讯网——每日最新资讯28at.com

  • def greet() 和 def say_hello
  • name = "julia" 和 name = "aanya"

我们应该选择哪个呢?看起来好像不可能有答案!HWL28资讯网——每日最新资讯28at.com

不过,如果我告诉你,原始的函数(我们称之为 base.py)是这样的:HWL28资讯网——每日最新资讯28at.com

def say_hello():    greeting = "hello"    name = "julia"    return greeting + " " + name

一切似乎变得清晰许多!在这个基础上,v1 将函数的名字更改为 greetv2 将 name = "aanya"。因此,合并时,我们应该同时做出这两处改变:HWL28资讯网——每日最新资讯28at.com

def greet():    greeting = "hello"    name = "aanya"    return greeting + " " + name

我们可以命令 Git 使用 git merge-file 来完成这次合并,结果正是我们预期的:它选择了 def greet() 和 name = "aanya"HWL28资讯网——每日最新资讯28at.com

$ git merge-file v1.py base.py v2.py -pdef greet():    greeting = "hello"    name = "aanya"    return greeting + " " + name⏎

这种将两个文件与其原始版本进行合并的方式,被称为 三路合并HWL28资讯网——每日最新资讯28at.com

如果你想在线上试一试,我在 jvns.ca/3-way-merge/ 创建了一个小实验场。不过我只是草草制作,所以可能对移动端并不友好。HWL28资讯网——每日最新资讯28at.com

Git 合并的是更改,而非文件

我对三路合并的理解是 —— Git 合并的是更改,而不是文件。我们对同一个文件做出两种不同的更改,Git 试图以合理的方式将这两种更改结合到一起。当两个更改都对同一行进行操作时,Git 可能会遇到困难,此时就会产生合并冲突。HWL28资讯网——每日最新资讯28at.com

Git 也可以合并超过两处的更改:你可以对同一文件有多达 8 处不同的更改,Git 会尝试将所有更改协调一致。这被称为八爪鱼合并,但除此之外我对其并不了解,因为我从未执行过这样的操作。HWL28资讯网——每日最新资讯28at.com

Git 如何使用三路合并来应用补丁

接下来,让我们进入到一个有些出乎意料的情境!当我们讨论 Git “应用补丁”(如在变基 —— rebase、撤销 —— revert 或遴选 —— cherry-pick 中所做的)时,其实并非是生成一个补丁文件并应用它。相反,实际执行的是一次三路合并。HWL28资讯网——每日最新资讯28at.com

下面是如何将提交 X 作为补丁应用到你当前的提交,并与之前的 v1v2 和 base 设置相对应:HWL28资讯网——每日最新资讯28at.com

  1. 在你当前提交中,文件的版本是 v1
  2. 在提交 X 之前,文件的版本是 base
  3. 在提交 X 中,文件的版本是 v2
  4. 执行 git merge-file v1 base v2 以合并它们(实际上,Git 并不直接执行 git merge-file,而是运行一个实现这个功能的 C 函数)。

总的来说,你可以将 base 和 v2 视为“补丁”,它们之间的差异就是你想要应用到 v1 上的更改。HWL28资讯网——每日最新资讯28at.com

遴选如何运作

假设我们有如下提交图,并且我们打算在 main 分支上遴选提交 YHWL28资讯网——每日最新资讯28at.com

A - B (main)  /    /     X - Y - Z

那么,如何将此情景转化为我们前面提过的 v1v2 和 base 组成的三路合并呢?HWL28资讯网——每日最新资讯28at.com

  • B 是 v1
  • X 是 base,而 Y 是 v2

所以,X 和 Y 共同构成了这个“补丁”。HWL28资讯网——每日最新资讯28at.com

其实,git rebase 无非就是重复多次执行 git cherry-pick 的过程。HWL28资讯网——每日最新资讯28at.com

撤销如何运作

现在,假如我们希望在如下的提交图上执行 git revert YHWL28资讯网——每日最新资讯28at.com

X - Y - Z - A - B
  • B 是 v1
  • Y 是 base,而 X 是 v2

这个过程反映的实际上就是遴选的情况,不过 X 和 Y 的位置颠倒了。我们需要这样做因为我们期望生成一个“反向补丁”。在 Git 中,撤销和遴选关系如此的紧密,它们甚至在同一个文件中实现:revert.c。HWL28资讯网——每日最新资讯28at.com

“三路补丁”是一个非常棒的技巧

使用三路合并将提交作为补丁应用的这个技巧非常巧妙且酷炫,我很惊讶之前从未听说过!我并未听过一个特定的名字来描述这种方法,但我更倾向于称之为“三路补丁”。HWL28资讯网——每日最新资讯28at.com

“三路补丁”的理念在于,你可以通过两个文件来定义补丁:在应用补丁前后的文件(在我们这篇文章中称之为 base 和 v2)。HWL28资讯网——每日最新资讯28at.com

因此,总体来看有三个文件被涉及到:一个是原文件,另外两个构成了补丁。HWL28资讯网——每日最新资讯28at.com

最重要的是,与普通补丁相比,三路补丁是一个更加高效的补丁方案,因为在有两个完整文件的情况下,你拥有更丰富的上下文信息来进行合并。HWL28资讯网——每日最新资讯28at.com

以下是我们例子中的常规补丁的大致情况:HWL28资讯网——每日最新资讯28at.com

@@ -1,1 +1,1 @@:- def greet():+ def say_hello():    greeting = "hello"

而下面这就是一个三路补丁。不过,需要提醒的是这个“三路补丁”并不是一个真正的文件格式,这只是我自己提出的一种概念。HWL28资讯网——每日最新资讯28at.com

BEFORE: (the full file)def greet():    greeting = "hello"    name = "julia"    return greeting + " " + nameAFTER: (the full file)def say_hello():    greeting = "hello"    name = "julia"    return greeting + " " + name

《Building Git》 中提到了这点

James Coglan 的书籍 《Building Git》 是我在 Git 源码之外唯一找到的地方,他解释了 git cherry-pick 是如何在底层运用三路合并的(我原以为《Pro Git》可能会提及这个,但我并没能找到此话题的内容)。HWL28资讯网——每日最新资讯28at.com

我购买完这本书后发现,我早在 2019 年时就已经买过了,这对我来说真的是个很好的参考。HWL28资讯网——每日最新资讯28at.com

Git 中的合并实际上比这更复杂

在 Git 中,合并不限于三路合并 —— 还有一种我不太理解的叫做“递归合并”,还有许多具体处理文件删除和移动的细节,同时也有多种合并算法。HWL28资讯网——每日最新资讯28at.com

如果想要了解更多相关知识,我最好的建议是阅读《Building Git》,尽管我还未完全阅读这本书。HWL28资讯网——每日最新资讯28at.com

Git 应用到底做了什么?

我也参阅了 Git 的源代码,试图理解 git apply 的功能。它似乎(不出意外地)在 apply.c 中实现。这段代码解析了一个补丁文件,并通入目标文件来寻找应该在何处应用补丁。核心逻辑似乎在 这里:思路好像是从补丁建议的行数开始,然后向前向后找寻。HWL28资讯网——每日最新资讯28at.com

/*	 * There's probably some smart way to do this, but I'll leave	 * that to the smart and beautiful people. I'm simple and stupid.	 */	backwards = current;	backwards_lno = line;	forwards = current;	forwards_lno = line;	current_lno = line;for (i = 0; ; i++) {     ...

这个处理过程不禁让人觉得非常直白、与之前的期望相符。HWL28资讯网——每日最新资讯28at.com

Git 三路应用的工作方式

git apply 命令中也有一个 --3way 参数,可以实现三路合并。因此,我们实际上可以通过如下方式,使用 git apply 来大体实现 git cherry-pick 的功能:HWL28资讯网——每日最新资讯28at.com

$ git show 10e96e46 --patch > out.patch$ git apply out.patch --3wayApplied patch to 'content/post/2023-07-28-why-is-dns-still-hard-to-learn-.markdown' with conflicts.U content/post/2023-07-28-why-is-dns-still-hard-to-learn-.markdown

但要注意,参数 --3way 并不只用到了补丁文件的内容!补丁文件开始的部分是:HWL28资讯网——每日最新资讯28at.com

index d63ade04..65778fc0 100644

d63ade04 和 65778fc0 是旧/新文件版本在 Git 对象数据库中的 ID,因此 Git 可以用这些 ID 来执行三路补丁操作。但如果有人将补丁文件通过邮件发送给你,而你并没有新/旧版本的文件,就无法执行这个操作:如果你缺少 blob,将会出现如下错误:HWL28资讯网——每日最新资讯28at.com

$ git apply out.patcherror: repository lacks the necessary blob to perform 3-way merge.

三路合并有点历史了

有一部分人指出,三路合并比 Git 的历史还要久远,它起源于 70 年代末期左右。有一篇 2007 年的 论文 对此进行了讨论。HWL28资讯网——每日最新资讯28at.com

就说这么多!

我真的对于我对于 Git 内部应用补丁的核心方法其实理解得并不深入这一点感到非常吃惊——学习这一点真的很酷!HWL28资讯网——每日最新资讯28at.com

虽然我对 Git 用户界面存在 诸多不满,但是这个特定问题并不包含在内。三路合并似乎是统一解决一系列不同问题的优雅方式,它对于人们来说也很直观(“应用一个补丁”这个想法是许多编程者都习以为常的思考模式,而它底层实现为三路合并的细节,实际上没有人真正需要去思考)。HWL28资讯网——每日最新资讯28at.com

我顺便快速推荐一下:我正在写一部有关 Git 的 zine,如果你对它的发布感兴趣,你可以注册我非常不频繁的 公告邮件列表。HWL28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-24742-0.htmlGit 的遴选和撤销操作是如何利用三路合并的

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Python的小应用--使用PyWebIO和PyMySQL创建身份证号码查询工具

下一篇: 阿里云崩,钉钉崩,咸鱼崩,淘宝崩...应用集群故障后自动恢复测试之进程自我拉起应该怎么做?

标签:
  • 热门焦点
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 太卷!Redmi MAX 100英寸电视便宜了:12999元买Redmi史上最大屏

    8月5日消息,从小米商城了解到,Redmi MAX 100英寸巨屏电视日前迎来官方优惠,到手价12999元,比发布价便宜了7000元,在大屏电视市场开卷。据了解,Redmi MAX 100
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • 三万字盘点 Spring 九大核心基础功能

    大家好,我是三友~~今天来跟大家聊一聊Spring的9大核心基础功能。话不多说,先上目录:图片友情提示,本文过长,建议收藏,嘿嘿嘿!一、资源管理资源管理是Spring的一个核心的基础功能,不
  • 中国家电海外掘金正当时|出海专题

    作者|吴南南编辑|胡展嘉运营|陈佳慧出品|零态LT(ID:LingTai_LT)2023年,出海市场战况空前,中国创业者在海外纷纷摩拳擦掌,以期能够把中国的商业模式、创业理念、战略打法输出海外,他们依
  • 东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,&ldquo;7
  • 年轻人的“职场羞耻感”,无处不在

    作者:冯晓亭 陶 淘 李 欣 张 琳 马舒叶来源:燃次元&ldquo;人在职场,应该选择什么样的着装?&rdquo;近日,在网络上,一个与着装相关的帖子引发关注,在该帖子里,一位在高级写字楼亚洲金
  • 英特尔Xe HPG游戏显卡:拥有512EU,单风扇版本

    据10 月 30 日外媒 TheVerge 消息报道,英特尔 Xe HPG Arc Alchemist 的正面实被曝光,不仅拥有 512 EU 版显卡,还拥有 128EU 的单风扇版本。另外,这款显卡 PCB
  • 中关村论坛11月25日开幕,15位诺奖级大咖将发表演讲

    11月18日,记者从2022中关村论坛新闻发布会上获悉,中关村论坛将于11月25至30日在京举行。本届中关村论坛由科学技术部、国家发展改革委、工业和信息化部、国务
Top