大约五个月前,我们开始了一个项目,对遗留的PHP-4/5应用程序进行检修和升级,将其迁移到PHP-7(以及许多其他东西)。这个应用程序由2700多个文件组成,几乎所有的文件都做了大量的修改。
与此同时,遗留应用程序继续支持客户,到目前为止已经进行了大约250次更改。我有(也能做……)git
补丁来表示这些变化。我的直接问题是,他们中的大多数不git apply
。
当然,很容易理解为什么:"行号",如补丁中所表达的,几乎是无用的。尽管在大多数情况下,查找的源代码在那里,但它可能已经移动了一段距离。
我目前的想法(基于对大约30个补丁文件的检查)是,在有用的情况下,要打补丁的文字源代码仍然是,逐字逐句地存在于源文件中,只是不在预期的位置。
虽然我足够现实,知道许多这些补丁将不得不分析和手工制作,我想尽量减少这一点,既为了时间又为了准确性。我希望那些将要做这件事的人……包括我在内……为了能够尽可能地利用自动化工具,知道他们必须检查每个补丁的工作。我不幻想我有可能一次自动处理所有这些文件,"Shazam."
那么,谁遇到过类似的情况呢?你建议我怎么做?一个建议是使用patch
命令和fuzz
选项,注意,这可能会起作用或可能会导致应用不正确的补丁。
(我们计划在任何情况下一次做一个补丁:"patch, git commit
, rinse and repeat。"这样我们就可以git diff
检查每个更改的完整性。
请求"战争故事"。谢谢。
git apply
提供了几个可用于启发式或半手动应用补丁的选项,其中大多数在git-apply(1)
手册页中有描述:
-
-C
可以减少必须在块中匹配才能成功打补丁的上下文行数。-
-C<n>
- 确保每次更改前后至少
<n>
行周围上下文匹配。当周围的上下文行较少时,它们必须全部匹配。默认情况下,没有上下文被忽略。
-
-
--recount
将忽略行号。-
--recount
- 不要相信块头中的行数,而是通过检查补丁来推断它们(例如在编辑补丁后没有适当地调整块头)
-
-
--reject
将在.rej
文件中留下无法应用的大块,就像patch
一样。然后,您可以检查这些文件并手动应用更改。-
--reject
- 对于原子性,
git apply
默认会使整个补丁失败,并且在某些块不适用时不触及工作树。此选项使它应用补丁中适用的部分,并将被拒绝的块留在相应的*中。rej文件。
-
-
--3way
将尝试三向合并,假设补丁最初是由git生成的。-
-3
-
--3way
- 当补丁不能干净地应用时,如果补丁记录了它应该应用的blobs的身份,并且我们在本地有这些blobs,则退回到3-way合并,可能会在工作树中的文件中留下冲突标记供用户解决。该选项暗示
--index
选项,与--reject
和--cached
选项不兼容
-
就我个人而言,我已经使用git apply -C1 --recount
成功地将被子补丁转换为git提交。
或者,您可以简单地使用patch
实用程序来应用补丁,而根本不使用git apply
命令。默认情况下,patch
将模糊地应用块,并在.rej
文件中留下完全无法应用的块;如果给出了--merge
选项,则失败的块将生成冲突标记。
我也有类似的经历。我们的团队正在开发不同芯片组和不同版本的谷歌Android代码库。所谓的公共问题或特性从一个代码库移植或重用到另一个代码库。
如果是从Android M到Android M,就容易多了。但从Android L到Android M或Android n,我们都有问题。有些补丁,通常是数百个,几乎不能直接应用。git补丁是++——diff,它不够清晰或直接,当我们必须手工应用它们时,会让我们抓狂。
代码库由超过400个git仓库组成。因此,我们为每个版本创建了一个按日期排序的提交列表。我们为每次提交制作一个前后补丁。前后贴片是并排贴片。左边是修改前的文件,右边是修改后的文件。补丁文件夹结构如<commit>/before
、<commit>/after
。因此,我们可以很容易地使用"Beyond Compare"这样的工具,以更友好的方式查看变化。
我们有一个脚本来制作前后补丁。它基本上是这样的:
#!/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补丁不能自动应用,我们就按照前后补丁手动应用它。虽然工作量很大,但一定要完成。