git apply -p(前导斜杠删除)是否不适用于重命名?
Does git apply -p (leading slash removal) not work for renames?
这是来自 git diff --no-index --no-prefix dir1 dir2 > dir.diff
的简单差异文件:
diff --git dir1/file1.txt dir2/file1.txt
index 45b983b..ce01362 100644
--- dir1/file1.txt
+++ dir2/file1.txt
@@ -1 +1 @@
-hi
+hello
diff --git dir1/file2.txt dir2/file2_rename.txt
similarity index 100%
rename from dir1/file2.txt
rename to dir2/file2_rename.txt
diff --git dir1/file3.txt dir1/file3.txt
deleted file mode 100644
index b1a17ba..0000000
--- dir1/file3.txt
+++ /dev/null
@@ -1 +0,0 @@
-zzz
diff --git dir2/file4.txt dir2/file4.txt
new file mode 100644
index 0000000..f761ec1
--- /dev/null
+++ dir2/file4.txt
@@ -0,0 +1 @@
+bbb
可以看到,修改了file1.txt,重命名了file2.txt,删除了file3.txt,增加了file4.txt。
现在,当我尝试应用补丁时:
cp -r dir1 dir_work
cd dir_work
git apply -v ../dir.diff
我得到以下详细输出,表明 file2 重命名时补丁失败:(补丁在没有 file2 的情况下工作完美)
Checking patch file1.txt...
Checking patch dir1/file2.txt => dir2/file2_rename.txt...
error: dir1/file2.txt: No such file or directory
Checking patch file3.txt...
Checking patch file4.txt...
所以对于 file1、file3、file4,前导目录(dir1/...
和 dir2/...
)被剥离(-p1
是 git apply
默认值),但不是改名?如何去除 file2 的前导目录?
这里的问题是检测文件重命名以及新旧名称的代码使用了两行:
rename from dir1/file2.txt
rename to dir2/file2_rename.txt
如您所见,其中包括 dir1/
和 dir2/
部分,但不包括 a/
和 b/
部分。即使您没有在 git diff
命令中使用 --no-prefix
,这仍然是正确的。
最后,git apply
的 -p1
选项,通常只剥离 a/
和 b/
,现在剥离 dir1/
和 dir2/
从 other diff 行,但不对这两行做任何事情。在内部,git apply
通常比 git apply
少去除一个前缀:
static int gitdiff_renamesrc(struct gitdiff_data *state,
const char *line,
struct patch *patch)
{
patch->is_rename = 1;
free(patch->old_name);
patch->old_name = find_name(state->root, line, NULL,
state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
使用git diff
没有 --no-prefix
和git apply -p2
,Git将因此去除一个 这两个名字的组成部分。因此,在 apply
步骤中使用 -p2
可能会有所帮助,而不是在 git diff
命令中使用 --no-prefix
。
这是来自 git diff --no-index --no-prefix dir1 dir2 > dir.diff
的简单差异文件:
diff --git dir1/file1.txt dir2/file1.txt
index 45b983b..ce01362 100644
--- dir1/file1.txt
+++ dir2/file1.txt
@@ -1 +1 @@
-hi
+hello
diff --git dir1/file2.txt dir2/file2_rename.txt
similarity index 100%
rename from dir1/file2.txt
rename to dir2/file2_rename.txt
diff --git dir1/file3.txt dir1/file3.txt
deleted file mode 100644
index b1a17ba..0000000
--- dir1/file3.txt
+++ /dev/null
@@ -1 +0,0 @@
-zzz
diff --git dir2/file4.txt dir2/file4.txt
new file mode 100644
index 0000000..f761ec1
--- /dev/null
+++ dir2/file4.txt
@@ -0,0 +1 @@
+bbb
可以看到,修改了file1.txt,重命名了file2.txt,删除了file3.txt,增加了file4.txt。
现在,当我尝试应用补丁时:
cp -r dir1 dir_work
cd dir_work
git apply -v ../dir.diff
我得到以下详细输出,表明 file2 重命名时补丁失败:(补丁在没有 file2 的情况下工作完美)
Checking patch file1.txt...
Checking patch dir1/file2.txt => dir2/file2_rename.txt...
error: dir1/file2.txt: No such file or directory
Checking patch file3.txt...
Checking patch file4.txt...
所以对于 file1、file3、file4,前导目录(dir1/...
和 dir2/...
)被剥离(-p1
是 git apply
默认值),但不是改名?如何去除 file2 的前导目录?
这里的问题是检测文件重命名以及新旧名称的代码使用了两行:
rename from dir1/file2.txt rename to dir2/file2_rename.txt
如您所见,其中包括 dir1/
和 dir2/
部分,但不包括 a/
和 b/
部分。即使您没有在 git diff
命令中使用 --no-prefix
,这仍然是正确的。
最后,git apply
的 -p1
选项,通常只剥离 a/
和 b/
,现在剥离 dir1/
和 dir2/
从 other diff 行,但不对这两行做任何事情。在内部,git apply
通常比 git apply
少去除一个前缀:
static int gitdiff_renamesrc(struct gitdiff_data *state,
const char *line,
struct patch *patch)
{
patch->is_rename = 1;
free(patch->old_name);
patch->old_name = find_name(state->root, line, NULL,
state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
使用git diff
没有 --no-prefix
和git apply -p2
,Git将因此去除一个 这两个名字的组成部分。因此,在 apply
步骤中使用 -p2
可能会有所帮助,而不是在 git diff
命令中使用 --no-prefix
。