代码之家  ›  专栏  ›  技术社区  ›  Stav Alfi

git cherry如何选择一系列提交?

  •  1
  • Stav Alfi  · 技术社区  · 7 年前

    rebase cherry-pick 一系列提交。

    我没有找到任何文章/目录来解释当一个人试图 择优挑选

    一些问题(我能想到)是:

    1. 什么 CHERRY_PICK_HEAD ref是?
    2. git cherry-pick 2^..4 ,git执行的操作顺序是什么 git使用的确切时间间隔 diff ?

    enter image description here

    1. 通过运行 git cherry-pick 1..8 ,git将做什么?

    enter image description here

    2 回复  |  直到 7 年前
        1
  •  5
  •   Stav Alfi    7 年前

    樱桃采摘 n 提交与cherry一个接一个地选择它们(具有不同的git调用)是一样的。不涉及分支或任何其他内容,只需在当前分支上为您创建新的提交即可。

    更多详细信息

    帮助页面 https://www.git-scm.com/docs/git-cherry-pick.html 说:

    给定一个或多个现有提交,应用每个提交引入的更改,为每个提交记录一个新的提交。

    让我们把这句话拆开:

    变化

    这有时也称为“差异”。这是什么 git diff HEAD somecommit 将输出。有时也称为“补丁”(实际上,来自 git diff 可以与平常一样使用 patch 实用性——当然还有 git apply 但这不是重点)。

    因此,“更改”是指指示以下工具的内容: git 色斑 如何修改文本文件以获得新的、已更改的文本文件。

    diff 两个文件上的实用程序。事实上,这就是 吉特 在内部使用cherry pick(当然,它有自己的diff实现);i、 e.这只是一个2路差速器,而不是类似于中的3路差速器 git merge 活动

    每一个介绍

    当您处于此状态时:

    ...----+----+----...
       abc  def          
    

    然后 git cherry-pick def 更改是提交之间的双向差异 abc def def “介绍”。

    应用更改

    这意味着 HEAD 和“更改”(即diff、补丁等),并创建一组新的文本文件。原则上,您可以将其视为双向合并(就像 色斑 实用程序可以)除非它不是,即如果 差异 输出与中的内容不匹配 头部 马上在这种情况下,git欺骗用户找到一个共同的祖先来进行三方合并,您可以在 What are the three files in a 3-way merge for interactive rebasing using git and meld? . 但从用户的角度来看,它仍然无法真正与 合并分支 就结构而言,它最终将是单亲提交,而不是类似于双亲提交的提交 合并分支 .

    录制新提交

    吉特 将更改应用于索引和工作目录,并提交。除非双向合并和三向合并没有冲突,在这种情况下,直接从“帮助”页面上看到我的一些评论:

    1. 当前分支和头指针停留在上次成功提交时。 [即,只是简单的头部。]
    2. [那就是 def 在我上面的照片中。]
    3. 干净地应用更改的路径在索引文件和工作树中都会更新。 [即,如果在提交中更改了许多文件,则可以干净地应用的文件是。]
    4. 对于冲突路径,索引文件最多记录三个版本,如git MERGE[1]的“TRUE MERGE”部分所述。工作树文件将包括由常用冲突标记括起的冲突描述<<<<<<&书信电报;和gt&燃气轮机&燃气轮机&燃气轮机&燃气轮机&燃气轮机>。 [即,与合并冲突相同,有一些“凭空变出来的”共同祖先。]
    5. 没有进行其他修改。

    最后,句子的其余部分:

    给定一个或多个现有提交,应用。。。记录每个的新提交。

    如果您给它多个提交,可能会显式地如中所示 git cherry-pick sha1 sha2 sha3... git cherry-pick sha1..sha2

    你的问题

    CHERRY\u PICK\u HEAD ref是什么?

    2. The CHERRY_PICK_HEAD ref is set to point at the commit that introduced the change that is difficult to apply.
    

    def ,并且发生合并冲突,则 CHERRY_PICK_HEAD 将指向 def .

    如上所述:

    1. 选择提交2,即。
      • Git计算1和2之间的差值。
      • 如果可能,该差异将作为双向合并应用到HEAD和committed。
      • 如果不可能,该差异将作为一个3路合并应用到HEAD和committed。
      • 如果 那个 不可能(即合并冲突),则您需要像往常一样手动解决冲突,它将等待您发出 git cherry-pick --continue .
    2. 选择提交4,即。。。相同的。

    通过运行git cherry pick 1。。8、git会做什么?

    同样,但这次它将选择提交2、3、4、8。

    (例如,未拾取范围中的“第一个”提交是常见行为 git log 2^..4 git log 1..8 将输出相同的提交-实际上与将拾取的相同。下面的cherry pick帮助页面对此进行了描述 <commits> 包括git如何浏览修订版的链接,了解所有详细信息。这不是 git cherry-pick 但是这些 .. 范围有效。)

        2
  •  1
  •   torek    7 年前

    我没有找到任何文章/目录来解释当一个人试图 cherry-pick 多次提交。

    在本例中,cherry pick代码使用Git的 定序器 ,也用于 git am git revert (在Git的最新版本中 git rebase — git再基 正如您所读到的,部分实现是使用 git cherry-pick ,尽管它也使用 吉特am :您得到哪一个取决于您提供给的标志 git再基 ). 注意,在内部, git还原 git樱桃镐 是相同的命令(从 builtin/revert.c ).

    sequencer只需在一系列提交上运行重复的“一次提交一次”Git子命令,如果单次命令失败,可以选择跳过任何单个提交。单个提交哈希ID通常不是通过运行 git rev-list . 所以你的“2”的第一部分和“3”可以通过运行找到问题 git版本列表 (尽管结果对人类来说不是特别有用:-)因为 git版本列表

    那么,让我们把这些按顺序排列:

    What CHERRY_PICK_HEAD ref is?

    启动定序器时 提交以进行cherry pick或revert,它 notices, writes the commit ID to CHERRY_PICK_HEAD or REVERT_HEAD , and invokes the code to do a single pick/revert . (有关更多详细信息,请点击GitHub上实际Git源代码的链接。)否则,它会执行rev list walk来构建提交列表,将其写入sequencer目录(或者如果有正在进行的序列操作,则会立即失败并拒绝您的尝试),然后一次执行一个cherry pick或revert。这需要 do_pick_commit() ,这是一个相当复杂的函数,但您可以看到,在第1118行,它还将把当前提交的哈希ID写入 CHERRY\u PICK\u头

    因此,每当任何单个樱桃采摘失败并以未合并索引停止,或由于使用 --no-commit , CHERRY\u PICK\u头 包含在命令停止时拾取的提交的哈希ID。

    然后,您可以解决问题并运行 git cherry-pick --continue . 此特定调用检查sequencer目录是否存在;如果存在,则假设您已经修复了问题,并尝试继续现有的、正在进行的樱桃拣选序列。

      2--3--4  <-- dev
     /
    1
     \
      5--6--7   <-- master (HEAD)
    

    通过运行 git cherry-pick 2^..4 ,git执行的操作顺序是什么 git使用的确切时间间隔 diff ?

    git rev-list 2^..4
    

    (更换 2 4 使用实际哈希ID,或使用名称 dev 为了识别提交4),您将看到它列出了4、3、2(按该顺序)的散列ID。执行时 git樱桃镐 不过,Git专门使用 颠倒的 按每个“.”排序-样式选择,因此实际提交哈希是2、3、4的哈希。

    因此,序列器将这三个散列ID写入序列区域,然后运行 do_pick_commit 在每一个上。从线条开始仔细观察 1043 再次在 1088 ,可以看出,说Git运行 差异 在每个提交的父级和子级之间。事实上,它运行着一个 合并 操作(“合并为动词”,我喜欢这样说),合并基是每个提交的父级,待合并提交作为 --theirs 犯罪(The --ours 与往常一样,提交是当前或 HEAD

    然而,合并操作本身 ,实际上,运行 git diff 在合并基和两个分支尖端之间。由于合并基是所选取的提交的父级,因此这会有所不同 2^ (或 1 )vs 2. 作为输入到 --他们的 一边它也不同 2^ 头部 作为输入到 --我们的 然后进行合并。

    默认情况下(无 -n --无提交 ),Git将提交此合并的结果,如果成功,则作为 单亲,非合并提交 . 所以当这个特别的樱桃采摘 执行 合并,它 普通的犯罪。这个新提交的提交消息是来自原始提交的提交消息的副本,即来自提交2的消息的副本(加上一行,如果您使用 -x

    如果一切顺利,sequencer将继续提交3。3的父项是2,因此sequencer调用合并机制来使用commit合并提交3和(上一步新创建的)头 2.

    如果 那个

    最终结果是:

      2--3--4  <-- dev
     /
    1
     \
      5--6--7--2'-3'-4'   <-- master (HEAD)
    

    哪里 2' 是一种 2. , 3' 是一种 3 4' 是一种 4.

      2---3---4
     /         \
    1--5--6--7--8   <-- dev
     \
      9   <-- master (HEAD)
    

    通过运行 git cherry-pick 1..8 ,git将做什么?

    在这里,我们将遇到多个问题。

    第一 择优挑选 调用sequencer代码,因为您已经指定了一系列提交, 2^..8 . 此特定子范围反转:

    git rev-list --reverse 2^..8
    

    此列表在中提交2、3、4、5、6、7和8 一些 秩序,但秩序到底是什么?我们要求从提交8(包括8本身)可以访问的所有提交,不包括从提交可以访问的所有提交 2^ (即提交1)。当然,没有 --reverse --反向 我们将在最后看到commit 8。但是8已经 父母,即4和7。Git可以在这里选择任何一个。

    没有 --topo-order ,Git首先选择具有最新时间戳的。假设这两个时间戳使它首先选择7。我们将得到8,然后是7(这样在反转之后,我们将得到7,最后是8)。现在,接下来要选择两个提交:6和4。假设这两个时间戳使Git接下来选择4。我们现在有两个提交可供选择:6和3。这个过程会重复,直到图中的两个分支重新收敛到提交1(无论如何我们都不会选择)。

    这个 --反向 这意味着我们得到了一个以提交8结尾的线性化列表,但2、3、4、5、6和7的顺序由时间戳决定(特别是 犯罪 时间戳,而不是作者时间戳)。因此,如果不查看提交时间戳或运行 git版本列表 ,要知道 哪一个 每个提交的订单都会被挑选出来。

    在任何情况下,sequencer仍然会逐个选择每个提交,无论它们的顺序如何 git rev-list --reverse . 但最终我们会挑选所有的2/3/4/5/6/7,它们是 合并,然后cherry pick commit 8 合并。不管怎样,我们都会通过的 the code at lines 967–990 合并, git樱桃镐 将要求我们 提供了 -m 选项为了承诺 合并提交8 git樱桃镐 将要求我们 提供 -m

    所以这棵樱桃树肯定会失败。为了让它正常工作,你 应该 樱桃采摘每个品种 2^..4 5^..7 (按任意顺序)。