Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply git patch created with git diff

I am trying to move uncommited changes from a local git repository to another local repository. On repo 1 I create a patch like this:

git diff > my_patch.patch

Inspecting the patch:

more my_patch.patch

I get the same output as running git diff on the first repo. In the second repo I run:

git apply --stat my_patch.patch
0 files changed

If I run git apply my_patch.patch I get no effect.
Am I creating the patch wrong? Am I applying it wrong?

Steps to reproduce the issue:

  1. Clone a repository 2 times (same branch checkout)
  2. In first repo, make some changes to a file (uncommited).
  3. Create patch from changes: git diff > ~/my_patch.patch
  4. Go to second repository. Try and apply patch: git apply ~/my_patch.patch
  5. Run git status. No changes!

Suggesting another way of moving uncommited changes to another local repo would also be good to solve my issue.

like image 614
Alex Rebega Avatar asked Jun 28 '26 14:06

Alex Rebega


1 Answers

Not only your usecase now (Q4 2021, Git 2.34+) is working as expected, but Git 2.35 (Q1 2022), "git apply"(man) has also been taught to ignore a message without a patch with the --allow-empty option.
And it learned to honor the --quiet option given from the command line.

See commit 324eb77, commit c21b8ae (13 Dec 2021) by Jerry Zhang (jerry-skydio).
(Merged by Junio C Hamano -- gitster -- in commit 62a3a27, 22 Dec 2021)

git-apply: add --allow-empty flag

Signed-off-by: Jerry Zhang

Some users or scripts will pipe "git diff"(man) output to git apply(man) when replaying diffs or commits.
In these cases, they will rely on the return value of "git apply" to know whether the diff was applied successfully.

However, for empty commits, "git apply" will fail.
This complicates scripts since they have to either buffer the diff and check its length, or run diff again with "exit-code", essentially doing the diff twice.

Add the "--allow-empty" flag to "git apply" which allows it to handle both empty diffs and empty commits created by git format-patch(man) --always by doing nothing and returning 0.

git apply now includes in its man page:

[--verbose | --quiet] [--unsafe-paths] [--allow-empty] [...]

git apply now includes in its man page:

--allow-empty

Don't return error for patches containing no diff.
This includes empty patches and patches with commit text only.


"git apply"(man) failed to extract the filename the patch applied to, when the change was about an empty file created in or deleted from a directory whose name ends with an SP, which has been corrected with Git 2.45 (Q2 2024), batch 16.

In your case, the git apply will be more robust.

See commit 776ffd1 (29 Mar 2024), commit 012c8b3 (28 Mar 2024), and commit 5ea0176 (19 Mar 2024) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 8289a36, 09 Apr 2024)

apply: parse names out of "diff --git" more carefully

Reported-by: Han Young

"git apply"(man) uses the pathname parsed out of the diff(man) --git header to decide which path is being patched, but this is used only when there is no other names available in the patch.
When there is any content change (like we can see in this patch, that modifies the contents of "apply.c") or rename (which comes with "rename from" and "rename to" extended diff headers), the names are available without having to parse this header.

When we do need to parse this header, a special care needs to be taken, as the name of a directory or a file can have a SP in it so it is not like "find a space, and take everything before the space and that is the preimage filename, everything after the space is the postimage filename".
We have a loop that stops at every SP on the "diff --git a/dir/file b/dir/foo" line and see if that SP is the right place that separates such a pair of names.

Unfortunately, this loop can terminate prematurely when a crafted directory name ended with a SP.
The next pathname component after that SP (i.e.
the beginning of the possible postimage filename) will be a slash, and instead of rejecting that position as the valid separation point between pre- and post-image filenames and keep looping, we stopped processing right there.

The fix is simple.
Instead of stopping and giving up, keep going on when we see such a condition.

like image 191
VonC Avatar answered Jun 30 '26 04:06

VonC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!