{"thread":{"id":"38501","subject":"[BUG] Move tracking in git diff is not as good as in git status","startedAt":"2015-02-05T06:11:42Z","lastAt":"2015-02-05T19:01:59Z","messageCount":3,"participants":["Scott Schmit","Kyle J. McKay","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"255615","messageId":"20150205061142.GA31599@odin.ulthar.us","threadId":"38501","inReplyTo":null,"subject":"[BUG] Move tracking in git diff is not as good as in git status","fromName":"Scott Schmit","fromEmail":"i.grok@comcast.net","sentAt":"2015-02-05T06:11:42Z","receivedAt":"2015-02-05T06:11:42Z","isPatch":false,"sender":{"key":"i.grok@comcast.net","avatar":null},"body":"In my use of git, I've noticed that \"git status\" is a lot better at\ntracking moves and renames than \"git diff\", and this has recently caused\nme a lot of headaches because a large number of moves were made in a\nsingle commit, and it was very difficult to figure out which moves were\nright and which were wrong.\n\nI was using a fairly old version of git (1.7.11), but was able to\nreproduce it on git 2.2.1.\n\nHere's a reproduction recipe:\n\n#!/bin/sh -x\n\n# Fill in your git.git working tree path here:\nGIT_GIT_REPO=\n\nif [ -z \"$GIT_GIT_REPO\" ]; then\n    echo Fill in GIT_GIT_REPO\n    exit 1\nfi\n\ngit init mv-test\ncd mv-test/\n\n# Pick two sample files of non-trivial size, since files that are too small\n# never get tracked as moves.\ncp ${GIT_GIT_REPO}/Documentation/asciidoc.conf .\ncp ${GIT_GIT_REPO}/Documentation/blame-options.txt .\ngit add *\ngit commit -m \"Start with two files from git.git/Documentation\"\n\n# Now rename them to something. Using 1 & 2 because they're nice & short.\ngit mv asciidoc.conf 1\ngit mv blame-options.txt 2\n\n# Status sees the rename\ngit status\n\n# So does the summary on the commit\ngit commit -m \"Rename both files\"\n\n# And move tracking works\ngit diff -M --stat --summary HEAD~..\ngit diff -C --stat --summary HEAD~..\n\n# Now \"shift\" the files\ngit mv 2 3\ngit mv 1 2\n\n# Status knows what's going on\ngit status\n\n# So does commit\ngit commit -m \"2=1;3=2;\"\n\n# Neither of these commands get it (but -C gets a glimmer of the truth)\ngit diff -M --stat --summary HEAD~..\ngit diff -C --stat --summary HEAD~..\n\n# Swap the files in place\ngit mv 3 tmp\ngit mv 2 3\ngit mv tmp 2\n\n# Status gets it\ngit status\n\n# Commit understands\ngit commit -m \"Swap 2 & 3\"\n\n# Diff has no idea\ngit diff -M --stat --summary HEAD~..\ngit diff -C --stat --summary HEAD~..\n\n---\n\nAt first, I thought it was because the \"git mv\" command recorded\nsomething in the index that's lost once the commit happens.\n\nTo check if that was so, I went back to the commit in question, did a\n\"git reset HEAD~1\" and \"git add -A .\" and git status understood what was\ngoing on just fine.\n\n-- \nScott Schmit\n"},{"id":"255617","messageId":"099A7D2D-6033-4A16-91DD-E2288BC5C729@gmail.com","threadId":"38501","inReplyTo":"20150205061142.GA31599@odin.ulthar.us","subject":"Re: [BUG] Move tracking in git diff is not as good as in git status","fromName":"Kyle J. McKay","fromEmail":"mackyle@gmail.com","sentAt":"2015-02-05T07:39:25Z","receivedAt":"2015-02-05T07:39:25Z","isPatch":false,"sender":{"key":"mackyle@gmail.com","avatar":"https://avatars.githubusercontent.com/u/813346?v=4"},"body":"On Feb 4, 2015, at 22:11, Scott Schmit wrote:\n\n> In my use of git, I've noticed that \"git status\" is a lot better at\n> tracking moves and renames than \"git diff\", and this has recently  \n> caused\n> me a lot of headaches because a large number of moves were made in a\n> single commit, and it was very difficult to figure out which moves  \n> were\n> right and which were wrong.\n>\n> I was using a fairly old version of git (1.7.11), but was able to\n> reproduce it on git 2.2.1.\n>\n> Here's a reproduction recipe:\n[...]\n> # Now \"shift\" the files\n> git mv 2 3\n> git mv 1 2\n[...]\n> git commit -m \"2=1;3=2;\"\n>\n> # Neither of these commands get it (but -C gets a glimmer of the  \n> truth)\n> git diff -M --stat --summary HEAD~..\n> git diff -C --stat --summary HEAD~..\n\nAh, but did you try this:\n\n   git diff -B -M --stat --summary HEAD~..\n\n> # Swap the files in place\n> git mv 3 tmp\n> git mv 2 3\n> git mv tmp 2\n[...]\n> git commit -m \"Swap 2 & 3\"\n>\n> # Diff has no idea\n> git diff -M --stat --summary HEAD~..\n> git diff -C --stat --summary HEAD~..\n\nAgain, try this:\n\n   git diff -B -M --stat --summary HEAD~..\n\nYou can even use this:\n\n   git log -B -M --summary\n\nto see them all.\n\nWhile you can configure -M (or -C) to be on by default (see git config  \ndiff.renames), there does not appear to be a config option to turn on - \nB (--break-rewrites) by default.\n\nAnd according to a recent thread [1], using -B and -M together can  \nproduce incorrect results so you might not want them both on by  \ndefault anyway.\n\n-Kyle\n\n[1] http://thread.gmane.org/gmane.linux.kernel/1879635\n"},{"id":"255636","messageId":"xmqq61bgmbbs.fsf@gitster.dls.corp.google.com","threadId":"38501","inReplyTo":"099A7D2D-6033-4A16-91DD-E2288BC5C729@gmail.com","subject":"Re: [BUG] Move tracking in git diff is not as good as in git status","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-05T19:01:59Z","receivedAt":"2015-02-05T19:01:59Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Kyle J. McKay\" <mackyle@gmail.com> writes:\n\n> On Feb 4, 2015, at 22:11, Scott Schmit wrote:\n>\n>> In my use of git, I've noticed that \"git status\" is a lot better at\n>> tracking moves and renames than \"git diff\", and this has recently\n>> caused\n>> me a lot of headaches because a large number of moves were made in a\n>> single commit, and it was very difficult to figure out which moves\n>> were\n>> right and which were wrong.\n>>\n>> I was using a fairly old version of git (1.7.11), but was able to\n>> reproduce it on git 2.2.1.\n>>\n>> Here's a reproduction recipe:\n> [...]\n>> # Now \"shift\" the files\n>> git mv 2 3\n>> git mv 1 2\n> [...]\n>> git commit -m \"2=1;3=2;\"\n>>\n>> # Neither of these commands get it (but -C gets a glimmer of the\n>> truth)\n>> git diff -M --stat --summary HEAD~..\n>> git diff -C --stat --summary HEAD~..\n>\n> Ah, but did you try this:\n>\n>   git diff -B -M --stat --summary HEAD~..\n\nYes, since f714fb84 (Enable rewrite as well as rename detection in\ngit-status, 2007-12-02) \"git status\" internally uses \"-B -M\".\n"}]}