Does git apply -p (leading slash removal) not work for renames?

我的梦境 提交于 2020-08-10 20:36:47

问题


Here is a simple diff file from 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

As you can see, file1.txt is modified, file2.txt is renamed, file3.txt is deleted, and file4.txt is added.

Now when I try to apply the patch:

cp -r dir1 dir_work
cd dir_work
git apply -v ../dir.diff

I get the following verbose output, indicating the patch failed on file2 rename: (patch works perfectly without 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...

So for file1, file3, file4, the leading directories (dir1/... and dir2/...) were stripped (-p1 is git apply default), but not for the rename? How can I strip the leading directory for file2?


回答1:


The problem here is that the code that detects the file rename, and the old and new names, uses the two lines:

rename from dir1/file2.txt
rename to dir2/file2_rename.txt

which as you can see include the dir1/ and dir2/ parts, but not an a/ nor b/ part. This would still be true even if you hadn't used --no-prefix in the git diff command.

In the end, git apply's -p1 option, which would normally strip just a/ and b/, is now stripping dir1/ and dir2/ from the other diff lines, but does not do anything with these two lines. Internally, git apply strips one fewer prefixes than git apply does in general:

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;
}

Using git diff without --no-prefix and git apply -p2, Git will thus strip one component from these two names. So it may help to use -p2 on the apply step, instead of --no-prefix on the git diff command.



来源:https://stackoverflow.com/questions/62858586/does-git-apply-p-leading-slash-removal-not-work-for-renames

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!