{"thread":{"id":"14963","subject":"Why doesn't git-apply remove empty file","startedAt":"2008-08-12T16:17:56Z","lastAt":"2008-08-15T15:53:07Z","messageCount":14,"participants":["Francis Moreau","Junio C Hamano","René Scharfe","Linus Torvalds","Stephan Beyer","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"86942","messageId":"38b2ab8a0808120917h10f15c81v4d1f04c0174dc994@mail.gmail.com","threadId":"14963","inReplyTo":null,"subject":"Why doesn't git-apply remove empty file","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2008-08-12T16:17:56Z","receivedAt":"2008-08-12T16:17:56Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hi,\n\nOr at least has an option to do so ?\n\nthanks\n-- \nFrancis\n"},{"id":"86993","messageId":"7vod3xpxq2.fsf@gitster.siamese.dyndns.org","threadId":"14963","inReplyTo":"38b2ab8a0808120917h10f15c81v4d1f04c0174dc994@mail.gmail.com","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-13T00:25:41Z","receivedAt":"2008-08-13T00:25:41Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"If you want to create an empty file, the patch would look like this:\n\n        diff --git a/bar b/bar\n        index 257cc56..e69de29 100644\n        --- a/bar\n        +++ b/bar\n        @@ -1 +0,0 @@\n        -foo\n\nOn the other hand, if you want to remove an empty file, the patch would\nlook like this:\n\n        diff --git a/bar b/bar\n        deleted file mode 100644\n        index 257cc56..0000000\n        --- a/bar\n        +++ /dev/null\n        @@ -1 +0,0 @@\n        -foo\n\nA patch generated by non-git tools would lack \"index\" and \"deleted\" lines,\nbut they will still have difference between \"bar\" and \"/dev/null\" on the\npostimage filename (i.e. \"+++\" line), and git-apply leaves an empty file\nfor the former, and removes the file for the latter patch.\n"},{"id":"87022","messageId":"38b2ab8a0808130048t506dbb7ah1d6fcd6bd4f3c90c@mail.gmail.com","threadId":"14963","inReplyTo":"7vod3xpxq2.fsf@gitster.siamese.dyndns.org","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2008-08-13T07:48:11Z","receivedAt":"2008-08-13T07:48:11Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"Hello,\n\nOn Wed, Aug 13, 2008 at 2:25 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> On the other hand, if you want to remove an empty file, the patch would\n> look like this:\n>\n>        diff --git a/bar b/bar\n>        deleted file mode 100644\n>        index 257cc56..0000000\n>        --- a/bar\n>        +++ /dev/null\n>        @@ -1 +0,0 @@\n>        -foo\n>\n> A patch generated by non-git tools would lack \"index\" and \"deleted\" lines,\n> but they will still have difference between \"bar\" and \"/dev/null\" on the\n> postimage filename (i.e. \"+++\" line), and git-apply leaves an empty file\n> for the former, and removes the file for the latter patch.\n>\n\nHm this is somehow wrong, please see:\n\n    $ mkdir a b\n    $ date > a/f\n    $ diff -Nurp a/f b/f\n    --- a/f 2008-08-13 09:27:29.000000000 +0200\n    +++ b/f 1970-01-01 01:00:00.000000000 +0100\n    @@ -1 +0,0 @@\n    -Wed Aug 13 09:27:29 CEST 2008\n\nSo '/dev/null' doesn't appear here. I think patch(1) uses the date of\nb/f for removing\nthe file.\n\nIf we keep going on:\n\n    $ diff -Nurp a b > test.patch\n    $ ( cd a && git apply ../test.patch )\n    $ ls a\n    f\n    $ cat a/f\n    $\n\nof course patch(1) does remove the file.\n\nThanks\n-- \nFrancis\n"},{"id":"87115","messageId":"48A357BA.8060003@lsrfire.ath.cx","threadId":"14963","inReplyTo":"38b2ab8a0808130048t506dbb7ah1d6fcd6bd4f3c90c@mail.gmail.com","subject":"Re: Why doesn't git-apply remove empty file","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2008-08-13T21:52:58Z","receivedAt":"2008-08-13T21:52:58Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Francis Moreau schrieb:\n>     $ mkdir a b\n>     $ date > a/f\n>     $ diff -Nurp a/f b/f\n>     --- a/f 2008-08-13 09:27:29.000000000 +0200\n>     +++ b/f 1970-01-01 01:00:00.000000000 +0100\n>     @@ -1 +0,0 @@\n>     -Wed Aug 13 09:27:29 CEST 2008\n> \n> So '/dev/null' doesn't appear here. I think patch(1) uses the date of\n> b/f for removing\n> the file.\n> \n> If we keep going on:\n> \n>     $ diff -Nurp a b > test.patch\n>     $ ( cd a && git apply ../test.patch )\n>     $ ls a\n>     f\n>     $ cat a/f\n>     $\n> \n> of course patch(1) does remove the file.\n\nI bet you are using GNU patch.  It removes files that are empty after\npatching and you need to specify --posix to make it keep empty files.\n\nLarry Wall's original version of patch keeps empty files by default and\nyou need to use the option option -E (or --remove-empty-files) to make\nit remove them.\n\nRené\n"},{"id":"87122","messageId":"alpine.LFD.1.10.0808131602200.3462@nehalem.linux-foundation.org","threadId":"14963","inReplyTo":"48A357BA.8060003@lsrfire.ath.cx","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-13T23:09:46Z","receivedAt":"2008-08-13T23:09:46Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 13 Aug 2008, René Scharfe wrote:\n> \n> I bet you are using GNU patch.  It removes files that are empty after\n> patching and you need to specify --posix to make it keep empty files.\n\nGNU patch' behavior wrt empty files is a bit more complex than that. It's \ntrue that you can disable it all with the POSIX mode (not that anybody \never does), but it's not an unconditional removal, I think.\n\nIt does look at the date of the destination if there is one, ie according \nto the man-page:\n\n      \"You can create a file by sending out a diff that compares /dev/null  or\n       an empty file dated the Epoch (1970-01-01 00:00:00 UTC) to the file you\n       want to create.  This only works if the file you want to create doesn’t\n       exist  already  in  the target directory.  Conversely, you can remove a\n       file by sending out a context diff that compares the file to be deleted\n       with  an  empty  file dated the Epoch.  The file will be removed unless\n       patch is conforming to POSIX and the -E or --remove-empty-files  option\n       is  not  given.  An easy way to generate patches that create and remove\n       files is to use GNU diff’s -N or --new-file option.\"\n\nand no, git never did that file date thing, so git acts differently from \nGNU patch in this thing (as in so many others, for that matter).\n\nI don't think it would necessarily be wrong to try to emulate GNU patch \nfor the case where git is guessing at removal, though (ie for the \n\"traditional diff\" case - for a \"git diff\", the removal question is \nunambiguous thanks to the git extensions, of course).\n\nThat said, I'm also not personally very motivated to add yet another odd \nGNU patch behavior quirk. Especially as we very much try to avoid parsing \nthat insane and not-well-specified date format anyway, and just ignore it. \nBut if somebody sends out a tested patch to add such logic, I wouldn't \nthink it _wrong_ either.\n\n\t\t\tLinus\n"},{"id":"87222","messageId":"38b2ab8a0808141242k4bd6867dt8ef54f160713061f@mail.gmail.com","threadId":"14963","inReplyTo":"alpine.LFD.1.10.0808131602200.3462@nehalem.linux-foundation.org","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2008-08-14T19:42:22Z","receivedAt":"2008-08-14T19:42:22Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"On Thu, Aug 14, 2008 at 1:09 AM, Linus Torvalds\n<torvalds@linux-foundation.org> wrote:\n> and no, git never did that file date thing, so git acts differently from\n> GNU patch in this thing (as in so many others, for that matter).\n>\n\nWell patch(1) is so used out there that makes git-apply often do the\nwrong thing for such corner cases when applying a patch made by\npatch(1).\n\nMaybe git-apply would be more friendly regarding patch(1) if it has an\noption to emulate GNU patch for some situations. Or if this means\nadding too many quirks in git-apply code, maybe give the possibity for\ngit-am to use patch(1) instead of git-apply.\n\n-- \nFrancis\n"},{"id":"87224","messageId":"alpine.LFD.1.10.0808141246190.3324@nehalem.linux-foundation.org","threadId":"14963","inReplyTo":"38b2ab8a0808141242k4bd6867dt8ef54f160713061f@mail.gmail.com","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-14T19:57:09Z","receivedAt":"2008-08-14T19:57:09Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 14 Aug 2008, Francis Moreau wrote:\n> \n> Well patch(1) is so used out there that makes git-apply often do the\n> wrong thing for such corner cases when applying a patch made by\n> patch(1).\n> \n> Maybe git-apply would be more friendly regarding patch(1) if it has an\n> option to emulate GNU patch for some situations. Or if this means\n> adding too many quirks in git-apply code, maybe give the possibity for\n> git-am to use patch(1) instead of git-apply.\n\nThe thing is, \"patch\" is a total piece of utterly unbelievable SH*T.\n\ngit-apply acts differently, yes, but it acts differently for a damn good \nreason. No, you cannot replace git-apply with that horrible crap that is \nGNU patch.\n\nSome of the reasons are purely trivial implementation issues:\n\n - git-apply knows about the index, and knows about updating it properly, \n   including tracking new files automatically.\n\nThat's an important thing, but yeah, it's an implementation issue.\n\nThe other things that git-apply do right are much more fundamental:\n\n - git apply doesn't leave half-applied state turds around when a patch \n   fails.\n\n   People who actually use \"patch\" for large projects will know the pain \n   here: if a diff fails in the middle, GNU patch will have applied the \n   previous parts (including to other files), and it's now your problem to \n   fix it up. There's no way to do an all-or-nothing patch, which is often \n   a huge requirement.\n\n - git apply doesn't guess (unless you really tell it to, and even then it \n   will guess a whole lot less than GNU patch). If a \"git apply\" succeeds, \n   it was probably good. If a GNU patch invocation succeeds, it might have \n   been total and utter crap, but hey, it tried to apply that piece of \n   shit very aggressively even when it made no sense and the context \n   didn't actually match even _remotely_.\n\n   Yeah, context diffs can still mis-apply even with git apply, but they \n   do so a hell of a lot less than with GNU patch, and if you want it to \n   just generate a random end result, you at least have to _ask_ for it.\n\nSo no. There's no way in hell that git am should use GNU patch.\n\nBut as mentioned, if somebody wants to parse the dates, we could do that. \n\n\t\t\tLinus\n"},{"id":"87225","messageId":"alpine.LFD.1.10.0808141258180.3324@nehalem.linux-foundation.org","threadId":"14963","inReplyTo":"alpine.LFD.1.10.0808141246190.3324@nehalem.linux-foundation.org","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-14T20:02:40Z","receivedAt":"2008-08-14T20:02:40Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 14 Aug 2008, Linus Torvalds wrote:\n>\n>   There's no way to do an all-or-nothing patch, which is often \n>    a huge requirement.\n\nSide note: there's a way to do a \"nothing or nothing\" thing, and then test \nthe return value of whether the do-nothing was successful or not.\n\nSo a reasonably common operation thing for scripting GNU patch is to \nliterally do\n\n\tpatch --dry-run\n\nfirst to see if the patch will succeed.\n\n..or to play games with backup and reject files after-the-fact, of course.\n\n\t\t\tLinus\n"},{"id":"87226","messageId":"38b2ab8a0808141317i158e13fel102cdb7e880d5d7@mail.gmail.com","threadId":"14963","inReplyTo":"alpine.LFD.1.10.0808141246190.3324@nehalem.linux-foundation.org","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Francis Moreau","fromEmail":"francis.moro@gmail.com","sentAt":"2008-08-14T20:17:54Z","receivedAt":"2008-08-14T20:17:54Z","isPatch":false,"sender":{"key":"francis.moro@gmail.com","avatar":null},"body":"On Thu, Aug 14, 2008 at 9:57 PM, Linus Torvalds\n<torvalds@linux-foundation.org> wrote:\n>\n> The thing is, \"patch\" is a total piece of utterly unbelievable SH*T.\n>\n> git-apply acts differently, yes, but it acts differently for a damn good\n> reason. No, you cannot replace git-apply with that horrible crap that is\n> GNU patch.\n>\n> Some of the reasons are purely trivial implementation issues:\n>\n>  - git-apply knows about the index, and knows about updating it properly,\n>   including tracking new files automatically.\n>\n> That's an important thing, but yeah, it's an implementation issue.\n>\n> The other things that git-apply do right are much more fundamental:\n>\n\nagreed with all of them...\n\n> So no. There's no way in hell that git am should use GNU patch.\n>\n\nJust for clarification, I'm not saying to replace git-apply by patch in git-am !\n\nBut in few situations it might be better to use GNU patch for git-am.\nSo we could have such option:\n\n              $ git am --applier=\"/usr/bin/patch\" ...\n\nthanks\n-- \nFrancis\n"},{"id":"87227","messageId":"20080814202159.GD7138@leksak.fem-net","threadId":"14963","inReplyTo":"alpine.LFD.1.10.0808141258180.3324@nehalem.linux-foundation.org","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-08-14T20:21:59Z","receivedAt":"2008-08-14T20:21:59Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nwhile at the git-apply topic...\n\nLinus Torvalds wrote:\n> On Thu, 14 Aug 2008, Linus Torvalds wrote:\n> >\n> >   There's no way to do an all-or-nothing patch, which is often \n> >    a huge requirement.\n[...]\n> \n> ..or to play games with backup and reject files after-the-fact, of course.\n\nWhat I missed when I first used git-apply (git-am) with some not-so-\nwell-done patches was something like a \"simulated merge\" (of course,\nonly when you ask for it), i.e. something like a user-friendly\n--reject behavior:\nInstead of generating reject files it puts conflict markers into the file.\n(If no context matches at all, then perhaps just insert them at the lines\nthat the hunk header says.)\nAnd then declaring the files as \"unmerged\", so that you can see it in\ngit status.\n\nI've seen two or three people asking on #git for such a feature, so\nit looked like I am not the only one who misses this. But yet I've had\nno time to implement such a thing.  Or is it even there, hidden?\n\nRegards,\n  Stephan\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"87230","messageId":"20080814205447.GC25469@sigill.intra.peff.net","threadId":"14963","inReplyTo":"20080814202159.GD7138@leksak.fem-net","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-08-14T20:54:47Z","receivedAt":"2008-08-14T20:54:47Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 14, 2008 at 10:21:59PM +0200, Stephan Beyer wrote:\n\n> Instead of generating reject files it puts conflict markers into the file.\n> (If no context matches at all, then perhaps just insert them at the lines\n> that the hunk header says.)\n> And then declaring the files as \"unmerged\", so that you can see it in\n> git status.\n\nI use \"git am -3\" for that. Then you get conflict markers, or you can\nuse git-mergetool.\n\n-Peff\n"},{"id":"87233","messageId":"20080814211034.GE7138@leksak.fem-net","threadId":"14963","inReplyTo":"20080814205447.GC25469@sigill.intra.peff.net","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-08-14T21:10:34Z","receivedAt":"2008-08-14T21:10:34Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nJeff King wrote:\n> On Thu, Aug 14, 2008 at 10:21:59PM +0200, Stephan Beyer wrote:\n> \n> > Instead of generating reject files it puts conflict markers into the file.\n> > (If no context matches at all, then perhaps just insert them at the lines\n> > that the hunk header says.)\n> > And then declaring the files as \"unmerged\", so that you can see it in\n> > git status.\n> \n> I use \"git am -3\" for that. Then you get conflict markers, or you can\n> use git-mergetool.\n\ngit am -3 looks for the base blob in the \"index\" line of the patch.\n\nNow imagine you do not have this blob in git, e.g. because you've not\nfetched some large side branch from another repo.\nThen git am -3 won't help, too. (Yes, in this example fetching the\nbranch may help, but there may be other examples.)\n\nRegards,\n  Stephan\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"87288","messageId":"20080815040834.GA3732@sigill.intra.peff.net","threadId":"14963","inReplyTo":"20080814211034.GE7138@leksak.fem-net","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-08-15T04:08:34Z","receivedAt":"2008-08-15T04:08:34Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 14, 2008 at 11:10:34PM +0200, Stephan Beyer wrote:\n\n> git am -3 looks for the base blob in the \"index\" line of the patch.\n> \n> Now imagine you do not have this blob in git, e.g. because you've not\n> fetched some large side branch from another repo.\n\nAh, you're right. That is much trickier (though it can still be used in\nsome cases, depending on how broken the patch is).\n\n> Then git am -3 won't help, too. (Yes, in this example fetching the\n> branch may help, but there may be other examples.)\n\nAn easy example that breaks: the patch submitter didn't use git at all,\nso there is no branch to fetch from. :)\n\n-Peff\n"},{"id":"87322","messageId":"alpine.LFD.1.10.0808150843320.3324@nehalem.linux-foundation.org","threadId":"14963","inReplyTo":"20080814202159.GD7138@leksak.fem-net","subject":"Re: Why doesn't git-apply remove empty file","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-15T15:53:07Z","receivedAt":"2008-08-15T15:53:07Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 14 Aug 2008, Stephan Beyer wrote:\n> \n> What I missed when I first used git-apply (git-am) with some not-so-\n> well-done patches was something like a \"simulated merge\" (of course,\n> only when you ask for it), i.e. something like a user-friendly\n> --reject behavior:\n\nIt's really hard to do. Largely impossible, I think. The reason is that \nwhen a patch fails, you - by definition - don't really know where it is \nsupposed to apply and what the original code is. Because if you did, the \npatch wouldn't fail!\n\nGit *can* do it (git am -3, as people have said), when you have a git \npatch, and the patch indicates the original blob. Then git can just see \nwhat the original state was, reconstruct the patched file, and do a normal \nthree-way merge. But it's not doable in general.\n\nNow, we could do other things, like try to _search_ for an original blob \nthat it applies cleanly to (or even have a \"guessing mode\" that does a \nreally rough patch-application with the GNU patch defaults and then does a \nthree-way merge of a fudged version with no fuzz as the base), so I'm not \nsaying that it would be fundamentally impossible to try to go further than \nwhat we do now, but it's definitely not trivial to do.\n\n> Instead of generating reject files it puts conflict markers into the file.\n> (If no context matches at all, then perhaps just insert them at the lines\n> that the hunk header says.)\n> And then declaring the files as \"unmerged\", so that you can see it in\n> git status.\n\nI do agree that it would be very cool. I'm so used to editing patches to \nmatch the target files by hand that I don't personally mind. I absolutely \ndetest reject files personally because of the way they mean that you have \na half-way done thing, so I will literally always edit the original patch \nin place instead.\n\nBut I agree that what you describe would be absolutely lovely.\n\n\t\t\tLinus\n"}]}