{"thread":{"id":"2015","subject":"[PATCH] Fall back to three-way merge when applying a patch.","startedAt":"2005-10-05T00:46:05Z","lastAt":"2005-10-07T05:16:14Z","messageCount":17,"participants":["Junio C Hamano","Linus Torvalds","Eric W. Biederman"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"9687","messageId":"7vd5mk7pv6.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":null,"subject":"[PATCH] Fall back to three-way merge when applying a patch.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-05T00:46:05Z","receivedAt":"2005-10-05T00:46:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"After git-apply fails, attempt to find a base tree that the patch\ncleanly applies to, and do a three-way merge using that base tree into\nthe current index.\n\nWhen the fall-back merge fails, the working tree can be resolved the\nsame way as you would normally hand resolve a conflicting merge.\nWhen making commit, use .dotest/final-commit as the log message\ntemplate.  Or you could just choose to 'git-checkout-index -f -a'\nto revert the failed merge.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * I will be placing this in the proposed updates branch.\n   Hopefully this would alleviate the complaints from people who\n   find the \"no fuzz\" policy of git-apply is too strict.\n\n   The change is helped if the patch sender uses the updated\n   git-format-patch that records which tree the patch is\n   supposed to cleanly apply to, but that is not strictly\n   necessary; it tries to find a tree that patch applies to from\n   the recent commits itself.\n\n git-applypatch.sh |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 61 insertions(+), 1 deletions(-)\n\napplies-to: 9eec9ff9326032bca405a12a265918725edf4ac7\nfb533c6562481dfbc4719f740aa0d85e2a45700c\ndiff --git a/git-applypatch.sh b/git-applypatch.sh\n--- a/git-applypatch.sh\n+++ b/git-applypatch.sh\n@@ -105,7 +105,67 @@ git-apply --index \"$PATCHFILE\" || {\n \t# Here if we know which revision the patch applies to,\n \t# we create a temporary working tree and index, apply the\n \t# patch, and attempt 3-way merge with the resulting tree.\n-\texit 1\n+\n+\tO_OBJECT=`cd \"$GIT_OBJECT_DIRECTORY\" && pwd`\n+\trm -fr .patch-merge-*\n+\n+\t(\n+\t\tN=10\n+\n+\t\t# if the patch records the base tree...\n+\t\tsed -ne '\n+\t\t\t/^diff /q\n+\t\t\t/^applies-to: \\([0-9a-f]*\\)$/{\n+\t\t\t\ts//\\1/p\n+\t\t\t\tq\n+\t\t\t}\n+\t\t' \"$PATCHFILE\"\n+\n+\t\t# or hoping the patch is against our recent commits...\n+\t\tgit-rev-list --max-count=$N HEAD\n+\n+\t\t# or hoping the patch is against known tags...\n+\t\tgit-ls-remote --tags .\n+\t) |\n+\twhile read base junk\n+\tdo\n+\t\t# Try it if we have it as a tree.\n+\t\tgit-cat-file tree \"$base\" >/dev/null 2>&1 || continue\n+\n+\t\trm -fr .patch-merge-tmp-* &&\n+\t\tmkdir .patch-merge-tmp-dir || break\n+\t\t(\n+\t\t\tcd .patch-merge-tmp-dir &&\n+\t\t\tGIT_INDEX_FILE=../.patch-merge-tmp-index &&\n+\t\t\tGIT_OBJECT_DIRECTORY=\"$O_OBJECT\" &&\n+\t\t\texport GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&\n+\t\t\tgit-read-tree \"$base\" &&\n+\t\t\tgit-apply --index &&\n+\t\t\tmv ../.patch-merge-tmp-index ../.patch-merge-index &&\n+\t\t\techo \"$base\" >../.patch-merge-base\n+\t\t) <\"$PATCHFILE\"  2>/dev/null && break\n+\tdone\n+\n+\ttest -f .patch-merge-index &&\n+\this_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&\n+\torig_tree=$(cat .patch-merge-base) &&\n+\trm -fr .patch-merge-* || exit 1\n+\n+\techo Falling back to patching base and 3-way merge using $orig_tree...\n+\n+\t# This is not so wrong.  Depending on which base we picked,\n+\t# orig_tree may be wildly different from ours, but his_tree\n+\t# has the same set of wildly different changes in parts the\n+\t# patch did not touch, so resolve ends up cancelling them,\n+\t# saying that we reverted all those changes.\n+\n+\tif git-merge-resolve $orig_tree -- HEAD $his_tree\n+\tthen\n+\t\techo Done.\n+\telse\n+\t\techo Failed to merge in the changes.\n+\t\texit 1\n+\tfi\n }\n \n if test -x \"$GIT_DIR\"/hooks/pre-applypatch\n---\n0.99.8.GIT\n"},{"id":"9692","messageId":"Pine.LNX.4.64.0510042155090.31407@g5.osdl.org","threadId":"2015","inReplyTo":"7vd5mk7pv6.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-05T04:56:58Z","receivedAt":"2005-10-05T04:56:58Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 4 Oct 2005, Junio C Hamano wrote:\n> \n>  * I will be placing this in the proposed updates branch.\n>    Hopefully this would alleviate the complaints from people who\n>    find the \"no fuzz\" policy of git-apply is too strict.\n\nThis should definitely be enabled by a switch only. \n\nFor example, I use git-applypatch _only_ through git-applymbox. Ie \nnon-interactively. I definitely do _not_ want it to try random other trees \nunless I tell it to, especially when applying a series of 175 patches in \none go.\n\n\t\tLinus\n"},{"id":"9695","messageId":"7vslvg1mcs.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510042155090.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-05T06:58:27Z","receivedAt":"2005-10-05T06:58:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> For example, I use git-applypatch _only_ through git-applymbox. Ie \n> non-interactively. I definitely do _not_ want it to try random other trees \n> unless I tell it to, especially when applying a series of 175 patches in \n> one go.\n\nMy understanding of your workflow, from reading your earlier\nposts to the git list, is:\n\n * Read bunch of mails -- mostly concentrating on the\n   description in the log message and skimming the code -- while\n   saving the worthy patches into a 'to-apply' mbox.\n\n * Review 'to-aplly' mbox again, perhaps excluding not-so-good\n   ones.  When you need to fix log messages, that is done in\n   this step.\n\n * Run git-applymbox on the surviving messages in a batch mode,\n   processing 175 patches in one go.\n\nWhat is your workflow after seeing that the 47th patch among 175\npatches fails to apply?  I understand you run git-applymbox\nwithout -q, so it immediately fails and exits there.  You would\nhave split mails, numbered from 0001 to 0175 in the .dotest\ndirectory, with msg, patch and info files from the mail 0047\nleft behind.\n\nI presume that, if the conflict/fuzz is manageably small, you\nwould hand edit the file 0047 to make the diff part to apply\ncleanly, and then run 'git-applymbox -c .dotest/0047'.  I\nwould understand you would be able to resume and process the\nrest 128 patches this way.\n\nOnce you mentioned that if the conflict is too great you would\napply the patch to an old version that the patch sender based\nher work on, and merge using git (this was the direct\ninspiration of the change to git-applypatch).\n\nWhat I am wondering is how that step fits in your workflow.  Do\nyou do this by the following sequence?\n\n * Temporarily switch to a new throwaway branch for merge from\n   the known old version with 'git checkout -b test v2.6.12';\n\n * 'git apply --index <.dotest/patch' to apply the patch, and\n   perhaps 'git commit -F .dotest/msg';\n\n * Switch back to the master branch with 'git checkout master';\n\n * Merge them with 'git resolve master test <some message>',\n   which may leave conflicts, in which case you would hand\n   resolve, and say 'git commit -F .dotest/msg'.  Then 'git\n   branch -d test' to get rid of the throwaway branch.\n\n * Resume the patch application with 'git-applymbox -c\n   .dotest/0048'.\n\nWell, I just noticed that it is not even immediately obvious\nthat the 47th of the 175 patches failed to apply from the\ngit-applymbox batch output (it shows how I do not process really\nmany patches myself X-<).  Is there anything I can do to improve\nthis?  For example, after git-applypatch exits with 0 exit\nstatus we could remove the split mail file, like this:\n\n------------\ndiff --git a/git-applymbox.sh b/git-applymbox.sh\n--- a/git-applymbox.sh\n+++ b/git-applymbox.sh\n@@ -82,7 +82,11 @@ do\n     do\n \tgit-applypatch .dotest/msg-clean .dotest/patch .dotest/info \"$signoff\"\n \tcase \"$?\" in\n-\t0 | 2 )\n+\t0)\n+\t\t# Remove the cleanly applied one to reduce clutter.\n+\t\trm -f .dotest/$i\n+\t\t;;\n+\t2)\n \t\t# 2 is a special exit code from applypatch to indicate that\n \t    \t# the patch wasn't applied, but continue anyway \n \t\t;;\n------------\n\nOr it may not matter at all if your \"after failure\" workflow is\nvery different from what I've been imagining.  This is the\nprimarily reason why I would like to understand your workflow\nbetter.\n"},{"id":"9702","messageId":"Pine.LNX.4.64.0510050725510.31407@g5.osdl.org","threadId":"2015","inReplyTo":"7vslvg1mcs.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-05T14:30:17Z","receivedAt":"2005-10-05T14:30:17Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 4 Oct 2005, Junio C Hamano wrote:\n\n> What is your workflow after seeing that the 47th patch among 175\n> patches fails to apply?  I understand you run git-applymbox\n> without -q, so it immediately fails and exits there.\n\nCorrect. \n\nWhat I usually do is to just ignore the split patches, and go back to the \nmbox. Delete the ones that applied, and look at the one that didn't. Then \nI try to apply that one manually - sometimes I actually do a quick manual \nbranch to a known version, apply and merge - and I think I might try to \nuse the \"base wiggle\" patch for that. Although I would actually prefer to \nbe able to try against a specific named release (not \"all named tags\" \nfirst).\n\nQuite often, the reason it doesn't apply is that I already have that patch \nthrough a git merge (or because I applied that patch earlier through \nanother person), in which case I don't even try to merge it, I just delete \nthat email too, and just do \"git-applymbox\" again.\n\n\t\tLinus\n"},{"id":"9744","messageId":"7vslvfcy0g.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510050725510.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-06T00:03:27Z","receivedAt":"2005-10-06T00:03:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> ... Although I would actually prefer to be able to try against\n> a specific named release (not \"all named tags\" first).\n\nThat makes sense, given that you know better than the tool can\npossibly guess, especially from the performance point of view.\n\nWhat's interesting is that from the correctness point of view,\nit should not make that much of a difference which base tree\nhappens to be picked -- if the base tree is wildly different\nfrom your current HEAD, most of that wild difference will be\ncarried over intact to the result of patch application for paths\nand parts of the files the patch does not touch.  Three-way\nmerge notices that and your \"changes\" from the base tree win.\n\n> Quite often, the reason it doesn't apply is that I already have that patch \n> through a git merge (or because I applied that patch earlier through \n> another person), in which case I don't even try to merge it, I just delete \n> that email too, and just do \"git-applymbox\" again.\n\nThanks.  So in short, you do not even need '-c' option, but just\ntrim the mbox you feed to applymbox and re-run it.\n\nWhile I was experimenting with the git-am (only in 'pu' branch,\nand still marked as \"do not use\"), I noticed that it does the\nright thing on an already applied patch.  It fails to apply,\nfinds an appropriate base and then notices the result of the\npatch application is already contained in the HEAD ;-).\n"},{"id":"9748","messageId":"m1mzln9zi1.fsf@ebiederm.dsl.xmission.com","threadId":"2015","inReplyTo":"7vslvfcy0g.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2005-10-06T01:59:34Z","receivedAt":"2005-10-06T01:59:34Z","isPatch":true,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>> ... Although I would actually prefer to be able to try against\n>> a specific named release (not \"all named tags\" first).\n>\n> That makes sense, given that you know better than the tool can\n> possibly guess, especially from the performance point of view.\n>\n> What's interesting is that from the correctness point of view,\n> it should not make that much of a difference which base tree\n> happens to be picked -- if the base tree is wildly different\n> from your current HEAD, most of that wild difference will be\n> carried over intact to the result of patch application for paths\n> and parts of the files the patch does not touch.  Three-way\n> merge notices that and your \"changes\" from the base tree win.\n\nThere is another workable strategy.  Modify git-diff-xxx to report\nthe sha1 of the tree, or the sha1's of the files the patch applies to.\nAnd make that information available to git-apply.  I don't how often\nit would help but it has the possibility of letting the tools know\nexactly what the patch applied against.\n\nA rational for why this would work is that is that a kernel repository\nis large,  and unless objects/alternatives can be made to work across\nservers there will be people who can use git for development but can't\nhost a repository that can be pulled from.   Especially for a small\npatch.\n\nUsing sha1's for context before merging should be able to give you a\nwhole lot more machine verifiable context with just a little bit of work. \n\nEric\n"},{"id":"9750","messageId":"Pine.LNX.4.64.0510051909390.31407@g5.osdl.org","threadId":"2015","inReplyTo":"m1mzln9zi1.fsf@ebiederm.dsl.xmission.com","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-06T02:18:41Z","receivedAt":"2005-10-06T02:18:41Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 5 Oct 2005, Eric W. Biederman wrote:\n>\n> There is another workable strategy.  Modify git-diff-xxx to report\n> the sha1 of the tree, or the sha1's of the files the patch applies to.\n\nNot workable.\n\nIt fundamentally only works for the first patch in a series. After that, \nthe rest will be based off a version that the recipient simply doesn't \nhave (well, if it's the _tree_ SHA1, and the recipient has no other \npatches, then they'll match, but that case is uninteresting, since it's \nthe trivial case that you always get right by just applying the things in \nthe first place).\n\nSo you'd have to make it the base for the patch _series_, at a minimum.\n\nAnd even that likely doesn't work very often. Any time you have a private \nmerge or some other patch in your tree, the recipient wouldn't be able to \nparse it.\n\nIn practice, I've found that most often it's very trivially obvious _why_ \na patch doesn't apply (I remember the \"other patch\" that happened to the \nsame file, or I just do a \"git-whatchanged -p filename\"), and it can be \nuseful to allow the person applying the patch to say \"ok, try to apply it \nagainst version xyz, and do a three-way merge\".\n\nBut it really tends to be fairly rare.\n\nNow obviously, some of that may be kernel-specific - a large part of the \nlack of patch conflicts is that we over the years have actively tried to \nset up the kernel sources so that people seldom step on each other (one \nexample is how we have all modules contain their own \"init_module()\" thing \nand sortign it out in the linker - because the old init/main.c approach \nwas _very_ painful since everybody wanted to add lines to the same file).\n\nSo it may turn out that other projects might have different wishes for how \nsomething like this would work. But I doubt it works very well to rely on \ncommit-level SHA1's - it's more likely to work if you try the \"last few \ntagged releases etc\", since patches that don't apply are often against the \nprevious release (and if they don't apply there either, then it's probably \nnot worth fighting over anyway).\n\n\t\tLinus\n"},{"id":"9752","messageId":"7v1x2zb7pa.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510051909390.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-06T04:17:05Z","receivedAt":"2005-10-06T04:17:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> ... But I doubt it works very well to rely on \n> commit-level SHA1's - it's more likely to work if you try the \"last few \n> tagged releases etc\", since patches that don't apply are often against the \n> previous release (and if they don't apply there either, then it's probably \n> not worth fighting over anyway).\n\nThat is the heuristics git-applypatch in the proposed updates\nbranch tries to attempt.  Recorded tree if exists (which is not\nvery interesting), last few commits from the current branch, and\nthen tagged releases.\n\nIdeally, if we had the path following git-rev-list you talked\nabout, we could first ask git-apply the set of paths the patch\ntouches, and instead of trying every commits from the HEAD, try\nonly commits that touch one (or more) of the given paths.\n\nAnother possible git-rev-list enhancement that might be useful\nis to pop commits not based on time but based on the depth from\nbranch heads.  Then we could:\n\n    git-rev-list --depth-order --max-count=$N --all \\\n    \t$(git-apply --show-files $patch | sed -e 's/^[^ ]* [^ ]* //p')\n\nto obtain list of the last few commits that touch the paths\ninvolved, in the order that is closer-to-tip first.\n"},{"id":"9755","messageId":"m1y8575i9y.fsf@ebiederm.dsl.xmission.com","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510051909390.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2005-10-06T05:25:13Z","receivedAt":"2005-10-06T05:25:13Z","isPatch":true,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Wed, 5 Oct 2005, Eric W. Biederman wrote:\n>>\n>> There is another workable strategy.  Modify git-diff-xxx to report\n>> the sha1 of the tree, or the sha1's of the files the patch applies to.\n>\n> Not workable.\n>\n> It fundamentally only works for the first patch in a series. After that, \n> the rest will be based off a version that the recipient simply doesn't \n> have (well, if it's the _tree_ SHA1, and the recipient has no other \n> patches, then they'll match, but that case is uninteresting, since it's \n> the trivial case that you always get right by just applying the things in \n> the first place).\n\nBut what about the file sha1?  The intuition is that you can\neasily provide a lot more context in diffs and that the extra\ncontext might be useful in merging patches.  The part that gives\nme how is when I look at if from a diff/patch perspective and\nnot from a git perspective.\n\n> So you'd have to make it the base for the patch _series_, at a minimum.\n>\n> And even that likely doesn't work very often. Any time you have a private \n> merge or some other patch in your tree, the recipient wouldn't be able to \n> parse it.\n\nTrue although in many cases people rework their diffs before sending\nthem out to avoid situations like the above.\n\n> In practice, I've found that most often it's very trivially obvious _why_ \n> a patch doesn't apply (I remember the \"other patch\" that happened to the \n> same file, or I just do a \"git-whatchanged -p filename\"), and it can be \n> useful to allow the person applying the patch to say \"ok, try to apply it \n> against version xyz, and do a three-way merge\".\n\nAh.  I had missed that git-whatchanged can be given a filename that is\nnice.  One of the better kept secrets of git.  That makes my whole\nquestion worthwhile :)\n\n> But it really tends to be fairly rare.\n\nI don't know how rare it is.  I have had a couple of patches in the last\nweek that I could successfully auto-merge between branches but the\ndiffs themselves would actually conflict.\n\n> Now obviously, some of that may be kernel-specific - a large part of the \n> lack of patch conflicts is that we over the years have actively tried to \n> set up the kernel sources so that people seldom step on each other (one \n> example is how we have all modules contain their own \"init_module()\" thing \n> and sortign it out in the linker - because the old init/main.c approach \n> was _very_ painful since everybody wanted to add lines to the same file).\n>\n> So it may turn out that other projects might have different wishes for how \n> something like this would work. But I doubt it works very well to rely on \n> commit-level SHA1's - it's more likely to work if you try the \"last few \n> tagged releases etc\", since patches that don't apply are often against the \n> previous release (and if they don't apply there either, then it's probably \n> not worth fighting over anyway).\n\nAgreed, commit level sha1 are not very interesting.\n\nBut if you happen to have at least the file level sha1 you can\nactually know if the patch was against what you think it is against.\n\nAt one level you could make conflicts more common by dropping any patch\nwhose source file had the wrong sha1.  At another level you could\ntest for the sha1 of the source file in the repository and know quickly\nif there is something the patch applies cleanly too.\n\nWalking through the list of commits and finding enough information to\nmerge the patch might still be prohibitive, but at least it is something\nthat could be automated, and the test to see if it interesting is\ncheap.\n\nEric\n"},{"id":"9757","messageId":"7vmzln9k0r.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510051909390.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-06T07:33:56Z","receivedAt":"2005-10-06T07:33:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> ... But I doubt it works very well to rely on \n> commit-level SHA1's - it's more likely to work if you try the \"last few \n> tagged releases etc\", since patches that don't apply are often against the \n> previous release (and if they don't apply there either, then it's probably \n> not worth fighting over anyway).\n\nYes.  That is the current heuristics git-applypatch in the\nproposed updates branch tries to attempt.  Recorded tree if\nexists (which is not very interesting), last few commits, and\nthen tagged releases.\n\nIdeally, if we had the path following git-rev-list you talked\nabout, we could first ask git-apply the set of paths the patch\ntouches, and instead of trying every commits from the HEAD, try\nonly commits that touch one (or more) of the given paths.\n\nAnother possible git-rev-list enhancement that might be useful\nis to pop commits not based on time but based on the depth from\nbranch heads.  Then we could:\n\n    git-rev-list --depth-order --max-count=$N --all \\\n    \t$(git-apply --show-files $patch | sed -e 's/^[^ ]* [^ ]* //p')\n\nto obtain list of last few commits that touch the paths\ninvolved, in the order that is closer-to-tip first.  This would\ngive us set of more useful commits than the current behaviour.\n"},{"id":"9764","messageId":"Pine.LNX.4.64.0510060731560.31407@g5.osdl.org","threadId":"2015","inReplyTo":"m1y8575i9y.fsf@ebiederm.dsl.xmission.com","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-06T14:35:58Z","receivedAt":"2005-10-06T14:35:58Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 5 Oct 2005, Eric W. Biederman wrote:\n>\n> Ah.  I had missed that git-whatchanged can be given a filename that is\n> nice.  One of the better kept secrets of git.  That makes my whole\n> question worthwhile :)\n\nThat's definitely not a secret - it was part of the whole point of \ngit-whatchanged. It's the native git version of \"annotate\", and I \npersonally find it much more useful.\n\nIt's not even just a filename. You can do\n\n\tgit-whatchanged -p drivers/scsi/ include/scsi\n\nto limit the set to those two subdirectories. IOW, you can give \ngit-whatchanged an arbitrary list of individual pathnames or directory \nnames.\n\n> But if you happen to have at least the file level sha1 you can\n> actually know if the patch was against what you think it is against.\n\nYes, a file-level SHA1 may be useful. On the other hand, I suspect that by \nthat time (since you have to search for the version anyway) you might as \nwell have the \"just try to apply the patch\" approach. It's basically the \nsame search space.\n\n\t\tLinus\n"},{"id":"9765","messageId":"m1wtkqk89a.fsf@ebiederm.dsl.xmission.com","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510060731560.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2005-10-06T14:52:33Z","receivedAt":"2005-10-06T14:52:33Z","isPatch":true,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Wed, 5 Oct 2005, Eric W. Biederman wrote:\n>>\n>> Ah.  I had missed that git-whatchanged can be given a filename that is\n>> nice.  One of the better kept secrets of git.  That makes my whole\n>> question worthwhile :)\n>\n> That's definitely not a secret - it was part of the whole point of \n> git-whatchanged. It's the native git version of \"annotate\", and I \n> personally find it much more useful.\n>\n> It's not even just a filename. You can do\n>\n> \tgit-whatchanged -p drivers/scsi/ include/scsi\n>\n> to limit the set to those two subdirectories. IOW, you can give \n> git-whatchanged an arbitrary list of individual pathnames or directory \n> names.\n\nWhich probably means it's time for me to generate a patch to the\ngit-whatchanged documentation.\n\n>> But if you happen to have at least the file level sha1 you can\n>> actually know if the patch was against what you think it is against.\n>\n> Yes, a file-level SHA1 may be useful. On the other hand, I suspect that by \n> that time (since you have to search for the version anyway) you might as \n> well have the \"just try to apply the patch\" approach. It's basically the \n> same search space.\n\nMaybe.\n\nAfter thinking about it I don't think you need to look through the\nhistory to use it for a merge3 operation.   As I recall merge3 only\nlooks at the base and the two derived versions of the file.  If we\nhave the sha1 of the original in the git repository I think all we\nneed to compute is the diff between that sha1 the current version\nfile.  And then apply the merge3 algorithm to combine the two sets of\nchanges.\n\n\nEric\n"},{"id":"9766","messageId":"Pine.LNX.4.64.0510060756060.31407@g5.osdl.org","threadId":"2015","inReplyTo":"m1wtkqk89a.fsf@ebiederm.dsl.xmission.com","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-06T14:59:36Z","receivedAt":"2005-10-06T14:59:36Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 6 Oct 2005, Eric W. Biederman wrote:\n> \n> After thinking about it I don't think you need to look through the\n> history to use it for a merge3 operation.   As I recall merge3 only\n> looks at the base and the two derived versions of the file.  If we\n> have the sha1 of the original in the git repository I think all we\n> need to compute is the diff between that sha1 the current version\n> file.  And then apply the merge3 algorithm to combine the two sets of\n> changes.\n\nAhh, that I can definitely agree with. In fact, it makes perfect sense.\n\nHowever, it assumes that everybody is a git user, which isn't actually \ntrue. Also, I'm wondering whether the advantages outweigh the \ndisadvantages: it would make the diff uglier. We'd have to add that SHA1 \nthere somewhere (either on the \"diff\" line itself, or as anothe rextended \ngit line like the \"rename from/to\" lines - a \"original <sha1>\" line).\n\n\t\tLinus\n"},{"id":"9768","messageId":"m1slvek20w.fsf@ebiederm.dsl.xmission.com","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510060756060.31407@g5.osdl.org","subject":"Re: [PATCH] Fall back to three-way merge when applying a patch.","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2005-10-06T17:07:11Z","receivedAt":"2005-10-06T17:07:11Z","isPatch":true,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Thu, 6 Oct 2005, Eric W. Biederman wrote:\n>> \n>> After thinking about it I don't think you need to look through the\n>> history to use it for a merge3 operation.   As I recall merge3 only\n>> looks at the base and the two derived versions of the file.  If we\n>> have the sha1 of the original in the git repository I think all we\n>> need to compute is the diff between that sha1 the current version\n>> file.  And then apply the merge3 algorithm to combine the two sets of\n>> changes.\n>\n> Ahh, that I can definitely agree with. In fact, it makes perfect sense.\n>\n> However, it assumes that everybody is a git user, which isn't actually \n> true. \n\nAgreed.  The question is the subset of everyone large enough to\nmake it a useful technique.  Given that a standalone diff utility can\nbe taught how to generate the extra information, and a standalone\npatch could use it to verify you are at least patching the version\nof the file the patch was intended for I suspect the subset of\neveryone is large enough to be interesting.\n\n> Also, I'm wondering whether the advantages outweigh the \n> disadvantages: it would make the diff uglier. We'd have to add that SHA1 \n> there somewhere (either on the \"diff\" line itself, or as anothe rextended \n> git line like the \"rename from/to\" lines - a \"original <sha1>\" line).\n\nI don't think an extra line in the header is going to be much of a problem.\nJust more header noise.  \n\nEric\n"},{"id":"9787","messageId":"7vachm5a4w.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510060756060.31407@g5.osdl.org","subject":"[PATCH] Show original and resulting blob object info in diff output.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-07T02:33:19Z","receivedAt":"2005-10-07T02:33:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This adds more cruft to diff --git header to record the blob SHA1 and\nthe mode the patch/diff is intended to be applied against, to help the\nreceiving end fall back on a three-way merge.  The new header looks\nlike this:\n\n    diff --git a/apply.c b/apply.c\n    old index 7be50413538868412a87c847f8fa184cadd0fa2a 100644\n    new index 83660822fcbb9edac523634999e30d65c2790cae 100644\n    --- a/apply.c\n    +++ b/apply.c\n    @@ -14,6 +14,7 @@\n     //    files that are being modified, but doesn't apply the patch\n     //  --stat does just a diffstat, and doesn't actually apply\n    +//  --show-index-info shows the old and new index info for...\n    ...\n\nThere is a counterpart option --show-index-info to git-apply command\nto summarize this:\n\n    - 7be5041... 100644\tapply.c\n    + 8366082... 100644\tapply.c\n    - ec2a161... 100644\tcache.h\n    + 514adb8... 100644\tcache.h\n    - ...\n\nUpon receiving such a patch, if the patch did not apply cleanly to the\ntarget tree, the recipient can try to find the matching old objects in\nher object database and create a temporary tree, apply the patch to\nthat temporary tree, and attempt a 3-way merge between the patched\ntemporary tree and the target tree using the original temporary tree\nas the common ancestor.\n\nThe patch lifts the code to compute the hash for an on-filesystem\nobject from update-index.c and makes it available to the diff output\nroutine.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n    Linus Torvalds <torvalds@osdl.org> writes:\n\n    > On Thu, 6 Oct 2005, Eric W. Biederman wrote:\n    >> \n    >> After thinking about it I don't think you need to look through the\n    >> history to use it for a merge3 operation.   As I recall merge3 only\n    >> looks at the base and the two derived versions of the file.  If we\n    >> have the sha1 of the original in the git repository I think all we\n    >> need to compute is the diff between that sha1 the current version\n    >> file.  And then apply the merge3 algorithm to combine the two sets of\n    >> changes.\n    >\n    > Ahh, that I can definitely agree with. In fact, it makes perfect sense.\n\n    And this is a sample implementation to do so.  Will not\n    graduate \"pu\" until the receiving end gets ready and unless\n    people agree that the additional cruft is not too\n    distracting.\n\n apply.c                        |   64 +++++++++++++++++++++++++++++++++-\n cache.h                        |    1 +\n diff.c                         |   76 +++++++++++++++++++++++++++++-----------\n sha1_file.c                    |   39 +++++++++++++++++++++\n t/diff-lib.sh                  |   10 ++++-\n t/t4000-diff-format.sh         |    6 +++\n t/t4001-diff-rename.sh         |    3 +-\n t/t4004-diff-rename-symlink.sh |    3 +-\n update-index.c                 |   33 ++---------------\n 9 files changed, 179 insertions(+), 56 deletions(-)\n\napplies-to: 8cf0bb652ffde36e57bca5d6f33287305a61bb74\n2c48a811a36ee6e12aeb044b3d1ff459b8d958c2\ndiff --git a/apply.c b/apply.c\nold index 7be50413538868412a87c847f8fa184cadd0fa2a 100644\nnew index ed2eac2c67dd003c8a0eaa7325e1543d1472777d 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -14,6 +14,7 @@\n //    files that are being modified, but doesn't apply the patch\n //  --stat does just a diffstat, and doesn't actually apply\n //  --show-files shows the directory changes\n+//  --show-index-info shows the old and new index info for paths if available.\n //\n static int check_index = 0;\n static int write_index = 0;\n@@ -22,8 +23,9 @@ static int summary = 0;\n static int check = 0;\n static int apply = 1;\n static int show_files = 0;\n+static int show_index_info = 0;\n static const char apply_usage[] =\n-\"git-apply [--stat] [--summary] [--check] [--index] [--apply] [--show-files] <patch>...\";\n+\"git-apply [--stat] [--summary] [--check] [--index] [--apply] [--show-files] [--show-index-info] <patch>...\";\n \n /*\n  * For \"diff-stat\" like behaviour, we keep track of the biggest change\n@@ -56,6 +58,8 @@ struct patch {\n \tstruct fragment *fragments;\n \tchar *result;\n \tunsigned long resultsize;\n+\tunsigned char old_sha1[20];\n+\tunsigned char new_sha1[20];\n \tstruct patch *next;\n };\n \n@@ -334,6 +338,24 @@ static int gitdiff_dissimilarity(const c\n \treturn 0;\n }\n \n+static int gitdiff_old_index(const char *line, struct patch *patch)\n+{\n+\tif (get_sha1_hex(line, patch->old_sha1))\n+\t\tmemcpy(patch->old_sha1, null_sha1, 20);\n+\telse\n+\t\tgitdiff_oldmode(line + 41, patch);\n+\treturn 0;\n+}\n+\n+static int gitdiff_new_index(const char *line, struct patch *patch)\n+{\n+\tif (get_sha1_hex(line, patch->new_sha1))\n+\t\tmemcpy(patch->new_sha1, null_sha1, 20);\n+\telse\n+\t\tgitdiff_newmode(line + 41, patch);\n+\treturn 0;\n+}\n+\n /*\n  * This is normal for a diff that doesn't change anything: we'll fall through\n  * into the next diff. Tell the parser to break out.\n@@ -438,6 +460,8 @@ static int parse_git_header(char *line, \n \t\t\t{ \"rename to \", gitdiff_renamedst },\n \t\t\t{ \"similarity index \", gitdiff_similarity },\n \t\t\t{ \"dissimilarity index \", gitdiff_dissimilarity },\n+\t\t\t{ \"old index \", gitdiff_old_index },\n+\t\t\t{ \"new index \", gitdiff_new_index },\n \t\t\t{ \"\", gitdiff_unrecognized },\n \t\t};\n \t\tint i;\n@@ -1136,6 +1160,36 @@ static void show_file_list(struct patch \n \t}\n }\n \n+static inline int is_null_sha1(const unsigned char *sha1)\n+{\n+\treturn !memcmp(sha1, null_sha1, 20);\n+}\n+\n+static void show_index_list(struct patch *list)\n+{\n+\tstruct patch *patch;\n+\n+\tfor (patch = list; patch; patch = patch->next) {\n+\t\tif ( (!patch->is_delete && is_null_sha1(patch->new_sha1)) ||\n+\t\t     (!patch->is_new && is_null_sha1(patch->old_sha1)) )\n+\t\t\tdie(\"patch does not record sha1 information\");\n+\t}\n+\n+\tfor (patch = list; patch; patch = patch->next) {\n+\t\tif (!is_null_sha1(patch->old_sha1))\n+\t\t\tprintf(\"- %s %06o\t%s\\n\",\n+\t\t\t       sha1_to_hex(patch->old_sha1),\n+\t\t\t       patch->old_mode,\n+\t\t\t       patch->old_name);\n+\n+\t\tif (!is_null_sha1(patch->new_sha1))\n+\t\t\tprintf(\"+ %s %06o\t%s\\n\",\n+\t\t\t       sha1_to_hex(patch->new_sha1),\n+\t\t\t       patch->new_mode,\n+\t\t\t       patch->new_name);\n+\t}\n+}\n+\n static void stat_patch_list(struct patch *patch)\n {\n \tint files, adds, dels;\n@@ -1476,6 +1530,9 @@ static int apply_patch(int fd)\n \tif (show_files)\n \t\tshow_file_list(list);\n \n+\tif (show_index_info)\n+\t\tshow_index_list(list);\n+\n \tif (diffstat)\n \t\tstat_patch_list(list);\n \n@@ -1534,6 +1591,11 @@ int main(int argc, char **argv)\n \t\t\tshow_files = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--show-index-info\")) {\n+\t\t\tapply = 0;\n+\t\t\tshow_index_info = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tfd = open(arg, O_RDONLY);\n \t\tif (fd < 0)\n \t\t\tusage(apply_usage);\ndiff --git a/cache.h b/cache.h\nold index ec2a1610b2fd6edec6c95847d4377f9c0241b738 100644\nnew index 514adb8f8ed621d98175bea0d701576de13eb620 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -165,6 +165,7 @@ extern int ce_match_stat(struct cache_en\n extern int ce_modified(struct cache_entry *ce, struct stat *st);\n extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);\n+extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);\n extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n \n struct cache_file {\ndiff --git a/diff.c b/diff.c\nold index 7d06b035ae8b6a53f10a7f94251a24d911baa509 100644\nnew index b602e25ccb2b4cf56dbfb5f2797651b1e44d4585 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -596,15 +596,31 @@ static void run_external_diff(const char\n \tremove_tempfile();\n }\n \n+static void diff_fill_sha1_info(struct diff_filespec *one)\n+{\n+\tif (DIFF_FILE_VALID(one)) {\n+\t\tif (!one->sha1_valid) {\n+\t\t\tstruct stat st;\n+\t\t\tif (stat(one->path, &st) < 0)\n+\t\t\t\tdie(\"stat %s\", one->path);\n+\t\t\tif (index_path(one->sha1, one->path, &st, 0))\n+\t\t\t\tdie(\"cannot hash %s\\n\", one->path);\n+\t\t}\n+\t}\n+\telse\n+\t\tmemset(one->sha1, 0, 20);\n+}\n+\n static void run_diff(struct diff_filepair *p)\n {\n \tconst char *pgm = external_diff();\n-\tchar msg_[PATH_MAX*2+200], *xfrm_msg;\n+\tchar msg[PATH_MAX*2+300], *xfrm_msg;\n \tstruct diff_filespec *one;\n \tstruct diff_filespec *two;\n \tconst char *name;\n \tconst char *other;\n \tint complete_rewrite = 0;\n+\tint len;\n \n \tif (DIFF_PAIR_UNMERGED(p)) {\n \t\t/* unmerged */\n@@ -616,38 +632,58 @@ static void run_diff(struct diff_filepai\n \tname = p->one->path;\n \tother = (strcmp(name, p->two->path) ? p->two->path : NULL);\n \tone = p->one; two = p->two;\n+\n+\tdiff_fill_sha1_info(one);\n+\tdiff_fill_sha1_info(two);\n+\n+\tlen = 0;\n+\tif (memcmp(one->sha1, two->sha1, 20)) {\n+\t\tif (memcmp(one->sha1, null_sha1, 20))\n+\t\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n+\t\t\t\t\t\"old index %s %06o\\n\",\n+\t\t\t\t\tsha1_to_hex(one->sha1),\n+\t\t\t\t\tone->mode);\n+\t\tif (memcmp(two->sha1, null_sha1, 20))\n+\t\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n+\t\t\t\t\t\"new index %s %06o\\n\",\n+\t\t\t\t\tsha1_to_hex(two->sha1),\n+\t\t\t\t\ttwo->mode);\n+\t}\n+\n \tswitch (p->status) {\n \tcase DIFF_STATUS_COPIED:\n-\t\tsprintf(msg_,\n-\t\t\t\"similarity index %d%%\\n\"\n-\t\t\t\"copy from %s\\n\"\n-\t\t\t\"copy to %s\",\n-\t\t\t(int)(0.5 + p->score * 100.0/MAX_SCORE),\n-\t\t\tname, other);\n-\t\txfrm_msg = msg_;\n+\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n+\t\t\t\t\"similarity index %d%%\\n\"\n+\t\t\t\t\"copy from %s\\n\"\n+\t\t\t\t\"copy to %s\\n\",\n+\t\t\t\t(int)(0.5 + p->score * 100.0/MAX_SCORE),\n+\t\t\t\tname, other);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tsprintf(msg_,\n-\t\t\t\"similarity index %d%%\\n\"\n-\t\t\t\"rename from %s\\n\"\n-\t\t\t\"rename to %s\",\n-\t\t\t(int)(0.5 + p->score * 100.0/MAX_SCORE),\n-\t\t\tname, other);\n-\t\txfrm_msg = msg_;\n+\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n+\t\t\t\t\"similarity index %d%%\\n\"\n+\t\t\t\t\"rename from %s\\n\"\n+\t\t\t\t\"rename to %s\\n\",\n+\t\t\t\t(int)(0.5 + p->score * 100.0/MAX_SCORE),\n+\t\t\t\tname, other);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n \t\tif (p->score) {\n-\t\t\tsprintf(msg_,\n-\t\t\t\t\"dissimilarity index %d%%\",\n-\t\t\t\t(int)(0.5 + p->score * 100.0/MAX_SCORE));\n-\t\t\txfrm_msg = msg_;\n+\t\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n+\t\t\t\t\t\"dissimilarity index %d%%\\n\",\n+\t\t\t\t\t(int)(0.5 + p->score *\n+\t\t\t\t\t      100.0/MAX_SCORE));\n \t\t\tcomplete_rewrite = 1;\n \t\t\tbreak;\n \t\t}\n \t\t/* fallthru */\n \tdefault:\n-\t\txfrm_msg = NULL;\n+\t\t/* nothing */\n+\t\t;\n \t}\n+\tif (len)\n+\t\tmsg[--len] = 0;\n+\txfrm_msg = len ? msg : NULL;\n \n \tif (!pgm &&\n \t    DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&\ndiff --git a/sha1_file.c b/sha1_file.c\nold index 895c1fab6fc00b8131e44851f33b79b1d2310b12 100644\nnew index 287f618827d9b2fd472c06add42ead65de291822 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1545,3 +1545,42 @@ int index_fd(unsigned char *sha1, int fd\n \t\tmunmap(buf, size);\n \treturn ret;\n }\n+\n+int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)\n+{\n+\tint fd;\n+\tchar *target;\n+\n+\tswitch (st->st_mode & S_IFMT) {\n+\tcase S_IFREG:\n+\t\tfd = open(path, O_RDONLY);\n+\t\tif (fd < 0)\n+\t\t\treturn error(\"open(\\\"%s\\\"): %s\", path,\n+\t\t\t\t     strerror(errno));\n+\t\tif (index_fd(sha1, fd, st, write_object, NULL) < 0)\n+\t\t\treturn error(\"%s: failed to insert into database\",\n+\t\t\t\t     path);\n+\t\tbreak;\n+\tcase S_IFLNK:\n+\t\ttarget = xmalloc(st->st_size+1);\n+\t\tif (readlink(path, target, st->st_size+1) != st->st_size) {\n+\t\t\tchar *errstr = strerror(errno);\n+\t\t\tfree(target);\n+\t\t\treturn error(\"readlink(\\\"%s\\\"): %s\", path,\n+\t\t\t             errstr);\n+\t\t}\n+\t\tif (!write_object) {\n+\t\t\tunsigned char hdr[50];\n+\t\t\tint hdrlen;\n+\t\t\twrite_sha1_file_prepare(target, st->st_size, \"blob\",\n+\t\t\t\t\t\tsha1, hdr, &hdrlen);\n+\t\t} else if (write_sha1_file(target, st->st_size, \"blob\", sha1))\n+\t\t\treturn error(\"%s: failed to insert into database\",\n+\t\t\t\t     path);\n+\t\tfree(target);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn error(\"%s: unsupported file type\", path);\n+\t}\n+\treturn 0;\n+}\ndiff --git a/t/diff-lib.sh b/t/diff-lib.sh\nold index a912f435aa67d7b2cde09f0b8c9855442c6c2377 100755\nnew index a4095db2ed3b57d5e042c5ca49dd912c1c534cf8 100755\n--- a/t/diff-lib.sh\n+++ b/t/diff-lib.sh\n@@ -29,7 +29,13 @@ compare_diff_raw_z () {\n compare_diff_patch () {\n     # When heuristics are improved, the score numbers would change.\n     # Ignore them while comparing.\n-    sed -e '/^[dis]*imilarity index [0-9]*%$/d' <\"$1\" >.tmp-1\n-    sed -e '/^[dis]*imilarity index [0-9]*%$/d' <\"$2\" >.tmp-2\n+    sed -e '\n+\t/^[dis]*imilarity index [0-9]*%$/d\n+\t/^[no][el][dw] index [0-9a-f]* [0-7]*$/d\n+    ' <\"$1\" >.tmp-1\n+    sed -e '\n+\t/^[dis]*imilarity index [0-9]*%$/d\n+\t/^[no][el][dw] index [0-9a-f]* [0-7]*$/d\n+    ' <\"$2\" >.tmp-2\n     diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2\n }\ndiff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh\nold index f3b6330a9b4af0e68d9e402ab7d82e600c939ccc 100755\nnew index fa387cc24b8e5e6c92df9d1d504b805c92b94e36 100755\n--- a/t/t4000-diff-format.sh\n+++ b/t/t4000-diff-format.sh\n@@ -7,6 +7,7 @@ test_description='Test built-in diff out\n \n '\n . ./test-lib.sh\n+. ../diff-lib.sh\n \n echo >path0 'Line 1\n Line 2\n@@ -29,6 +30,8 @@ cat >expected <<\\EOF\n diff --git a/path0 b/path0\n old mode 100644\n new mode 100755\n+old index 85d7fd2fbbe9564fe6ecc5e72416adb36e62d658 100644\n+new index 6ad36e52f0002937ed2de6a1c15d8a0ae5df056a 100755\n --- a/path0\n +++ b/path0\n @@ -1,3 +1,3 @@\n@@ -38,6 +41,7 @@ new mode 100755\n +Line 3\n diff --git a/path1 b/path1\n deleted file mode 100755\n+old index 85d7fd2fbbe9564fe6ecc5e72416adb36e62d658 100755\n --- a/path1\n +++ /dev/null\n @@ -1,3 +0,0 @@\n@@ -48,6 +52,6 @@ EOF\n \n test_expect_success \\\n     'validate git-diff-files -p output.' \\\n-    'cmp -s current expected'\n+    'compare_diff_patch current expected'\n \n test_done\ndiff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh\nold index be474856824f8e6659151590ed5acff38187e97d 100755\nnew index 2e3c20d6b9468bf413e97d422e7dbe13ac4238cd 100755\n--- a/t/t4001-diff-rename.sh\n+++ b/t/t4001-diff-rename.sh\n@@ -7,6 +7,7 @@ test_description='Test rename detection \n \n '\n . ./test-lib.sh\n+. ../diff-lib.sh\n \n echo >path0 'Line 1\n Line 2\n@@ -61,6 +62,6 @@ EOF\n \n test_expect_success \\\n     'validate the output.' \\\n-    'diff -I \"similarity.*\" >/dev/null current expected'\n+    'compare_diff_patch current expected'\n \n test_done\ndiff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh\nold index f59614ae255b33f450a784200716c9fd63b0a054 100755\nnew index a23aaa0a9471c68b233480cf34c7115d1f40e154 100755\n--- a/t/t4004-diff-rename-symlink.sh\n+++ b/t/t4004-diff-rename-symlink.sh\n@@ -10,6 +10,7 @@ copy of symbolic links, but should not p\n by an edit for them.\n '\n . ./test-lib.sh\n+. ../diff-lib.sh\n \n test_expect_success \\\n     'prepare reference tree' \\\n@@ -61,6 +62,6 @@ EOF\n \n test_expect_success \\\n     'validate diff output' \\\n-    'diff -u current expected'\n+    'compare_diff_patch current expected'\n \n test_done\ndiff --git a/update-index.c b/update-index.c\nold index b825a11d2f6d8a53f5e42e4f157ba036a13edb59 100644\nnew index 9dc518877b67bedced29ac91ecd8fafbb2a60135 100644\n--- a/update-index.c\n+++ b/update-index.c\n@@ -37,8 +37,6 @@ static int add_file_to_cache(const char \n \tint size, namelen, option, status;\n \tstruct cache_entry *ce;\n \tstruct stat st;\n-\tint fd;\n-\tchar *target;\n \n \tstatus = lstat(path, &st);\n \tif (status < 0 || S_ISDIR(st.st_mode)) {\n@@ -77,34 +75,9 @@ static int add_file_to_cache(const char \n \tfill_stat_cache_info(ce, &st);\n \tce->ce_mode = create_ce_mode(st.st_mode);\n \tce->ce_flags = htons(namelen);\n-\tswitch (st.st_mode & S_IFMT) {\n-\tcase S_IFREG:\n-\t\tfd = open(path, O_RDONLY);\n-\t\tif (fd < 0)\n-\t\t\treturn error(\"open(\\\"%s\\\"): %s\", path, strerror(errno));\n-\t\tif (index_fd(ce->sha1, fd, &st, !info_only, NULL) < 0)\n-\t\t\treturn error(\"%s: failed to insert into database\", path);\n-\t\tbreak;\n-\tcase S_IFLNK:\n-\t\ttarget = xmalloc(st.st_size+1);\n-\t\tif (readlink(path, target, st.st_size+1) != st.st_size) {\n-\t\t\tchar *errstr = strerror(errno);\n-\t\t\tfree(target);\n-\t\t\treturn error(\"readlink(\\\"%s\\\"): %s\", path,\n-\t\t\t             errstr);\n-\t\t}\n-\t\tif (info_only) {\n-\t\t\tunsigned char hdr[50];\n-\t\t\tint hdrlen;\n-\t\t\twrite_sha1_file_prepare(target, st.st_size, \"blob\",\n-\t\t\t\t\t\tce->sha1, hdr, &hdrlen);\n-\t\t} else if (write_sha1_file(target, st.st_size, \"blob\", ce->sha1))\n-\t\t\treturn error(\"%s: failed to insert into database\", path);\n-\t\tfree(target);\n-\t\tbreak;\n-\tdefault:\n-\t\treturn error(\"%s: unsupported file type\", path);\n-\t}\n+\n+\tif (index_path(ce->sha1, path, &st, !info_only))\n+\t\treturn -1;\n \toption = allow_add ? ADD_CACHE_OK_TO_ADD : 0;\n \toption |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;\n \tif (add_cache_entry(ce, option))\n---\n0.99.8.GIT\n"},{"id":"9788","messageId":"Pine.LNX.4.64.0510062139560.31407@g5.osdl.org","threadId":"2015","inReplyTo":"7vachm5a4w.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Show original and resulting blob object info in diff output.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-07T04:47:56Z","receivedAt":"2005-10-07T04:47:56Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Thu, 6 Oct 2005, Junio C Hamano wrote:\n> \n>     diff --git a/apply.c b/apply.c\n>     old index 7be50413538868412a87c847f8fa184cadd0fa2a 100644\n>     new index 83660822fcbb9edac523634999e30d65c2790cae 100644\n\nHmm.. It strikes me that if we don't have the SHA1 object, then the SHA1 \nis largely useless except as a verification of the thing (ie we can still \n_calculate_ the blob sha of whatever the current file is).\n\nAnd if we _do_ have the SHA1, then we don't actually need all of it.\n\nSo the above is just very ugly, but it would be equally useful if it just \nhad a partial SHA1 - still plenty good to identify the thing.\n\nIO, why not make it shorter ans prettier and just make it be\n\n\tindex 7be50413538868412a87..83660822fcbb9edac523\n\nwhich is basically the first 20 hex digits of each SHA1.\n\nStill plenty good to look up the object if we have it, and _certainly_ \ngood enough as a quick verification. And much less \"imposing\".\n\nThe thing is, I actually tend to look at diffs when I send stuff out or \nreceive them, and your one is just very ugly:\n\n> applies-to: 8cf0bb652ffde36e57bca5d6f33287305a61bb74\n> 2c48a811a36ee6e12aeb044b3d1ff459b8d958c2\n> diff --git a/apply.c b/apply.c\n> old index 7be50413538868412a87c847f8fa184cadd0fa2a 100644\n> new index ed2eac2c67dd003c8a0eaa7325e1543d1472777d 100644\n> --- a/apply.c\n> +++ b/apply.c\n> @@ -14,6 +14,7 @@\n\nThat's a _lot_ of very \"solid\" unreadable stuff. It makes my eyes water. \nI'd really like to minimize it.\n\nIf you want the \"applies-to\" etc, then _all_ of it could be just crammed \nonto just one line (just cut each SHA1 down to 10 hex characters: 40 bits \nis still _way_ enough to indicate a unique version of a particular file if \nwe have it, even if it's \"just\" a quarter of the full name. It's not \nlike this is meant to be cryptographic. In fact, I bet 20 bits would be \nplenty).\n\n\t\tLinus\n"},{"id":"9791","messageId":"7vpsqh29gh.fsf@assigned-by-dhcp.cox.net","threadId":"2015","inReplyTo":"Pine.LNX.4.64.0510062139560.31407@g5.osdl.org","subject":"Re: [PATCH] Show original and resulting blob object info in diff output.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-07T05:16:14Z","receivedAt":"2005-10-07T05:16:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> IOW, why not make it shorter ans prettier and just make it be\n>\n> \tindex 7be50413538868412a87..83660822fcbb9edac523\n>\n> which is basically the first 20 hex digits of each SHA1.\n\nMakes sense.\n\n> If you want the \"applies-to\" etc,...\n\napplies-to: is for the whole tree, and I think it can go if we\ndo this per-blob signature thing.\n\nThe first SHA1 after applies-to: is coming from diff-tree,\nnoting the commit object _after_ the change.  I could filter it\nwhile running format-patch, because it is useless from patch\napplication point of view.\n\n> .... In fact, I bet 20 bits would be plenty).\n\nSo the updated proposal would be:\n\n    diff --git a/apply.c b/apply.c\n    index 7be5041..8366082 100644\n    --- a/apply.c\n    +++ b/apply.c\n    @@ -14,6 +14,7 @@\n    ...\n    diff --git a/foo.sh b/bar.sh\n    old mode 100644\n    new mode 100755\n    index 7be5041..8366082\n    similarity index 86%\n    rename from foo.sh\n    rename to bar.sh\n    --- a/foo.sh\n    +++ b/bar.sh\n    @@ -14,6 +14,7 @@\n    ...\n\nwhere the \"index\" line shows abbreviated SHA1 for pre- and post-\nimage blob, with an optional mode bit string only if there is no\nmode change; otherwise we would have old/new mode line anyway.\n"}]}