{"thread":{"id":"30436","subject":"How does git now about future renames during a rebase?","startedAt":"2012-05-06T04:11:00Z","lastAt":"2012-05-06T08:52:49Z","messageCount":2,"participants":["Jon Seymour","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"190873","messageId":"CAH3Anro6o478A41eXcsFU7guOobQXhqq=DdpNpGWgriRVfqcZQ@mail.gmail.com","threadId":"30436","inReplyTo":null,"subject":"How does git now about future renames during a rebase?","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2012-05-06T04:11:00Z","receivedAt":"2012-05-06T04:11:00Z","isPatch":false,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"I had a history that looked like this:\n\n1. some other commit\n2. commit that moves files from one directory to a new directory\n3. commit that edits files in the new directory.\n\nI then did an interactive rebase to move the commit 3 before commit 2.\n\n1. some other commit\n3a. commit that edits files in the new directory.\n2a. commit that moves files from one directory to a new directory\n\nI didn't expect this to work, but somehow git worked out that it\nneeded to apply the change in 3 to the original location of the files.\n\nHow does it do this?\n\njon.,\n"},{"id":"190885","messageId":"20120506085248.GC27878@sigill.intra.peff.net","threadId":"30436","inReplyTo":"CAH3Anro6o478A41eXcsFU7guOobQXhqq=DdpNpGWgriRVfqcZQ@mail.gmail.com","subject":"Re: How does git now about future renames during a rebase?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-05-06T08:52:49Z","receivedAt":"2012-05-06T08:52:49Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, May 06, 2012 at 09:41:00AM +0530, Jon Seymour wrote:\n\n> I had a history that looked like this:\n> \n> 1. some other commit\n> 2. commit that moves files from one directory to a new directory\n> 3. commit that edits files in the new directory.\n> \n> I then did an interactive rebase to move the commit 3 before commit 2.\n> \n> 1. some other commit\n> 3a. commit that edits files in the new directory.\n> 2a. commit that moves files from one directory to a new directory\n> \n> I didn't expect this to work, but somehow git worked out that it\n> needed to apply the change in 3 to the original location of the files.\n> \n> How does it do this?\n\nWhen you pick a commit, we actually do a merge between it and the\ncurrent HEAD, using the parent of the picked commit as a merge base. So\nimagine we have this short history:\n\n  git init repo &&\n  cd repo &&\n  seq 1 100 >foo && git add foo && git commit -m base &&\n  git mv foo bar && git commit -m move &&\n  echo 101 >>bar && git add bar && git commit -m change\n\nI.e., a move followed by a change. And you run:\n\n  git rebase -i HEAD~2\n\nand swap the two commits. So afterwards we will have a change followed\nby a move. What does git see?\n\nWhen we pick the first commit (\"change\"), we end up merging with these\nparameters:\n\n  - The \"ours\" side is \"base\", with \"foo\" containing 1..100.\n  - The \"theirs\" side is \"change\", with \"foo\" absent and \"bar\"\n    containing 1..101.\n  - The ancestor is \"move\", with \"foo\" absent and \"bar\" containing\n    1..100.\n\nSo rename detection sees that our side moved bar to foo (compared to the\nancestor), and the other side added a line to bar. And it resolves by\nputting the modified content into \"foo\". Now obviously nobody _actually_\nmoved bar to foo; it was quite the opposite. But that makes sense; a\ncherry-pick merge like this sees the reverse of what happened between\nthe picked commit and the destination commit (less any changes which\nhave been picked already).\n\nAnd then we pick the second commit (\"move\"), with these merge\nparameters:\n\n  - The \"ours\" side is now changed', \"foo\" containing 1..101.\n  - The \"theirs\" side is \"move\", with \"foo\" absent and \"bar\" containing\n    1..100.\n  - The ancestor is \"base\", with \"foo\" containing 1..100.\n\nNow it looks like their side made a move (\"foo\" to \"bar\"), and our\nside modified \"foo\" (i.e., the opposite of the last case). So we again\nresolve to put the final content in \"bar\".\n\nDoes that make sense?\n\n-Peff\n"}]}