Create git diff between two directories and apply patch to directory

Viewed 1356

My goal is to create a diff between two folders so that file changes can be applied easily.

My current command:

git diff --no-index --binary 20140902/ 20141227/ > 01.diff

The diffs of each file look like this:

diff --git a/20140902/Documents/sheet.xlsx b/20141227/Documents/sheet.xlsx
index 3d0d2c8acd53eb068ac5d390048e7f624dd012b9..fe5a87dd3b99874746e137d752fa6b151544c0ca 100644
GIT binary patch
delta 11480
...

How can I apply this diff to a folder current which has the same contents as 20140902 (or if necessary, to a folder named 20140902)?

When I try

cd current/
git apply ../01.diff

I get

error: git diff header lacks filename information when removing 1 leading pathname component (line 3)

where line 3 is line "GIT binary patch". Maybe the lines in diff file should look like

diff --git a/Documents/sheet.xlsx b/Documents/sheet.xlsx

?

1 Answers

TL;DR: try git apply -p2 ....

Description

The right setup is not completely clear to me from your posting, so I will show my setup:

$ mkdir tpatch
$ cd tpatch
$ mkdir -p 20140902/Documents 20141227/Documents
$ printf 'binary\0stuff' > 20140902/Documents/foo
$ printf 'different\0binary' > 20141227/Documents/foo
$ git diff --no-index --binary 20140902/ 20141227/ > 01.diff

(The resulting patch is indeed a GIT binary patch thanks to the NULs in the printf output above, though mine has two literals instead of a delta.)

Next, I created a repository in the directory current. If your repository is at a different level, you might need a different -p value:

$ mkdir current; cd current; git init
Initialized empty Git repository in .../tmp/tpatch/current/.git/
$ cp -r ../20140902/Documents .
$ ls
Documents
$ git add . && git commit -m initial
[master (root-commit) ee60bbe] initial
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Documents/foo

Note that at this point I get the same error with a plain git apply, becuase stripping a/ from the diff leaves Git with 20140902/Documents/foo, not Documents/foo:

$ git apply ../01.diff 
error: git diff header lacks filename information when removing 1 leading pathname component (line 3)

However, by using -p2, we tell Git to remove two components (a/20140902/) from the path, after which the file name Documents/foo matches the one in the repository and work-tree:

$ git apply -p2 ../01.diff
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   Documents/foo

no changes added to commit (use "git add" and/or "git commit -a")

If you have a more complex situation, you might need to use the --src-prefix and/or --dst-prefix options in the git diff command in the first place, but probably just -p2 will do the trick.

Related