8

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.

4
  • It would help if you created a minimal reproducible example. Note that git apply --stat tells you what would change, without applying, as it disables the --apply option. Commented Apr 29, 2020 at 9:15
  • I know, I just wanted to show that git will not make any change from the .patch file. Commented Apr 29, 2020 at 10:25
  • 1
    If I try your 5 steps, the result is that git status shows me Changes not staged for commit in the modified file, and git diff in the clone in which the patch is applied shows the same patch I applied with git apply. Commented Apr 29, 2020 at 10:38
  • I cannot reproduce the problem. The patch applies on the clone and I see the differences applied there. Commented Apr 29, 2020 at 20:30

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.