-
Notifications
You must be signed in to change notification settings - Fork 666
Description
Description
The diff hunk header between two pairs of @
for a newly created file indicates that it applies to the first line of /dev/null
file and confuses the patch implementations on FreeBSD and OpenBSD which then ask for a filename to be specified when one tries to apply the patch.
Steps to Reproduce the Problem
Create and commit a file containing a single line, generate patches from that commit and try to apply the patches in an empty directory.
Git's output has a hunk indicator @@ -0,0 +1 @@
:
$ git show
[...]
diff --git a/hello b/hello
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/hello
@@ -0,0 +1, @@
+hello
whereas the equivalent output of jj has @@ -1,0 +1,1 @@
:
$ jj show --git -r @-
[...]
diff --git a/hello b/hello
new file mode 100644
index 0000000000..ce01362503
--- /dev/null
+++ b/hello
@@ -1,0 +1,1 @@
+hello
The problem is the first -1
here. The BSD's patch implementations (derived from Larry Wall's patch) special case @@ 0
and use that as a hint that a new file needs to be created. Whether that's a great approach is a different question, but it has been this way for more than thirty years. If it's not @@ 0
, it doesn't find the file and enters interactive mode, which doesn't work.
A simlar problem exists for the reverted diff, but it doesn't confuse BSD patch.
I think the following passage in the POSIX 2024 specification indicates that git's behavior is the expected one:
"%1d,%1d", <beginning line number>, <number of lines>
otherwise. If a range is empty, its beginning line number shall be the number of the line just before the range, or 0 if the empty range starts the file.
Expected Behavior
The diffs generated by git and jujutsu apply cleanly for the system-provided patch and create files as needed.
Actual Behavior
Attempting to apply the diffs in an empty directory results in the following ouptut on FreeBSD (tested on 14.2) and OpenBSD (tested on 7.6):
$ patch < /tmp/jj.diff
Hmm... Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|Commit ID: 58258525c7bc0bb5afa9c672df4570600da27803
|Change ID: nzylvuozztzlpxkovltwqukupmmzwmlw
|Bookmarks: master master@git
|Author: Theo Buehler <tb@openbsd.org> (2024-12-07 22:04:11)
|Committer: Theo Buehler <tb@openbsd.org> (2024-12-07 22:04:11)
|
| msg
|
|diff --git a/hello b/hello
|new file mode 100644
|index 0000000000..ce01362503
|--- /dev/null
|+++ b/hello
--------------------------
File to patch:
and as you can see, you're asked to enter the file name. This won't work of course since the file doesn't exist yet:
File to patch: hello
No file found--skip this patch? [n] n
patch: **** can't find hello
The diff generated by git on the other hand applies cleanly:
$ patch < /tmp/git.diff
Hmm... Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|commit 58258525c7bc0bb5afa9c672df4570600da27803
|Author: Theo Buehler <tb@openbsd.org>
|Date: Sat Dec 7 22:04:11 2024 +0100
|
| msg
|
|diff --git a/hello b/hello
|new file mode 100644
|index 0000000..ce01362
|--- /dev/null
|+++ b/hello
--------------------------
(Creating file hello...)
Patching file hello using Plan A...
Empty context always matches.
Hunk #1 succeeded at 1.
done
Editing the patch and changing the -1
to 0
or using GNU's patch works around this issue.
Specifications
- Platform: FreeBSD 14.x, OpenBSD 7.6
- Version: Affects jj versions 0.22 to 0.24 at least, probably present for much longer.