I recently encountered an issue using patch and git.
Say I remove two files in git and generate a patch:
diff 0890cdaa2d2a6ad756ba98130e078b3cd64bee7d 5b6279eb53ece69d2a014adf566f22adb61d94e4
--- a/a
+++ /dev/null
@@ -1,1 +1,0 @@
-foo
--- a/b
+++ /dev/null
@@ -1,1 +1,0 @@
-bar
When I try to apply this, we process the first hunk. curfile is nil,
so we set it to /dev/null, then read the contents of a into f, and
apply the hunk. Then, we get to the second hunk. It also has newpath
of /dev/null, so we *do not* read the contents of b. However, now we
are searching for the contents of b in a, which fails:
stdin:8: unable to find hunk offset in b
Historically, I believe patch implementations worked by using the
first file that existed of the --- name and the +++ name, falling back
to prompting the user for the name of the file to patch. The new
9front patch works a bit differently and patches the --- name into the
+++ name, with a bit of logic to remove files with /dev/null as the
+++ name.
I don't think this is ideal behavior, because it is common to see
patches like
--- a.orig Wed Sep 28 21:53:55 2022
+++ a Wed Sep 28 21:53:58 2022
@@ -1 +1 @@
-foo
+bar
for example in BSD ports systems. Given this file, patch(1) will
complain
patch: open a.orig: 'a.orig' file not found
rather than patching the file a. Similarly, given a patch like
--- a
+++ a.new
@@ -1,1 +1,1 @@
-foo
+bar
patch(1) will write the patched file to a.new and leave a alone
rather than patching a.
I propose we implement the standard behavior in patch(1) (maybe
without the prompting part) to interoperate better with patches
created by other tools. This will fix the issue I encountered since
there is no separate "old path" and "new path", just the file selected
for patching.
We can still retain the logic to remove the file if the +++ name is
/dev/null. However, longer term it might be worth supporting the
git-diff extended header lines:
deleted file mode <mode>
new file mode <mode>
old mode <mode>
new mode <mode>
There are also headers for renames and copies, but I don't think git
or patch should bother with that, and should just present them as
deleted and added files.
Thoughts?