Skip to contentSkip to conversation

retrospective move

DISCUSSION jemmyw 3 participants 5 messages Jun 15, 2016

lore
Share & tools
lore

jemmyw

author
#0 lore raw

Hi. Awhile ago I copied some files in my local repo then commited. In another commit I deleted the original files, so essentially I did a mv that git doesn't know about. Now I'm trying to merge from another branch where changes have happened to the files in their original locations, and it's making the merge somewhat difficult. Is there a way to ease this?

Signature · 2 lines
View this message in context: http://www.nabble.com/retrospective-move-tp21826423p21826423.html
Sent from the git mailing list archive at Nabble.com.
#1 lore raw
Quoted 6 lines · jemmyw

Hi. Awhile ago I copied some files in my local repo then commited. In another commit I deleted the original files, so essentially I did a mv that git doesn't know about. Now I'm trying to merge from another branch where changes have happened to the files in their original locations, and it's making the merge somewhat difficult. Is there a way to ease this?

Git never "knows" about a move, it only detects them after the fact. A corollary of this is that 'git mv a b' is more or less the same as 'cp a b; git rm a; git add b'.

Now since you have a copy followed by a removal in two separate commits, the merge logic won't treat this as a rename. Some ideas for possible solutions:

* If your cp&rm commits are strictly local, you could squash them into a single commit. See man git-rebase(1), especially the -i flag. That way, the merge logic will recognise it as a rename.

* You can use an extra line of history that has a "real" one-step mv. Suppose you currently have

     *---*---*---*---*      upstream
      \
       \
        +--C--o--R--o--o    local

where C is the copy and R is the removal. Then you can introduce an extra "gateway" branch that does just the move:

     *---*---*---*---*      upstream
     |\
     | \
     |  +--M                gateway
     |
      \
       \
        +--C--o--R--o--o    local

Now merge gateway to local (i.e. git checkout local && git merge gateway), and resolve all resulting conflicts. I think you can actually use '-s ours' in that merge, but be sure to check the results.

     *---*---*---*---*      upstream
     |\
     | \
     |  +--M                gateway
     |      \
      \      +----------+
       \                 \
        +--C--o--R--o--o--1    local

Finally, you can use the gateway branch to "do the rename" on all incoming new changes, by first merging upstream to gateway and later again gateway to local, like so:

     *---*---*---*---*.      upstream
     |\                \
     | \                \
     |  +--M-------------2       gateway
     |      \             \
      \      +----------+  \
       \                 \  \
        +--C--o--R--o--o--1--3   local

It won't be very pretty history, but it should only give (rename related) merge conflicts at M.

HTH :-)

Signature · 2 lines
Thomas Rast
trast@{inf,student}.ethz.ch
#2 lore raw

2009/2/4 Thomas Rast <[email protected]>:

Quoted 8 lines
Quoted 6 lines · jemmyw

Hi. Awhile ago I copied some files in my local repo then commited. In another commit I deleted the original files, so essentially I did a mv that git doesn't know about. Now I'm trying to merge from another branch where changes have happened to the files in their original locations, and it's making the merge somewhat difficult. Is there a way to ease this?

Quoted 6 lines

Git never "knows" about a move, it only detects them after the fact. A corollary of this is that 'git mv a b' is more or less the same as 'cp a b; git rm a; git add b'.

Now since you have a copy followed by a removal in two separate commits, the merge logic won't treat this as a rename.

I don't think it holds. Git only sees the endpoints and the bases, it does not matter if the "move" was actually two commits. Maybe they have changed dramatically and git is not able to detect the rename (or the files are small). Another possible cause could be that you have a lot of renames (see config merge.renamelimit).

You could see if git detects the rename diffing differents commits:

$ git diff --raw -M commit1 commit2

if it does not detect you could use other limits as:

$ git diff --raw -M50 commit1 commit2

while commit1 and 2 are the endpoints or the merge base.

It could hep if you could provide a minimal test case, or at least the commands and output you get.

HTH,
Santi

#3 lore raw
Quoted 13 lines · Santi Béjar

2009/2/4 Thomas Rast <[email protected]>:

Quoted 12 lines
Quoted 6 lines · jemmyw

Hi. Awhile ago I copied some files in my local repo then commited. In another commit I deleted the original files, so essentially I did a mv that git doesn't know about. Now I'm trying to merge from another branch where changes have happened to the files in their original locations, and it's making the merge somewhat difficult. Is there a way to ease this?

Git never "knows" about a move, it only detects them after the fact. A corollary of this is that 'git mv a b' is more or less the same as 'cp a b; git rm a; git add b'.

Quoted 8 lines
Quoted 2 lines

Now since you have a copy followed by a removal in two separate commits, the merge logic won't treat this as a rename.

I don't think it holds. Git only sees the endpoints and the bases, it does not matter if the "move" was actually two commits. Maybe they have changed dramatically and git is not able to detect the rename (or the files are small). Another possible cause could be that you have a lot of renames (see config merge.renamelimit).

Hmm, you're right. I stand corrected.

Here's a sequence of commands that makes a test case:

git init
seq 1 10 > A
git add A
git commit -m initial
seq 11 15 >> A
git commit -m second A
seq 16 20 >> A
git commit -m third
git checkout -b side HEAD~2
cp A B
git add B
git commit -m copy
seq 3 10 > B # <--
git commit -m edit B
git rm A
git commit -m delete

Then running

git merge master

goes through cleanly, but changing the line indicated above to 'seq 5 10' makes it less similar, falling through the detection and causing a conflict. The minimum required similarity for merges does not seem to be configurable unfortunately.

Signature · 2 lines
Thomas Rast
trast@{inf,student}.ethz.ch
#4 lore raw

2009/2/4 Thomas Rast <[email protected]>:

[...]

Quoted 20 lines

Here's a sequence of commands that makes a test case:

git init
seq 1 10 > A
git add A
git commit -m initial
seq 11 15 >> A
git commit -m second A
seq 16 20 >> A
git commit -m third
git checkout -b side HEAD~2
cp A B
git add B
git commit -m copy
seq 3 10 > B # <--
git commit -m edit B
git rm A
git commit -m delete

Quoted 7 lines

Then running

git merge master

goes through cleanly, but changing the line indicated above to 'seq 5 10' makes it less similar, falling through the detection and causing a conflict.

Thanks, but that's known, this is why I wrote "or the files are small". I was not clear, but what I wanted was a *real* test case. In which cases this is a problem in practice.

Quoted 2 lines

The minimum required similarity for merges does not seem to
be configurable unfortunately.

No, but nevertheless it works fine most of the time, except with small files.

HTH,
Santi