31

Is it possible to know if a file has been patched already, before apply the patch?

I need to do this in a script, any thoughts?

2

5 Answers 5

31

Yep, just run patch with --dry-run option, it either would fail or succeed which can be found out with its exit status.

But in more general (and less error prone) way, you probably have to run it with -R option which means "reverse" since only if it was able to revert the whole patch it could be considered as "applied". Otherwise (without '-R') it could fail just due to some parts of the original file was changed. Below is a simple example:

if ! patch -R -p0 -s -f --dry-run <patchfile; then
  patch -p0 <patchfile
fi

(Evenmore, in the snippet above you might even prefer to silence patch completely redirecting its stdout and stderr to /dev/null)

7
  • 1
    This does not work for me. When I run that command, if the patch has not been applied, it asks whether to 'un-reverse' the patch in interactive mode and, if I use batch mode, it will ignore the reverse operation and apply the patch, returning 0.
    – synack
    Oct 19, 2017 at 20:30
  • 1
    Hey, try adding -sf to patch (can be written as patch -Rsfp0 --dry-run)
    – poige
    Oct 20, 2017 at 5:31
  • 1
    @synack did it go ok?
    – poige
    Oct 26, 2017 at 9:06
  • 3
    BTW, if you're using Git, the same idea works, but using git apply -R --check instead.
    – jtchitty
    May 1, 2020 at 1:58
  • How is --dry-run -R a "more common (and error prone) way"? It succeeds exactly when the patch has been applied. I suggest that you meant that the first option, with no -R, is error prone, and the answer could be rephrased to indicate this. Aug 26, 2020 at 7:37
18

Just in case it helps someone, if you are using bash script then the example given by Omnifarious would not work. In bash the exit status of a successful command is 0

So the following would work:

patch -p0 -N --dry-run --silent < patchfile 2>/dev/null
#If the patch has not been applied then the $? which is the exit status 
#for last command would have a success status code = 0
if [ $? -eq 0 ];
then
    #apply the patch
    patch -p0 -N < patchfile
fi
3
  • The checking should be against 1 instead of 0: if [ $? -eq 1 ]
    – Crisson
    Dec 20, 2015 at 5:46
  • 2
    No, 0 is correct. Patch would exit with non-zero if the dry-run failed for some reason, in which case the patch shouldn't be applied.
    – Fls'Zen
    Aug 10, 2016 at 2:49
  • My script was correct in bash. bash considers an exit code of 0 to be true for the purposes of if. Precisely because most commands use an exit code of 0 to indicate success. Oct 16, 2019 at 2:44
2

Here is a guess, assuming that you are using the patch utility and each file to be patched has its own patch:

if patch <options> -N --dry-run --silent <patchfile 2>/dev/null; then
    echo The file has not had the patch applied,
    echo and the patch will apply cleanly.
else
    echo The file may not have had the patch applied.
    echo Or maybe the patch doesn't apply to the file.
fi
3
  • Or, if you patched the files before and want to know, whether it touched some specific file, you can run the first patch round with the -B option, which would cause backup to be made. Then you check for existence of the backup.
    – peterph
    Nov 15, 2012 at 10:12
  • 8
    Could you expand a bit on why you chose to use nohup in that if case?
    – zrajm
    Apr 17, 2013 at 12:48
  • @zrajm - I can't remember why I did that. And by the time I noticed (because of an edit approval request) that it was there, it was so long ago there's no chance I'll ever recover the reason. It seems quite pointless to me looking at it now. Oct 16, 2019 at 2:41
1

In my case I wanted to make that check so that running the patch command wouldn't end up with an interactive terminal asking what to do (especially for CI).

Turns out that if you only need that you can also use the --forward argument and it'll skip the patch if already applied!

0

This worked to me.

"scripts": {
    "symfony-scripts": [
        "patch -N --silent -p0 < patches/vendor/somefile.js.patch &2>/dev/null",
        "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .