16

(long story ...)

I'm in the midst of bringing a gigantic PHP application up to the present century ... ;-) ... while other teams are continuing to maintain the existing version of it.

This has lead, so far, to about 275 patches. Trouble is, one of the changes that we've made is to convert <? tags to <?php, and several similar changes throughout the code. All of which, of course, prevent applying patches, because (indeed ...) the source-code doesn't match.

So, I thought to write a little script to edit the patch files: to change the tags in the patch.

What I'm getting, though, is corrupt patch.

So, what I'd like to know is: what causes this message? That is to say, what sort of errors is Git looking for, when it comes up with this message? I need to "tweak my tweaker" ... ahem ... so that the edited patches work. (N.B. the original patch-files, before I tweak them, are not "corrupt," so it must be something I'm doing.)

My script is attempting to change the aforesaid PHP tag, and <?php echo, and one function-name. Nothing more than a global preg-replace. I don't readily see what I could be munging that would be of, shall we say, "structural concern" to Git. But, obviously, something is.

Example patch: corrupt patch at line 37 ...

From 342c5939da8cf4cbe495be7d635cd627bd2a44ed Mon Sep 17 00:00:00 2001
From: xxx <xxx@yyy.com>
Date: Wed, 17 Feb 2016 03:45:31 +0000
Subject: [PATCH 001/275] Make it all work 


---
 catalog/includes/modules/shipping/upsFreeGround.php | 2 +-
 catalog/product_info_v3.php                         | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/catalog/includes/modules/shipping/upsFreeGround.php b/catalog/includes/modules/shipping/upsFreeGround.php
index 45a6da4..55ccecb 100755
--- a/catalog/includes/modules/shipping/upsFreeGround.php
+++ b/catalog/includes/modules/shipping/upsFreeGround.php
@@ -194,7 +194,7 @@ function quote($method = '') {

         // Can probably combine this with the above, eventually
         $allFreeBW2016Plaques = false;
-           if (STORES_ID == 10) {
+           if ((STORES_ID == 10) || (STORES_ID == 26)) {
             $allFreeBW2016Plaques = true;
             foreach ($order->products as $aProduct) {
                    $thisNote = $aProduct['product_specific_notes'];
diff --git a/catalog/product_info_v3.php b/catalog/product_info_v3.php
index 09d88de..10d9b76 100644
--- a/catalog/product_info_v3.php
+++ b/catalog/product_info_v3.php
@@ -186,7 +186,7 @@ function doRequestComplete() {
        }
    }
 <?php -if ((STORES_ID == 10) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
+if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
 function doCheckBW2016PlaqueProperty() {
    thePropertyNumber = document.getElementById('propertyToCheck');
    if (thePropertyNumber.value == "") {
@@ -1426,7 +1426,7 @@ if($combo_count>0) { ?>
                        ?>
                        </div> <!-- div_add_to_cart -->
            </div> <!-- cart_info_row2 -->
-           <?php if ((STORES_ID == 10) && (in_array( $products_id, $bwFreePlaqueIDList2016))) {
+           <?php if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array( $products_id, $bwFreePlaqueIDList2016))) {
                // First, let's see if we are "sold out"
                $query = "select bw_plaque_2016_id from bw_plaque_2016 where first_one_free='1' limit 1";
                $bwpRes = tep_db_query( $query);
@@ -1629,7 +1629,7 @@ DIVCONTAINER;
 </table> <!--pageTable for sure -->

 <script type='text/javascript'>
-   <?php if ((STORES_ID == 10) && (in_array( $products_id, $bwFreePlaqueIDList2016))) { ?>
+   <?php if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array( $products_id, $bwFreePlaqueIDList2016))) { ?>
    function doFreePlaquePriceChange() {
        // Change the quantity to 1
        $('quantityToAdd').setValue('1');
-- 
2.6.4 (Apple Git-63)
Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
  • Do the patch files contain sha1 hashes? – melpomene Jun 25 '16 at 15:51
  • I'm not sure what I would be looking for. Can you tell me what such a thing would look like in the patch file? Is it possible to tell apply to ignore any such hashes? (I understand that a patch might contain an anti-corruption check ... but, if it does, I want to ignore it in this case.) – Mike Robinson Jun 25 '16 at 15:59
  • Can you post an example of a corrupt patch? – melpomene Jun 25 '16 at 15:59
  • Patch added to text of post. The command is `git apply --check -v --directory=foobar`. I had hoped that the `-v` option would tell me more about what the corruption was, but it doesn't. – Mike Robinson Jun 25 '16 at 16:28
  • By my counting, line 37 reads: `@@ -1426,7 +1426,7 @@ if($combo_count>0) { ?>` – Mike Robinson Jun 25 '16 at 16:30
  • The line numbers in the patch are wrong. Are you changing the headers, too? – Edward Thomson Jun 25 '16 at 17:22
  • At the risk of sounding stupid ... please explain. The only thing that I am consciously doing is slurping the entire text of the patch-file into memory and applying a few regular-expression replaces to it: `` becomes ` – Mike Robinson Jun 25 '16 at 20:08
  • *("Nev-er-mind ...")* ... see below ... – Mike Robinson Jun 25 '16 at 20:41
  • 1
    In my case, the corrupted patch lacked spaces in otherwise empty context lines (the lines around the actual changes prefixed with `+` and `-` must apparently have a leading space even if they are blank). It also missed a line break at the very end. This whitespace was removed by GitHub (I copied a diff from a comment and pasted it in a text file). – CodeManX Dec 07 '17 at 14:43

4 Answers4

17

tl;dr: I suspect that you have somehow removed a line ending when transforming a line that consists only of <?.

Your script has either removed an important line in the patch, or you have altered the headers. The first hunk of the diff of catalog/product_info_v3.php is malformed.

Its header is:

@@ -186,7 +186,7 @@ function doRequestComplete() {

Which indicates information about the how the hunk corresponds to the preimage (the original file) and the postimage (produced by applying this patch). The preimage information is prefixed by a -, and is -186,7, indicating that this hunk includes 7 lines from the preimage, beginning at line 186. The postimage information is prefixed by a +, and is +186,7, indicating that this hunk will emit 7 lines to the postimage, beginning at line 186.

These 7 lines can either include context (which are lines in common, prefixed with a space), lines that exist only in the preimage (prefixed with a -), or lines that exist only in the postimage (prefixed with a +).

Looking at the hunk at then labeling each line with its type:

  context:         }
  context:     }
  context:  <?php -if ((STORES_ID == 10) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
postimage: +if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
  context:  function doCheckBW2016PlaqueProperty() {
  context:     thePropertyNumber = document.getElementById('propertyToCheck');
  context:     if (thePropertyNumber.value == "") {

The context lines, again, will be in both the preimage and the postimage. So there are 6 lines in total for the preimage, and 7 lines for the postimage.

But your header said that there were 7 lines for the preimage! So either the header is wrong or the instructions are wrong. (And Git is expecting to see another line of preimage at line 37, but instead it's a new header line, so Git has determined that your patch file is corrupt.)

The lines in this patch suggest that you are adding the if line to the postimage, which did not exist in the preimage. If this is correct, then you have broken your header, and it should be -186,6 +186,7 indicating that there is a line being added to the postimage.

Alternately, if you were changing the if line, then you have omitted its preimage state, and you should have a line above the postimage line.

Looking carefully, it looks like you've actually missed a newline after the <?php in the line above. Your context was probably not <?php -if ... since I suspect that is not valid PHP, with a hyphen in front of the if.

I suspect that this hunk should look like:

@@ -186,7 +186,7 @@ function doRequestComplete() {
       }
   }
 <?php
-if ((STORES_ID == 10) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
+if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
 function doCheckBW2016PlaqueProperty() {
    thePropertyNumber = document.getElementById('propertyToCheck');
    if (thePropertyNumber.value == "") {

Which is not corrupt, and now there are 7 lines of preimage (the six context lines, plus the line that only exists in the preimage that are prefixed with the -) and 7 lines of postimage (the six context lines, plus the line that only exists in the postimage that are prefixed with the +.)

So now we have a legal patch, as the instructions match the header.

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • 1
    Drat ... the "up-vote" button only works ONCE. **:-D** *"Priceless!"* Now, let me spend the next half-hour absorbing what you've just said here. ### *"Ahh, I see something ..."* – Mike Robinson Jun 25 '16 at 20:14
11

I had this error when I tried to paste (Ctrl+C -> Ctrl+V) a patch:

$ git patch
[Ctrl+Shift+V to paste in terminal]
[Ctrl+D to end input]

It would tell me the patch was corrupt on the last line.

The solution was to add an Enter before using Ctrl+D to end input. It was missing the final, blank line.

Luc
  • 5,339
  • 2
  • 48
  • 48
  • This fixed my issue. When copying from the terminal after running `git diff`, really get that last linefeed right before the first letter of the prompt when making your selection. – Jesse Hogan Aug 27 '20 at 16:40
  • 1
    Similar to this answer, when copying a chunk from `git diff` output in the terminal in order to use (on a mac) `pbpaste | git apply -`, it would only work if I was careful that the selection **included the last newline** of the patch context (mouse to the left of the _next_ @@ line). If I only selected to the end of the last line without its newline, I got the corrupt patch message. – Joshua Goldberg Dec 22 '21 at 23:10
  • I also wanted to note that options to git apply that appeared promising in the documentation to relax its requirements on the exact linecount of the patch context did not help. It still needed to include the whole context exactly, including the final newline. (I tried --ignore-eof, -C1, --reject, and --recount) – Joshua Goldberg Dec 22 '21 at 23:27
1

Pursuing Edward's superlative answer to this question, I took a closer look at the "before" and "after" patch files.   Well, I’m not yet sure how my regular-expression did this, but here, apparently, is what it did:

The original patch-file:

<?
-if ((STORES_ID == 10) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
+if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>

... and the one after my regex got through with it:

 <?php -if ((STORES_ID == 10) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
+if (((STORES_ID == 10) || (STORES_ID == 26)) && (in_array($products_id, $bwFreePlaqueIDList2016))) { ?>
 function doCheckBW2016PlaqueProperty() {

What's the problem? The "newline" is gone.

Feeling both puzzled and a little bit foolish now, I looked at my (PHP) code:

$content = preg_replace('/\<\?\s*(?=[^xp=])/', '<?php ', $content);

and-d-d-d..., "there it is." :-/

The intent of this obviously-in-error (somehow...?) regular expression is to use a "zero-length positive look-ahead assertion" (?= to find <? tags that are not already <?php or <?xml.

(Whack!) "D'oh!"

I'm using a positive look-ahead assertion to apply a test for "not in the following list of characters. In this case, I should be using a negative look-ahead: (?![px=]) Pretty sure that'll keep the newline from being consumed. (I'm not reading the file a line at a time. I'm just slurping in the whole thing.)

Edit #2: ... And, in so many milliseconds, the right answer appears in comment #1: The \s* is consuming the newline, and negative-lookahead (which doesn't seem to be working at all) is unnecessary. (In fact, \s* shouldn't be there at all!) Using positive lookahead once again, and removing the \s*, and replacing with just <?php instead of the same thing followed by a space ... the script works:

$content = preg_replace('/\<\?(?=[^xp=])/', '<?php', $content);

Most-sincere and effusive thanks to all of you who helped me figure this one out. (And especially to Edward, who just explained to all of us in so much detail how those patch-files actually are formatted!)

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
  • 2
    The problem is your `\s*` matching the `\n`. The positive lookahead is fine. Either don't match the newline or use `(\s*)` and embed the match in the replacement. – maaartinus Jun 25 '16 at 20:40
0

Here is how I came to this issue.

  1. I do sommit modify on some files, then I found I should undo the modification on one file.
  2. I try to checkout the file, but I forgot to specific the file, which I used is git checkout .
  3. Before checkout I do git diff to see the modification, So I copy the diff output from the console and create the patch file.
  4. Then I git apply the patch file, I got this issue.

How to fix it. check the patch file format from dos to unix. (By vim, set ff=unix)

LF00
  • 27,015
  • 29
  • 156
  • 295