应用存储是否涉及三种方式的合并,还是仅将存储修补到当前的工作树?

时间:2019-01-23 03:33:47

标签: git

git stash的帮助页上说

pop [--index] [-q|--quiet] [<stash>]
     

从存储列表中删除单个存储状态,然后将其应用到顶部   当前工作树状态的状态,即进行   git隐藏推。工作目录必须与索引匹配。

     

应用状态可能会因冲突而失败;在这种情况下,不是   从隐藏列表中删除。您需要手动解决冲突   然后手动调用git stash drop。

“应用状态”是否涉及三种方式的合并,或者只是将存储库修补到当前的工作树上?

这是什么类型的“冲突”?我只知道三向合并带来的冲突。

谢谢。

1 个答案:

答案 0 :(得分:5)

“应用状态”确实是一种三元合并。

(在文档中)您在问题How is a stash entry a child commit of HEAD commit and index's commit?中指出:

  

祖先图看起来像这样:

       .----W
      /    /
-----H----I
     

其中HHEAD提交,I是记录索引状态的提交,而W是记录工作状态的提交树。

我将把git stash pop分解为两个组成部分,依次为git stash applygit stash drop。如果套用步骤成功,则pop也将执行drop步骤。如果不是这样(例如,由于冲突而停止),pop将跳过dropgit stash代码目前为literally a shell script,我想说的只是一个shell脚本,但是它是一个相当大而复杂的代码,占了700多行,而the pop code的字面意思是这样读取:

pop_stash() {
    assert_stash_ref "$@"

    if apply_stash "$@"
    then
        drop_stash "$@"
    else
        status=$?
        say "$(gettext "The stash entry is kept in case you need it again.")"
        exit $status
    fi
}
如您所见,

应用,如果可行,请放下;如果它不起作用,请打印一条信息行,并使用将要退出的相同状态代码退出。

应用索引(I)提交

因为每个存储区至少有两个提交-I索引状态和W工作树状态,所以 apply 步骤可以同时应用 。在您运行git stash applygit stash pop时,选择是同时应用这两种状态,还是仅应用W状态。如果您选择同时应用两者,则I状态将被应用,其含义为:

git diff <hash-of-H> <hash-of-I> | git apply --cached

(尽管actual line of code稍有不同,以允许索引中包含二进制文件,并且在此之前和之后是一些相当棘手的魔术来处理各种极端情况和困难情况)。

因为这仅仅是diff | patch,所以它不是真正的三向合并。有关其含义的详细信息,请参见What is the difference between git cherry-pick and git format-patch | git am?Mark Adelsberger's accepted answermy own)。无论如何,补丁可能会失败。如果确实失败,则可以选择使用git stash branch而不是git stash apply --index,这可以保证正常工作。

应用工作树(W)提交

在任何情况下,假设您要么选择忽略I提交,要么成功应用了该提交,而Git则将结果保留下来,以便在以后的应用过程中使用,Git现在继续进行以下三个操作:您正在询问的方式合并。

这部分非常棘手。不过,它的核心是this line

if git merge-recursive $b_tree -- $c_tree $w_tree

进行三向合并,合并基础为提交H--ours提交为开始合并时索引中的值,而--theirs提交为W提交的内容。

注意:git merge-recursive会尝试在开始合并时容纳工作树中的所有内容,即使它与充当ours树的索引内容不匹配也是如此。这并不总是成功的,这就是为什么git stash pop进入肮脏的工作树通常不是一个好主意。

如果存在合并冲突,则这三棵树-$b_tree提交的Ha tree that git stash made from your index before running git merge-recursive$c_tree和提交{{1 }} –正如我在my answerGit Stash Pop - Resolve Conflicts with mergetool中所述,这是进入合并冲突暂存槽中的索引的文件的三个来源。

请注意,如果您确实使用$w_tree进行合并,则通常会丢弃开始合并时在工作树中进行的所有未暂存的更改。这也是一个通常用不干净的工作树启动W的原因。如果启动git mergetool时工作树与索引匹配,则如果发生合并冲突,状态会好得多。