代码之家  ›  专栏  ›  技术社区  ›  Ulrich Scholz

Git:更改文件的修改属性

git
  •  1
  • Ulrich Scholz  · 技术社区  · 6 年前

    我们的代码使用一个数据库,这个数据库的特定模式版本与一个版本号相关联。现在的版本是95。

    update_96 . 但是,如果其他人同时更新数据库,并且她/他的功能分支在此之前被合并以进行开发,则具有该名称的文件已经存在。合并或重设基础会产生冲突。

    现在,两个新的 更新\u 96 文件是独立的:我想,我只需要将我的重命名为 update_97 以前是 并尝试合并这两个文件。我猜,原因是修改属性重命名为修改。

    如何将此属性更改为Added?删除/读取的各种实验 更新\u 97 在单独的提交没有解决这个问题。

    2 回复  |  直到 6 年前
        1
  •  0
  •   torek    6 年前

    X 提交B有一个文件 Y ,这是两个单独的提交,包含两个单独的文件。

    当Git比较两个提交时,就像比较其中一个提交中的两个图片一样 Spot the Difference games . 左边有个快照,右边有个快照。每个快照都由文件组成。让我们把commit A放在左边,commit B放在右边,比较一下:

    • Y ,而提交B只有 Y 已删除 (再加上任何不同的 ).

    • 如果提交只有 ,提交B同时具有 Y ,则比较A和B的结果将是: 文件 已创建 (以及任何不同的 ).

    • 但如果有人 ),并且提交B (而不是 现在 事情变得有趣起来。有一对文件 不匹配,但可能 内容仍然匹配 .

    这是第三种情况,Git将尝试 文件是否被重命名(也可能被修改)。如果内容完全匹配,Git会将文件视为已重命名(或未更改),一位一位,100%相同。但这对于现实世界的案例来说还不够好,所以Git会的 如果内容仅匹配99%、80%甚至51%,请查看重命名的文件。

    此重命名检测是一个确定文件身份的问题。是文件 在与文件相同的 Y Ship of Theseus 相似性指数 ,一个介于0%相似和100%精确匹配之间的数字,并命令一个文件 已重命名 i、 例如,相同的文件如果一个不匹配的左侧文件与一个不匹配的右侧文件至少有50%相似。具有名称匹配的文件已经作为“同一文件”配对,因此这只适用于上述具有文件的情况 .

    这个“50%相似”只是一个例子 不过。如果你的迁移与其他人的迁移有62%的相似性,而所有其他文件 应该 被检测为“更名”都比较相似,可以吗 提高门槛 . (与 git diff 必须关闭 具有 -M

    现在,在上面,我一直在说 差异比较 git rebase git merge . 但是 git再基 实际上是一系列的cherry pick操作,每个cherry pick都是一个合并,而 合并分支 当然也是合并(好吧,除非是“快进”,这根本不是合并)。因此 你所做的一切都涉及到Git的内部合并引擎。 怎样 Git的合并引擎可以工作,其实很简单:

    • 合并操作有三个输入: 合并基 我们称之为 B 还有左边 L R . 左边 提交是关键 --ours 一个,另一个 R 提交是关键 --theirs

    • 为了执行合并,Git将合并基与两边的每一边进行比较:

      git diff --find-renames <B> <L>   # what we changed
      git diff --find-renames <B> <R>   # what they changed
      

      那么吉特 合并两组更改 变成一个大的变化来应用 B --find-renames

      (当然,如果Git 查找重命名,可以有重命名/重命名冲突,或重命名/删除冲突。但在这之前你不用担心。如果只有这两个不同点中的一个“面”重命名了一个文件,那么Git通过进行重命名来组合更改。)

    • 组合了这些更改之后,Git将它们应用于 B 更改到工作树中,并因合并冲突而停止(并在索引中保留每个输入文件的所有三个版本)。你得收拾残局。

    在您的特定情况下,问题是Git在您不希望的情况下检测到重命名。如果这两个文件完全匹配,Git仍然会检测到这些重命名,但在这种情况下,它通常是无害的。这种情况通常只有在Git猜错的时候才有问题,因为一个文件有点太相似,或者相反的情况是它不够相似。

    幸运的是,就像 差异比较 ,你可以 相似性阈值。这个 git再基 命令接受Git的调用 策略选项 ,我认为这是一个可怕的名字;我叫他们 因为给他们的信是 -X (扩展)。其中之一就是 -X find-renames= threshold 好的 坏的 rename只有62%相似,具体如下:

    git merge ... -X find-renames=90 ...
    

    当然,如果某个“好”的重命名为51%,而某个“坏”的重命名为99%,这并没有帮助。在不知道实际数字是多少的情况下,你怎么知道该用什么呢 -X find-renames 差异比较

    • 找到合并基。为了 合并分支 ,使用 git merge-base --all . 对于cherry pick,合并基是要复制的提交的父级。Rebase使用cherry pick,因此要复制的每个提交的合并基是该提交的父级。找到发生“重命名”(实际上不是重命名)的提交对,并使用其父级。

    • 现在您已经有了合并基础,请将其与感兴趣的提交(合并的左侧和右侧)进行比较,使用 差异比较 -M50 或设置 diff.renames true 差异比较 将执行重命名检测。)

    还有一些问题。特别是,如果你正在做一个再基,那就需要一系列的樱桃采摘。这个 --我们的 或者,每次合并的左侧都是要在其上拾取樱桃的提交,在复制完上一个提交之前,您不知道该提交是什么,因为rebase构建了 新的 提交链一次提交一个。也就是说,输入 L commit是 以前的 樱桃采摘(这就是为什么一些折扣一再重复相同的合并冲突。)

    不过,这是使用Git提供的工具解决每个问题的一般方法(在实践中,您通常可以猜测:匹配不好意味着默认的50%太容易接受,所以只需移动一半到严格,或75%,然后重试。错过的匹配意味着它太严格了,所以移动一半到permissive,或者25%,然后重试。)

    (注意 -X查找重命名 是新的拼写;对于非常旧的Git版本,它是 -X rename-threshold 合并分支 文档。)

        2
  •  0
  •   OhleC    6 年前

    可以将git属性设置为 -merge 对于这些文件,这将完全阻止自动合并。

    为此,您需要添加一行

    update_* -merge
    

    给你的 .gitattributes

    请参见: https://git-scm.com/docs/gitattributes#_performing_a_three_way_merge

    一个更高级的解决方案将定义和设置一个自定义的合并驱动程序(也在上面的链接中描述)