12
  1. I have a file, foo.txt
  2. Create and checkout branch 'branch_A'
  3. git mv foo.txt bar.txt followed by git add -A then git commit -m "renamed foo.txt"
  4. Checkout master, git checkout master
  5. remove foo.txt and commit.
  6. Now merge branch_A, git merge branch_A

And with this, I get an merge conflict (rename/delete).

CONFLICT (rename/delete): Rename foo.txt->bar.txt in branch_A and deleted in HEAD

This makes sense and is what I'd expect. However, I'd like to know if there is a way for git merge to not detect renames, but instead treat them as added/deleted. In this case, I'd expect git to detect that foo.txt was deleted and simply add bar.txt. No conflict.

I've tried using -X rename-threshold, but it has not worked for me. I've tried thresholds 0 and 120 (a number above 100). What am I missing?

Thanks!

P.S. I'm also getting error: refusing to lose untracked file at... errors. What does this mean?

Ken Hirakawa
  • 7,831
  • 10
  • 38
  • 49
  • 1
    `error: refusing to lose untracked file at...` could be the result of merging `bar.txt`, which was tracked in `branch_A` but untracked in `master`, assuming that it exists in your working directory – Chris Frederick May 16 '11 at 04:57
  • 1
    With git 2.8 (March 2016), you will have the option of doing a `git merge --no-renames`. See [my answer below](http://stackoverflow.com/a/35672618/6309) – VonC Feb 27 '16 at 16:59
  • 2
    With Git 2.18 (Q2 2018), you have the option of `git config merge.renames false`. See [my updated answer below](https://stackoverflow.com/a/35672618/6309). – VonC Jun 03 '18 at 21:31

2 Answers2

10

Update Sept. 2021:

The 2016 option mentioned below is now obsolete, and replaced by the new merge strategy ORT ("Ostensibly Recursive's Twin"), which does a much better job handling rename detection.

The primary difference noticable here is that the updating of the working tree and index is not done simultaneously with the merge algorithm, but is a separate post-processing step.

The new API is designed so that one can do repeated merges (e.g. during a rebase or cherry-pick) and only update the index and working tree one time at the end instead of updating it with every intermediate result.

Also, one can perform a merge between two branches, neither of which match the index or the working tree, without clobbering the index or working tree.

The "ort" backend does the complete merge inmemory, and only updates the index and working copy as a post-processing step.

Starting with Git 2.34 (Q4 2021), this will be the default.
In the meantime:

git merge -s ort MyBranch-to-merge
          ^^^^^^

2016:

With git 2.8 (March 2016), you will have another option (as an option to the recursive merge strategy)

git merge -Srecursive -Xno-renames

See commit 44c74ec, commit 2307211, commit 63651e1 (24 Feb 2016), commit 2307211, commit 63651e1 (24 Feb 2016), commit 87892f6, commit 83837ec (21 Feb 2016), and commit 1b47ad1, commit d2b11ec (17 Feb 2016) by Felipe Gonçalves Assis (asiz).
(Merged by Junio C Hamano -- gitster -- in commit 4ce064d, 26 Feb 2016)

merge-recursive: option to disable renames

The recursive strategy turns on rename detection by default.
Add a strategy option to disable rename detection even for exact renames.

The man git-merge will include:

no-renames

Turn off rename detection.
See git diff --no-renames.

(Note, as seen in commit 1b47ad1, the find-renames merge strategy, following git diff interface, makes the option rename-threshold redundant starting with git 2.8)


You have an additional setting with Git 2.18 (Q2 2018): with the merge.renames configuration set to false, the recursive merge strategy can be told not to spend cycles trying to find renamed paths and merge them accordingly.

See commit 6f10a09, commit 85b4603, commit a7152e9 (02 May 2018) by Ben Peart (benpeart).
(Merged by Junio C Hamano -- gitster -- in commit 6e2ba77, 30 May 2018)

merge: add merge.renames config setting

Add the ability to control rename detection for merge via a config setting.
This setting behaves the same and defaults to the value of diff.renames but only applies to merge.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • was this removed in 2.9? The git maintainers ppa of stable releases does not have this flag AFAICT. – ThorSummoner Jun 24 '16 at 22:10
  • 1
    @ThorSummoner I agree. It is actually an option to a merge strategy. I have edited the answer. – VonC Jun 24 '16 at 22:23
  • @VonC: may I offer 2 tiny edits: add hyphen in git-merge; drop double-hyphen before no-renames. Should say: "The man git-merge will include: no-renames" – chrisinmtown May 10 '17 at 12:59
  • @chrisinmtown Thank you. I have edited the answer accordingly. – VonC May 10 '17 at 13:36
10

Can you try with:

git merge -s resolve branch_A

This will enable resolve merge strategy, which does not try to detect renames:

resolve

This can only resolve two heads (i.e. the current branch and another branch you pulled from) using a 3-way merge algorithm. It tries to carefully detect criss-cross merge ambiguities. It does not handle renames.

Also, have you tried looking at similar questions here:

git rename/delete confusion

git divergent renaming

mik
  • 3,575
  • 3
  • 20
  • 29
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • 5
    This really needs more explanation – Liam Nov 21 '18 at 16:40
  • Basically I had `file.txt` that I had modified and move to the `foo` subdirectory, and then backtracked in history and used the same `file.txt` as a starting point to modify it and move it to a `bar` directory. Then I tried to merge the two branches, wanting to wind up with separate `foo` and `bar` versions of the file with a history going back to the same source. Using `-s resolve` as @manojlds indicated worked beautifully, but as Liam mentioned, it really does need more explanation. But thanks so much manojlds for the answer. – Garret Wilson Mar 20 '19 at 00:12