* Re: Rename of file is causing changes to be lost
2018-03-08 16:01 Rename of file is causing changes to be lost Robert Dailey
@ 2018-03-13 14:32 ` Robert Dailey
2018-03-13 16:51 ` Elijah Newren
1 sibling, 0 replies; 4+ messages in thread
From: Robert Dailey @ 2018-03-13 14:32 UTC (permalink / raw)
To: Git
On Thu, Mar 8, 2018 at 10:01 AM, Robert Dailey <rcdailey.lists@gmail.com> wrote:
> I'm on Windows and core.ignorecase is set to 'true' when I clone/init
> a repository. I've got a branch where I started making changes to a
> file AND renamed it only to change its case. The changes I've made
> were significant enough that git no longer detects a rename, instead
> the files show up as "D" and "A" in git status (deleted then added).
> To correct this, I do an interactive rebase to add an additional
> commit before the first one to rename the file without changing it,
> and *then* allow the second commit to change the file. The goal is
> that rebase should detect the rename and automatically move the
> changes in the (now) second commit to the newly named file. Here's a
> MCVE (treat this as a script):
>
> #/bin/bash
> git init testgitrepo
> cd testgitrepo/
> git config core.ignorecase true # This is set by Windows for me, but
> hopefully will allow this to repro on linux. Didn't test linux though.
> echo "first change" > foo.txt
> git add . && git commit -m 'first change'
> git checkout -b topic
> echo "second change" > foo.txt
> git mv foo.txt FOO.txt
> git add . && git commit -m 'second change'
> git rebase -i master # Move line 1 to line 2, and put "x false" in line 1
> git mv foo.txt FOO.txt && git commit -m 'rename foo'
> git rebase --continue
> git mergetool
>
> After the rebase continue, you will get a conflict like so:
>
> error: could not apply 527d208... second change
>
> When you have resolved this problem, run "git rebase --continue".
> If you prefer to skip this patch, run "git rebase --skip" instead.
> To check out the original branch and stop rebasing, run "git rebase --abort".
>
> Could not apply 527d208... second change
> CONFLICT (rename/delete): foo.txt deleted in 527d208... second change
> and renamed to FOO.txt in HEAD. Version HEAD of FOO.txt left in tree.
>
> The last command, `git mergetool` runs, giving you the option to pick
> the Created (left) or Deleted (right) version of the file:
>
> Left: The file is created, but selecting this erases the changes from
> the "added" version on the remote (which is topic). Basically the
> rename of only case confused git, and we lost the changes on the
> remote version of the file
> Right: File is deleted. Changes are still lost.
>
> The ideal outcome is that the changes from the "added" version of the
> file in the 2nd commit get carried over to the "renamed" version of
> the file, which when you compare the two are named exactly the same
> after the 1st commit is introduced. How can I solve this issue?
I wanted to bump this and see if anyone would have a spare few minutes
to help me out with this. I know it's a needlessly complex situation,
but I'd really love to know how to resolve the specific issue, or
perhaps learn a better way to approach this in the future if I'm
shooting myself in the foot here.
Thanks again.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Rename of file is causing changes to be lost
2018-03-08 16:01 Rename of file is causing changes to be lost Robert Dailey
2018-03-13 14:32 ` Robert Dailey
@ 2018-03-13 16:51 ` Elijah Newren
2018-03-13 18:02 ` Robert Dailey
1 sibling, 1 reply; 4+ messages in thread
From: Elijah Newren @ 2018-03-13 16:51 UTC (permalink / raw)
To: Robert Dailey; +Cc: Git
On Thu, Mar 8, 2018 at 8:01 AM, Robert Dailey <rcdailey.lists@gmail.com> wrote:
> I'm on Windows and core.ignorecase is set to 'true' when I clone/init
> a repository. I've got a branch where I started making changes to a
> file AND renamed it only to change its case. The changes I've made
> were significant enough that git no longer detects a rename, instead
> the files show up as "D" and "A" in git status (deleted then added).
> To correct this, I do an interactive rebase to add an additional
> commit before the first one to rename the file without changing it,
> and *then* allow the second commit to change the file. The goal is
> that rebase should detect the rename and automatically move the
> changes in the (now) second commit to the newly named file. Here's a
> MCVE (treat this as a script):
>
> #/bin/bash
> git init testgitrepo
> cd testgitrepo/
> git config core.ignorecase true # This is set by Windows for me, but
> hopefully will allow this to repro on linux. Didn't test linux though.
> echo "first change" > foo.txt
> git add . && git commit -m 'first change'
> git checkout -b topic
> echo "second change" > foo.txt
> git mv foo.txt FOO.txt
> git add . && git commit -m 'second change'
> git rebase -i master # Move line 1 to line 2, and put "x false" in line 1
> git mv foo.txt FOO.txt && git commit -m 'rename foo'
> git rebase --continue
> git mergetool
>
> After the rebase continue, you will get a conflict like so:
>
> error: could not apply 527d208... second change
>
> When you have resolved this problem, run "git rebase --continue".
> If you prefer to skip this patch, run "git rebase --skip" instead.
> To check out the original branch and stop rebasing, run "git rebase --abort".
>
> Could not apply 527d208... second change
> CONFLICT (rename/delete): foo.txt deleted in 527d208... second change
> and renamed to FOO.txt in HEAD. Version HEAD of FOO.txt left in tree.
>
> The last command, `git mergetool` runs, giving you the option to pick
> the Created (left) or Deleted (right) version of the file:
>
> Left: The file is created, but selecting this erases the changes from
> the "added" version on the remote (which is topic). Basically the
> rename of only case confused git, and we lost the changes on the
> remote version of the file
> Right: File is deleted. Changes are still lost.
>
> The ideal outcome is that the changes from the "added" version of the
> file in the 2nd commit get carried over to the "renamed" version of
> the file, which when you compare the two are named exactly the same
> after the 1st commit is introduced. How can I solve this issue?
Cool, thanks for the testcase. I don't have a good workaround for
you, but this is clearly a bug in the merge-recursive logic in git. I
guess it's what might be called a rename/add/delete conflict, which
git just doesn't handle. Your testcase triggers the bug just fine on
linux, though you can trigger the exact same bug without case
sensitivity using a slightly different setup (and no need for an
interactive rebase):
------
git init foobar
cd foobar
echo "original file" >foo
git add foo
git commit -m "original"
git branch L
git branch R
git checkout L
git rm foo
echo "different file" >bar
git add bar
git commit -m "Remove foo, add bar"
git checkout R
git mv foo bar
git commit -m "rename foo to bar"
git merge L
-------
git has code to handle rename/delete conflicts and rename/add
conflicts, but since one side of history BOTH deleted foo and added an
unrelated bar, that means both types of changes are relevant to the
same path (bar) -- essentially, a rename/delete/add conflict. Sadly,
git only goes down a codepath that handles one of those two (the
rename/delete), and incorrectly throws away the separate add:
-----
$ git ls-files -s
100644 78fa0f415ae2bdb5c0182c067eacaaf843699b39 2 bar
$ git ls-tree -r master
100644 blob 78fa0f415ae2bdb5c0182c067eacaaf843699b39 foo
$ git ls-tree -r L
100644 blob f286e5cdd97ac6895438ea4548638bb98ac9bd6b bar
$ git ls-tree -r R
100644 blob 78fa0f415ae2bdb5c0182c067eacaaf843699b39 bar
-----
But the problem is actually a bit bigger than shown here; there are
higher order corner cases here too. I realized in the past that e.g.
rename/rename(1to2) could also have rename/add conflicts for each
rename (thus making a rename/rename/add/add conflict possible), but I
also felt there were probably some other bad interactions out there.
I figured they were likely theoretical only, so I didn't bother
investigating. But, combining your example with that other one, we
should also be able to come up with a
rename/rename/add/add/delete/delete conflict. I wonder if there are
others...
Anyway, I recorded this at
https://bugs.chromium.org/p/git/issues/detail?id=11. Sorry I don't
have a workaround, but I'll try to eventually get back to this and fix
it.
^ permalink raw reply [flat|nested] 4+ messages in thread