14

I am trying to apply a few patches to my repo, and getting message patch does not apply unless I specify params --ignore-space-change --ignore-whitespace. Some patches can't be applied even with these keys, it says there are conflicts to be solved manually. (but actually nothing conflicts there, auto merge must had solved this)

I have done an experiment: created a patch from a commit in my repo, reset master to the previous commit, tried to apply patch from the file. The same error message.

Any ideas, why this might happen?

UPD the commands are very simple:

git format-patch -o ../_patches 0f3bf7874c32b22256ae2d9dc00b1afd6464e43c
git reset --hard 0f3bf7874c32b22256ae2d9dc00b1afd6464e43c
git am ../_patches/0001-test2.patch

(this id refers to the first commit before last)

fithu
  • 2,101
  • 2
  • 16
  • 22

2 Answers2

16

You need to pass the --keep-cr flag to git am. It's unfortunate, but because of competing standards (email workflow versus local), there's really not much choice.

You may want to try setting up a .gitattributes file as well. Trying to recreate your issue, I was able to get things to work when I specified the file as requiring CRLF. Note, without normalizing the files first, it did show the whole file as modified. I commonly use a .gitattributes with this:

.gitattributes  export-ignore
.gitignore      export-ignore

*.txt           text
*.C             text trailing-space space-before-tab -indent-with-non-tab
*.rst           text trailing-space space-before-tab -indent-with-non-tab
*.clj           text trailing-space space-before-tab -indent-with-non-tab

*.c             text diff=cpp trailing-space space-before-tab -indent-with-non-tab
*.cpp           text diff=cpp trailing-space space-before-tab -indent-with-non-tab
*.h             text diff=cpp trailing-space space-before-tab -indent-with-non-tab
*.hpp           text diff=cpp trailing-space space-before-tab -indent-with-non-tab
*.py            text diff=python trailing-space space-before-tab -indent-with-non-tab
*.tex           text diff=tex
*.java          text diff=java trailing-space space-before-tab -indent-with-non-tab
*.pl            text diff=perl trailing-space space-before-tab -indent-with-non-tab
*.php           text diff=php
*.rb            text diff=ruby trailing-space space-before-tab -indent-with-non-tab

*.vcproj        eol=crlf
*.dsp           eol=crlf
*.dsw           eol=crlf

*.sh            eol=lf

*.jpg           binary
*.png           binary
*.gif           binary
*.tiff          binary

You'll want to normalize your line ending according to the gitattributes man page. Another SO user ended up turning off core.autocrlf as well to get clean commits and patches.

Trying to reproduce your bug

$ git init repo
Initialized empty Git repository in c:/tmp/git-eol/repo/.git/
$ cd repo
$ git config --local core.autocrlf false
$ vim foo.txt
$ git add foo.txt
$ git commit -m "Add foo."
[master (root-commit) 3903abd] Add foo.
 1 file changed, 3 insertions(+)
 create mode 100644 foo.txt
$ vim foo.txt
$ git st
## master
 M foo.txt
$ git commit -m "Add more foo." -a
[master 03e991a] Add more foo.
 1 file changed, 2 insertions(+)
$ git format-patch HEAD~1
0001-Add-more-foo.patch
$ vim 0001-Add-more-foo.patch

Looking at the patch file that was produced, I see this:

As you can see, the carriage returns (^Ms) were kept in the patch. This is with core.autocrlf=false. Continuing on, I see:

$ git reset --hard HEAD~1
HEAD is now at 3903abd Add foo.
$ git am 0001-Add-more-foo.patch
Applying: Add more foo.
error: patch failed: foo.txt:1
error: foo.txt: patch does not apply
Patch failed at 0001 Add more foo.
The copy of the patch that failed is found in:
   c:/tmp/git-eol/repo/.git/rebase-apply/patch
When you have resolved this problem, run "git am --resolved".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
$ git am --abort

So the patch doesn't apply well out-of-the-box. Using --keep-cr was as expected though:

$ git am --keep-cr 0001-Add-more-foo.patch
Applying: Add more foo.
$

Okay. So let's try this with core.autocrlf=true (in a different repository):

# Removed the initial commands...
$ git format-patch HEAD~1
0001-Add-more-foo.patch
$ git reset --hard HEAD~1
HEAD is now at 525b5aa Initial commit.
$ git am 0001-Add-more-foo.patch
Applying: Add more foo.
$ git config --get core.autocrlf
true

The patch in this case had LF endings everywhere.

Community
  • 1
  • 1
John Szakmeister
  • 38,342
  • 9
  • 78
  • 72
  • This doesn't seem to solve problem with not applicable patches. – fithu Apr 23 '13 at 05:28
  • Did you try? Not only have I run into this issue before, but I reproduced it here. You're comment below about producing patches with LF's I believe is incorrect. The header has LFs, but the actual lines of the diff probably have CRLF endings. `git am` strips away the CR, which is where the problem comes in. Perhaps you actually have *mixed* line endings? – John Szakmeister Apr 23 '13 at 08:26
  • You are trying to tell me that I'm wrong having only _assumptions and beliefs_?? There are no mixed line endings. All line endings in generated patch files are pure LFs, despite repo uses only CRLFs. – fithu Apr 23 '13 at 09:03
  • No, I'm asking if you actually checked the *whole patch* or not. It's easy to mistake it as being LF only if you only look at the first few lines. :-) That's interesting though. Do you have any git attributes set up? And I assume you're running on Windows? – John Szakmeister Apr 23 '13 at 09:21
  • FWIW, I tried a few things to get a LF only patch, but I did run `dos2unix` over it to get an LF-only patch, and can get the same kind of failure. Setting up a .gitattributes helped things though. You can see how to do that [in this SO question and answer](http://stackoverflow.com/q/16082802/683080). – John Szakmeister Apr 23 '13 at 10:05
  • Windows. Using CRLF on *nix doesn't make any sense. No git attributes set, just a blank repo. And it happens _only_ when I create blank repo using core.autocrlf=false. – fithu Apr 23 '13 at 11:10
  • There are all kinds of reasons why you might see CRLF in files under Linux, not the least of which is because you're using a network share accessed by other members of your team who are using Windows. I'm having a difficult time reproducing the bug. I've updated my answer with what I see. Setting `core.autocrlf=false` worked fine, when using `--keep-cr` as I suggested before. What version of msysgit are you using? I did this with 1.8.0. – John Szakmeister May 01 '13 at 10:22
2

Aha! Looks like I've found the reason. The repository uses CRLF line endings, but format-patch creates patch files with LF's. When I create a repo from scratch with autocrlf=false and make the same experiment, I have the same problem. (looks like a bug in Git)
Any advise how to fix this?

UPD my solution was to create a fresh repository with autocrlf=true and re-import all changes from both repositories into it.

fithu
  • 2,101
  • 2
  • 16
  • 22