{"thread":{"id":"17549","subject":"retrospective move","startedAt":"2009-02-04T08:43:36Z","lastAt":"2009-02-04T12:57:55Z","messageCount":5,"participants":["jemmyw","Thomas Rast","Santi Béjar"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"103086","messageId":"21826423.post@talk.nabble.com","threadId":"17549","inReplyTo":null,"subject":"retrospective move","fromName":"jemmyw","fromEmail":"jeremy@boost.co.nz","sentAt":"2009-02-04T08:43:36Z","receivedAt":"2009-02-04T08:43:36Z","isPatch":false,"sender":{"key":"jeremy@boost.co.nz","avatar":null},"body":"\nHi. Awhile ago I copied some files in my local repo then commited. In another\ncommit I deleted the original files, so essentially I did a mv that git\ndoesn't know about. Now I'm trying to merge from another branch where\nchanges have happened to the files in their original locations, and it's\nmaking the merge somewhat difficult. Is there a way to ease this?\n-- \nView this message in context: http://www.nabble.com/retrospective-move-tp21826423p21826423.html\nSent from the git mailing list archive at Nabble.com.\n"},{"id":"103093","messageId":"200902041017.47564.trast@student.ethz.ch","threadId":"17549","inReplyTo":"21826423.post@talk.nabble.com","subject":"Re: retrospective move","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-04T09:17:45Z","receivedAt":"2009-02-04T09:17:45Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"jemmyw wrote:\n> \n> Hi. Awhile ago I copied some files in my local repo then commited. In another\n> commit I deleted the original files, so essentially I did a mv that git\n> doesn't know about. Now I'm trying to merge from another branch where\n> changes have happened to the files in their original locations, and it's\n> making the merge somewhat difficult. Is there a way to ease this?\n\nGit never \"knows\" about a move, it only detects them after the fact.\nA corollary of this is that 'git mv a b' is more or less the same as\n'cp a b; git rm a; git add b'.\n\nNow since you have a copy followed by a removal in two separate\ncommits, the merge logic won't treat this as a rename.  Some ideas for\npossible solutions:\n\n* If your cp&rm commits are strictly local, you could squash them into\n  a single commit.  See man git-rebase(1), especially the -i flag.\n  That way, the merge logic will recognise it as a rename.\n\n* You can use an extra line of history that has a \"real\" one-step mv.\n  Suppose you currently have\n\n     *---*---*---*---*      upstream\n      \\\n       \\\n        +--C--o--R--o--o    local\n\n  where C is the copy and R is the removal.  Then you can introduce an\n  extra \"gateway\" branch that does just the move:\n\n     *---*---*---*---*      upstream\n     |\\\n     | \\\n     |  +--M                gateway\n     |\n      \\\n       \\\n        +--C--o--R--o--o    local\n\n  Now merge gateway to local (i.e. git checkout local && git merge\n  gateway), and resolve all resulting conflicts.  I think you can\n  actually use '-s ours' in that merge, but be sure to check the\n  results.\n\n     *---*---*---*---*      upstream\n     |\\\n     | \\\n     |  +--M                gateway\n     |      \\\n      \\      +----------+\n       \\                 \\\n        +--C--o--R--o--o--1    local\n\n  Finally, you can use the gateway branch to \"do the rename\" on all\n  incoming new changes, by first merging upstream to gateway and later\n  again gateway to local, like so:\n  \n     *---*---*---*---*.      upstream\n     |\\                \\\n     | \\                \\\n     |  +--M-------------2       gateway\n     |      \\             \\\n      \\      +----------+  \\\n       \\                 \\  \\\n        +--C--o--R--o--o--1--3   local\n\n  It won't be very pretty history, but it should only give (rename\n  related) merge conflicts at M.\n\nHTH :-)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"103104","messageId":"adf1fd3d0902040231h2fb6f199oee143e36a7501a2a@mail.gmail.com","threadId":"17549","inReplyTo":"200902041017.47564.trast@student.ethz.ch","subject":"Re: retrospective move","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2009-02-04T10:31:43Z","receivedAt":"2009-02-04T10:31:43Z","isPatch":false,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2009/2/4 Thomas Rast <trast@student.ethz.ch>:\n> jemmyw wrote:\n>>\n>> Hi. Awhile ago I copied some files in my local repo then commited. In another\n>> commit I deleted the original files, so essentially I did a mv that git\n>> doesn't know about. Now I'm trying to merge from another branch where\n>> changes have happened to the files in their original locations, and it's\n>> making the merge somewhat difficult. Is there a way to ease this?\n>\n> Git never \"knows\" about a move, it only detects them after the fact.\n> A corollary of this is that 'git mv a b' is more or less the same as\n> 'cp a b; git rm a; git add b'.\n>\n> Now since you have a copy followed by a removal in two separate\n> commits, the merge logic won't treat this as a rename.\n\nI don't think it holds. Git only sees the endpoints and the bases, it\ndoes not matter if the \"move\" was actually two commits. Maybe they\nhave changed dramatically and git is not able to detect the rename (or\nthe files are small). Another possible cause could be that you have a\nlot of renames (see config merge.renamelimit).\n\nYou could see if git detects the rename diffing differents commits:\n\n$ git diff --raw -M commit1 commit2\n\nif it does not detect you could use other limits as:\n\n$ git diff --raw -M50 commit1 commit2\n\nwhile commit1 and 2 are the endpoints or the merge base.\n\nIt could hep if you could provide a minimal test case, or at least the\ncommands and output you get.\n\nHTH,\nSanti\n"},{"id":"103118","messageId":"200902041333.40776.trast@student.ethz.ch","threadId":"17549","inReplyTo":"adf1fd3d0902040231h2fb6f199oee143e36a7501a2a@mail.gmail.com","subject":"Re: retrospective move","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-04T12:33:38Z","receivedAt":"2009-02-04T12:33:38Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Santi Béjar wrote:\n> 2009/2/4 Thomas Rast <trast@student.ethz.ch>:\n> > jemmyw wrote:\n> >>\n> >> Hi. Awhile ago I copied some files in my local repo then commited. In another\n> >> commit I deleted the original files, so essentially I did a mv that git\n> >> doesn't know about. Now I'm trying to merge from another branch where\n> >> changes have happened to the files in their original locations, and it's\n> >> making the merge somewhat difficult. Is there a way to ease this?\n> >\n> > Git never \"knows\" about a move, it only detects them after the fact.\n> > A corollary of this is that 'git mv a b' is more or less the same as\n> > 'cp a b; git rm a; git add b'.\n> >\n> > Now since you have a copy followed by a removal in two separate\n> > commits, the merge logic won't treat this as a rename.\n> \n> I don't think it holds. Git only sees the endpoints and the bases, it\n> does not matter if the \"move\" was actually two commits. Maybe they\n> have changed dramatically and git is not able to detect the rename (or\n> the files are small). Another possible cause could be that you have a\n> lot of renames (see config merge.renamelimit).\n\nHmm, you're right.  I stand corrected.\n\nHere's a sequence of commands that makes a test case:\n\n  git init\n  seq 1 10 > A\n  git add A\n  git commit -m initial\n  seq 11 15 >> A\n  git commit -m second A\n  seq 16 20 >> A\n  git commit -m third\n  git checkout -b side HEAD~2\n  cp A B\n  git add B\n  git commit -m copy\n  seq 3 10 > B               # <--\n  git commit -m edit B\n  git rm A\n  git commit -m delete\n\nThen running\n\n  git merge master\n\ngoes through cleanly, but changing the line indicated above to 'seq 5\n10' makes it less similar, falling through the detection and causing a\nconflict.  The minimum required similarity for merges does not seem to\nbe configurable unfortunately.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"103132","messageId":"adf1fd3d0902040457p7823792dg80a6d389f8079c32@mail.gmail.com","threadId":"17549","inReplyTo":"200902041333.40776.trast@student.ethz.ch","subject":"Re: retrospective move","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2009-02-04T12:57:55Z","receivedAt":"2009-02-04T12:57:55Z","isPatch":false,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2009/2/4 Thomas Rast <trast@student.ethz.ch>:\n\n[...]\n\n>\n> Here's a sequence of commands that makes a test case:\n>\n>  git init\n>  seq 1 10 > A\n>  git add A\n>  git commit -m initial\n>  seq 11 15 >> A\n>  git commit -m second A\n>  seq 16 20 >> A\n>  git commit -m third\n>  git checkout -b side HEAD~2\n>  cp A B\n>  git add B\n>  git commit -m copy\n>  seq 3 10 > B               # <--\n>  git commit -m edit B\n>  git rm A\n>  git commit -m delete\n>\n> Then running\n>\n>  git merge master\n>\n> goes through cleanly, but changing the line indicated above to 'seq 5\n> 10' makes it less similar, falling through the detection and causing a\n> conflict.\n\nThanks, but that's known, this is why I wrote \"or the files are\nsmall\". I was not clear, but what I wanted was a *real* test case. In\nwhich cases this is a problem in practice.\n\n>  The minimum required similarity for merges does not seem to\n> be configurable unfortunately.\n\nNo, but nevertheless it works fine most of the time, except with small files.\n\nHTH,\nSanti\n"}]}