Git:建议在知道来源发生重大变化时应用补丁

时间:2016-06-26 14:12:22

标签: git patch

大约五个月前,我们开始了一个项目,对大型PHP-4/5应用程序进行大修和升级,将其转移到PHP-7(以及许多其他方面)。该应用程序包含2,700多个文件,并对几乎所有文件进行了大量更改。

与此同时,遗留应用程序继续为客户提供支持,迄今已进行了大约250次更改。我有(并且可以制作......)git补丁来表示这些变化。我当前的问题是,他们中的大多数都没有git apply

当然,很容易理解为什么:补丁中表达的“行号”非常无用。虽然在大多数情况下,正在查找的源代码是,但它可能已移动了一段距离。

我目前的想法(基于对大约30个补丁文件的检查)是有用的 - 很多情况下要修补的文字源代码是仍然在源文件中逐字存在,而不是在预期的位置。

虽然我现实足以知道许多这些补丁必须手工分析和制作,但我想最大限度地减少这一点,无论是为了时间还是为了准确。我希望那些将会这样做的人......包括我(!)......能够尽可能地利用自动化工具,因为他们知道他们必须检查每个补丁的工作。我没有幻想,我可能会立即自动执行所有这些文件,“Shazam。

因此,谁在那里处理过类似的情况?你有什么建议我这样做?一个建议是使用带有patch选项的fuzz命令,但需要注意的是,可能会导致应用错误的补丁。

(我们计划在任何情况下一次做一个补丁:“补丁,git commit,冲洗并重复。”这样我们就可以git diff检查每个改变理智。)

“战争故事”要求。感谢。

2 个答案:

答案 0 :(得分:0)

我有类似的经历。我们的团队正在开发谷歌不同芯片组和不同版本的Android代码库。所谓的通用颁发或功能从一个代码库移植或重用到另一个代码库。

如果它从Android M到Android M,它会更容易。但是我们遇到了从Android L到Android M或Android N的问题。一些补丁(通常是几百个)很难直接应用。并且git补丁是++ - diff,它们不够清晰或不够简单,当我们必须手动应用它们时,它们让我们很生气。

代码库由400多个git repos组成。因此,我们为每个仓库制作按日期排序的提交列表。我们为每个提交制作一个前后补丁。前后补丁是并排补丁。左边是更改前的文件,右边是更改后的文件。补丁文件夹结构类似于<commit>/before<commit>/after。因此,我们可以轻松使用“超越比较”等工具。以更友好的方式看待变化。

我们有一个脚本来制作前后补丁。它基本上是这样的:

#!/bin/bash 

#takes one parameter, the commit
commit=$1

#copy the modified files after the change
git checkout -f $commit
git log -1 $commit --name-only --pretty=%h | tail -n +3 | while read line
do
mkdir -p ~/backup/$commit/after/$(dirname $line)
cp -v $line ~/backup/$commit/after/$line
done

#copy the same files before the change
git checkout -f $commit^
git log -1 $commit --name-only --pretty=%h | tail -n +3 | while read line
do
mkdir -p ~/backup/$commit/before/$(dirname $line)
cp -v $line ~/backup/$commit/before/$line
done

然后,差异补丁和之前的补丁和列表都会传递给团队成员。如果无法自动应用git diff补丁,我们只需按照之前的补丁手动应用它。虽然工作量很大,但还是要完成。

答案 1 :(得分:0)

git apply提供了几个选项,可用于试探性地或半手动地应用补丁,git-apply(1)手册页中对此进行了详细描述:

  • -C可以减少为了成功修补必须在块中匹配的上下文行的数量。

      
    -C<n>
    确保每次更改前后至少有<n>行周围上下文匹配。当周围环境的行数减少时,它们都必须匹配。默认情况下,不会忽略任何上下文。
  • --recount将忽略行号。

      
    --recount
    不要相信块头中的行数,而是通过检查补丁来推断它们(例如,在编辑补丁后未适当调整块头)。
  • --reject会像.rej一样在patch文件中留下无法应用的块。然后,您可以检查这些文件并手动应用更改。

      
    --reject
    对于原子性,默认情况下,git apply会使整个补丁失效,并且当某些块不适用时不会触及工作树。此选项使它可以应用补丁的适用部分,并将被拒绝的块保留在相应的* .rej文件中。
  • --3way将尝试三向合并,假设补丁最初是由git生成的。

      
    -3
    --3way
    当补丁不能完全应用时,如果该补丁记录了它应该应用于blob的标识,并且这些blob在本地可用,可能会将冲突标记保留在工作树的文件中,以供用户解决。此选项暗含--index选项,并且与--reject--cached选项不兼容。

我个人使用git apply -C1 --recount成功地将被子补丁转换为git commits。

或者,您可以简单地使用patch实用程序来应用补丁,而根本不使用git apply命令。默认情况下,patch将模糊地应用块,而将块完全无法应用于.rej文件中;如果指定了--merge选项,则失败的大块将改为生成冲突标记。