gpt4 book ai didi

git - git merge 具有不同目录结构的分支

转载 作者:行者123 更新时间:2023-12-02 07:55:22 32 4
gpt4 key购买 nike

我对git有点陌生,我已经使用了几个月,而且Im可以轻松完成大多数基本任务。所以...我认为现在该承担一些更复杂的任务了。
在我的工作中,我们有一些人在处理较旧的代码以对其进行更新,这涉及实际的代码工作以及将目录结构更新为更具模块化的方式。我的问题是,这两件事是否可以在并行分支中完成,然后合并或重新设置。我的直觉说不,因为dir重组是一个重命名,而git通过添加新文件并删除旧文件来重命名(至少这是我的理解)。但是我想确定。
这是场景:
父分支看起来像:

├── a.txt
├── b.txt
├── c.txt

然后我们分支两个分支,分别是branchA和branchB。在branchB中,我们修改结构:
├── lib
│   ├── a.txt
│   └── b.txt
└── test
└── c.txt

然后在branchA中,我们更新a,b和c。

是否可以将branchA中所做的更改与branchB中的新结构合并?
想到了rebase,但是,我不认为git mv之后lib / a.txt实际上连接到a.txt。

詹姆森

最佳答案

首先,请注意:您可以随时尝试合并,然后将其退出,以查看其作用:

$ git checkout master
Switched to branch 'master'
$ git status

(确保它是干净的—在发生更改时退出失败的合并并不有趣)
$ git merge feature

如果合并失败:
$ git merge --abort

如果自动合并成功,但是您不想保留它:
$ git reset --hard HEAD^

(请记住 HEAD^是当前提交的第一个父级,并且合并的第一个父级是“合并之前的内容”。因此,如果合并有效,则 HEAD^是合并前的提交。)

这是一个简单的配方,用于查找 git merge将自动检测到的重命名。
  • 确保diff.renamelimit 1是0,而diff.renamestrue:
    $ git config --get diff.renamelimit
    0
    $ git config --get diff.renames
    true

    如果尚未通过这种方式设置它们,请进行设置。 (这会影响下面的diff步骤。)
  • 选择您要合并到的分支,以及您要合并的分支。也就是说,您将很快执行类似git checkout master; git merge feature的操作;我们需要在这里知道这两个名字。找到它们之间的合并基础:
    $ into=master from=feature
    $ base=$(git merge-base $into $from); echo $base

    您应该看到一些40个字符的SHA-1,例如ae47361...或此处的其他内容。 (可以在这里到处随意键入masterfeature而不是$into$from。我正在使用变量,因此这是“食谱”而不是“示例”。)
  • 将合并基础与$into$from进行比较,以查看哪些文件被检测为“重命名”:
    $ git diff --name-status $base $into
    R100 fileB fileB.renamed
    $ git diff --name-status $base $from
    R100 fileC fileD

  • (您可能需要将这些差异运行,并将输出保存到两个文件中,然后在以后仔细阅读这些文件。注意:您可以使用特殊语法 master...feature获得第三个差异的效果:这里的三个点表示“查找合并基础”。)

    这两个输出部分具有文件列表ojid_code dded, A eleted, D odified, M enamed等(此示例仅具有两个重命名,匹配率为100%)。

    由于 R$into,因此第一个列表是git认为已在 master中发生的事情。 (当合并 master时,这些是git“希望保留”的更改。)

    同时, feature$from,因此第二个列表是git认为 feature中发生的事情。 (这些是git在合并时希望“现在添加到 feature”中的更改。)

    在这一点上,您必须做很多工作:
  • 标记为master的文件git将被检测为已重命名。
  • 如果两个分支中的两个R列表相同,那么您可能会很好(但是仍然可以阅读)。如果第一个列表中存在R,而第二个列表中没有...,请参见下文。
  • 当您运行R(或git checkout master; git merge feature)时,git将进行第二个列表中所示的重命名,以便将这些更改“添加”到git checkout $into; git merge $from中。
  • 无论如何,请将其与您希望git检测为重命名的文件进行比较。查找要显示为master条目的DA条目:这些发生在以下情况之一:在分支之一中,您不仅重命名了文件,而且对内容的更改如此之大,以致git不再检测到重命名。

  • 如果第二个列表没有显示您想要看到的所有内容,则需要帮助git out。请参阅下面的详细说明。

    如果第一个列表的重命名不在第二个列表中,那么这可能是完全无害的,或者可能导致“不必要的”合并冲突和错过真正合并的机会。 Git将假设您打算保留此重命名,并查看merge-from分支(在这种情况下为 R$from)中发生的事情。如果原始文件在此处被修改,则git将尝试将此处的更改引入重命名的文件中。那可能就是你想要的。如果原始文件未在此处修改,则git没有任何内容可放入,并且将保留该文件。那可能也是您想要的。同样,“坏”情况是未检测到的重命名:git认为原始文件已在 feature分支中删除,并创建了其他名称的新文件。

    在这种“坏”情况下,git会给您合并冲突。例如,它可能会说:
    CONFLICT (rename/delete): newname deleted in feature and renamed in HEAD.
    Version HEAD of newname left in tree.
    Automatic merge failed; fix conflicts and then commit the result.

    这里的问题不是git在 feature中以新名称保留了文件(我们可能要这么做);这是因为git可能错过了合并分支 master中所做的更改的机会。

    更糟糕的是-这可能可以归类为错误-如果新名称出现在merge-from分支 feature中,但是git认为那里是一个新文件,git只会在工作树中留下文件的merge-into版本。发出的消息是相同的。在这里,我对 feature进行了一些更改,以将 master重命名为 fileB,并在 fileE上,确保git不会将更改检测为重命名:
    $ git diff --name-status $base master
    R100 fileB fileE
    $ git diff --name-status $base feature
    D fileB
    R100 fileC fileD
    A fileE
    $ git checkout master; git merge feature
    CONFLICT (rename/delete): fileE deleted in feature and renamed in HEAD.
    Version HEAD of fileE left in tree.
    Automatic merge failed; fix conflicts and then commit the result.

    注意潜在的误导性消息 feature。 Git正在打印新名称(名称的 fileE deleted in feature版本);那是它相信您“想要”看到的名称。但是在 master中“删除”的是文件 fileB,由全新的 feature代替。

    (下面提到的 fileE可能能够处理这种特殊情况。)

    1还有一个 git-imerge(在源代码中用小写的 merge.renameLimit拼写,但是这些配置变量不区分大小写),可以单独设置。将这些设置为0会告诉git使用“合适的默认值”,随着CPU的速度越来越快,这些默认值多年来已经发生了变化。如果未设置单独的合并重命名限制,则git使用diff重命名限制,如果未设置或为0,则再次使用合适的默认值。如果设置不同,则merge和diff将在不同情况下检测重命名。

    您现在还可以在与 limit,例如 -Xrename-threshold=的递归合并中设置“重命名阈值”。此处的用法与 -Xrename-threshold=50%git diff选项的用法相同。此选项首先出现在git 1.7.4中。

    假设您在 -M分支上,并且执行 mastergit merge 12345467。这是git的作用:
  • 查找合并基础:git merge otherbranchgit merge-base master 1234567

    这产生一个提交ID。我们将该ID称为git merge-base master otherbranch,称为“基本”。 Git现在具有三个特定的提交ID:B,合并基础;当前分支B的提示的提交ID;以及您提供的提交ID,master或分支1234567的提示。为了完整起见,我们只用提交图来绘制这些内容。假设它看起来像这样:
    A - B - C - D - E       <-- master
    \
    F - G - H - I <-- otherbranch

    如果一切顺利,git将产生一个合并提交,该提交具有otherbranchE作为其两个父项,但是我们想将注意力集中在生成的工作树上,而不是提交图上。
  • 鉴于这三个提交(I BE),git计算两个差异,即la I:
    git diff B E
    git diff B I

    在这种情况下,第一个是对git diff进行的更改集,第二个是对branch进行的更改集。

    如果您手动运行otherbranch,则可以使用git diff设置用于重命名检测的“相似性阈值”(在合并过程中对其进行设置,请参见上文)。 Git的默认合并将自动重命名检测设置为50%,这是在没有-M选项且-M设置为diff.renames的情况下得到的结果。

  • 如果文件“足够相似”(并且“完全相同”就足够了),则git将检测到重命名:
        $ git diff B otherbranch  # I tagged the merge-base `B`
    diff --git a/fileB b/fileB.txt
    similarity index 71%
    rename from fileB
    rename to fileB.txt
    index cfe0655..478b6c5 100644
    --- a/fileB
    +++ b/fileB.txt
    @@ -1,3 +1,4 @@
    file B contains
    several lines of
    stuff.
    +changeandrename

    (在这种情况下,我只是从 true重命名为 fileB,但是检测也可以跨目录使用。)请注意,这可以通过 fileB.txt输出方便地表示:
        $ git diff --name-status B otherbranch
    R071 fileB fileB.txt

    (我还要在这里注意,我在全局git配置中将 git diff --name-status设置为 diff.renamestrue。)
  • Git现在尝试将diff.renamelimit = 0B的更改(在I上)组合成从otherbranchB的更改(在E上)。

  • 如果git能够检测到 branch已从 lib/a.txt重命名,它将连接它们。 (并且您可以通过执行 a.txt来预览是否会这样做。)在这种情况下,自动合并结果可能是您想要的,或者足够接近。

    如果不是,它将不会。

    当自动重命名检测失败时,有一种方法可以逐步分解提交(或者可能已经被充分分解)。例如,假设按照 git diff的顺序 F G H提交,一个步骤(也许是 I)只是将 G重命名为 a.txt,而其他步骤( lib/a.txtF和/或 H)对 I进行了许多其他更改( )愚弄git,以至于没有意识到文件已重命名。您可以在此处执行的操作是增加合并次数,以便git可以“查看”重命名。为了简单起见,我们假设 a.txt不会更改 F,而 a.txt重命名它,以便从 GB的差异显示重命名。我们可以做的是首先合并commit G:
    git checkout master; git merge otherbranch~2

    一旦合并完成,并且git在树中从 G重命名为 a.txt,以对分支 lib/a.txt进行新的合并提交,我们将进行第二次合并以引入 branchH:
    git merge otherbranch

    此两步合并使git“做正确的事”。

    在最极端的情况下,一个增量的,逐个提交的合并序列(手动完成将非常痛苦)将拾取所有可能拾取的东西。幸运的是,已经有人为您编写了这个“增量合并”程序: I 。我没有尝试过,但是对于困难的情况,这是显而易见的答案。

    关于git - git merge 具有不同目录结构的分支,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22582605/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com