Mercurial internal:merge and binary file conflicts - mercurial

Folks, I'm using internal:merge tool since I'm not a big fan of GUI diff tools. I really like it and the only thing I find a bit confusing and not quite convenient is its behavior for binary file conflicts.
It can't merge binary files and exits which is absolutely correct. However in the directory with the conflicting file "foo" it creates only "foo.orig" file.
Can it at least create "foo.other" as well so I can pick which version of file to use(mine or the pulled one)?
P.S. I asked the same question in Mercurial mailing list but noone replied me for several days, maybe I'll have more luck here :)

You have already gotten some input to your question on the Mercurial mailing list -- I went ahead and tried making the script suggested in the thread. It's been a long while since I've used Subversion, but I think this simple script does the trick:
#!/bin/sh
cp "$1" "$1.mine"
cp "$2" "$1.base"
cp "$3" "$1.other"
false
The final false command makes the script return a non-zero exit code, signaling to Mercurial that the merge failed. For Windows it looks like this (thanks Pavel):
#copy %1 %1.mine
#copy %2 %1.base
#copy %3 %1.other
exit 1
I saved the Unix version in ~/tmp/m.sh and tried it with no other merge settings configured than
[ui]
merge = ~/tmp/m.sh
I made a repository with two heads, each with a conflicting change to a JPEG file (mg.jpg). I also added a non-conflicting change to a text file (a.txt). Merging gave:
% hg --debug merge
searching for copies back to rev 1
resolving manifests
overwrite None partial False
ancestor 0848c2f8f8f8 local 845b8aa076bd+ remote f611c55aa8ec
mg.jpg: versions differ -> m
a.txt: versions differ -> m
preserving a.txt for resolve of a.txt
preserving mg.jpg for resolve of mg.jpg
picked tool '~/tmp/m.sh' for a.txt (binary False symlink False)
merging a.txt
my a.txt#845b8aa076bd+ other a.txt#f611c55aa8ec ancestor a.txt#0848c2f8f8f8
premerge successful
picked tool '~/tmp/m.sh' for mg.jpg (binary True symlink False)
merging mg.jpg
my mg.jpg#845b8aa076bd+ other mg.jpg#f611c55aa8ec ancestor mg.jpg#0848c2f8f8f8
merging mg.jpg failed!
0 files updated, 1 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
The nice thing is that the pre-merge could merge a.txt by itself and so no a.txt.* files were created:
% hg stat
M a.txt
M mg.jpg
? mg.jpg.base
? mg.jpg.mine
? mg.jpg.orig
? mg.jpg.other
You can probably fine-tune this script further to suit your needs -- if you do so, then consider adding the information to the Mercurial wiki or at least post your finding on the mailing list.

Related

Why don't mercurial file sets work when adding files?

I'm trying to use mercurial file sets to add all the files in a directory tree, excluding very large files and any binary files. Cribbing from the mercurial documentation, this command should do it:
hg init
hg add 'set: size("<1M") and not binary()'
However this returns a status code of 0, and hasn't added anything to my new, empty repo. I've tried just 'set: not binary()' and that didn't work either.
The frustrating thing is that although I can google for mercurial file sets, and find lots of examples, I can't find anything to help troubleshoot when it doesn't work!
I don't have a .hgignore file, and it's a fresh empty repo. Mercurial 4.2.2.
The directory where I'm testing this has a couple of artificially created files for the purpose of testing. In my real use case, I inherit a multi-gigbyte tarball of assorted sources and binaries from a client, and I want to get all the sources into mercurial before I start hacking to fix their problems, hence the need to exclude the binaries and large files that otherwise choke mercurial.
Here's my little test script:
#!/bin/sh -ex
dd if=/dev/urandom of=binary_1k bs=1 count=1024
dd if=/dev/urandom of=binary_2M bs=1 count=2097152
echo "This. Is, a SMALL text file." > text_small
hexdump binary_1k > text_1k
hexdump binary_2M > text_2M
ls -lh
file binary_1k
file binary_2M
file text_1k
file text_2M
hg init
hg add 'set: size("<1M") and not binary()'
hg status -a
hg add 'set: not binary()'
hg status -a
hg add 'set: size("<1M")'
hg status -a
At the end of this, each status command reports no files in the repo, and the add commands report no errors.
The problem is that file sets do a query of Mercurial's repository data base, which knows only about files that are part of the repository or have been added.
One solution is to add all, and then to get rid of the files that you don't like, e.g.:
hg forget 'set:size(">1M") or binary()'
This works, because the query also requires recently added files, even if they haven't been committed yet.

Mercurial creates unversioned copies of files during update to different branch

A little while ago I noticed that hg started creating unversioned copies of files in the repository at seemingly random times when I update between branches. I can't for the life of me think of what I might have changed for this to start happening. There is nothing in the verbose or trace output to indicate that these files are being created.
The new unversioned filenames all end with what seems to be a random string added to the end of the extension:
file1.txt-23121dd1
someotherfile.sql-bc769bd2
bizarrofile.cs-40a93ed0
hgisinvadingurhead.ppt-f8e9015a
When trying to determine the pattern of this happening I've noticed the following:
The added characters in the filenames do not correspond with any changeset ID in the repository. I have done a grep -i to the output of hg history and the string in the filename does not appear anywhere in the output.
In all cases the files existed in the branch I was working on but do not exist in the branch I update to.
Sometimes it's only one or two files, sometimes it's several.
It is never the case that these are all of the files that exist in one branch but not the other.
It is never the case that it is the same set of unversioned files between updates.
Others on my team who are cloning the same repositories do not seem to be experiencing this
I thought maybe it was something within the repository but it also happens in other existing repositories and in brand new ones as well.
For example, I have done this (hg output omitted except for hg status output at the end, but no errors come from the output):
c:\> mkdir repo
c:\> cd repo
c:\repo\> hg init
c:\repo\> echo default > default.txt
c:\repo\> hg add
c:\repo\> hg commit -m "Commit default"
c:\repo\> hg branch branch1
c:\repo\> echo branch1 > branch1.txt
c:\repo\> hg add
c:\repo\> hg commit -m "Commit branch1"
c:\repo\> hg update default
c:\repo\> hg status
? branch1.txt-23121dd1
This is not repeatable every time. I could repeat these steps and sometimes the unversioned file will be there at the end and sometimes it won't. It's very sporadic. In larger repositories, though, I almost always see at least one unversioned file between branch updates.
Full output of hg update default follows. The output always displays as such whether or not the unversioned file is created.
resolving manifests
calling hook preupdate.eol: <function preupdate at 0x0000000002571668>
removing branch1.txt
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
I was using an older version of hg when I first noticed it but the problem still exists after updating to 2.3.2. I am using Windows 7 Pro x64 with TortoiseHG 2.5.1 x64. I don't think it's related to Tortoise, however, because I can replicate the problem by just using hg from the command line.
The contents of my mercurial.ini file are:
[ui]
username=myname <myname#mydomain.com>
ignore=C:\users\myusername\.hgignore
verbose=true
trace=true
[eol]
native = CRLF
only-consistent = False
[extensions]
purge =
eol =
I can live with it, but it's a pain to make sure I'm not accidentally adding these files to the repository in changesets with other new files.
If someone has seen this and could point me to the culprit I'd be most appreciative!
If a file is in use when updating between changesets, the in-use file is renamed with the added numbers so the update can succeed.
Does disabling the eol extension help matters? I noticed that your test did not use a .hgeol file as well (that's one of the things associated with this extension). There's another thread hereabouts that is dedicated to some problems with this extension.

Mercurial requiring manual merges unexpectedly

I've got a project running under Mercurial and am finding a lot of situations where a file needs manually merging, when I believe it should be able to merge automatically. I am wondering whether there are any options that can be given to Mercurial to help it out in these areas.
The project has an underlying platform with a couple of hundred files that can't be edited on the project. When the platform is updated, the project gets updated versions of these core files outside of Mercurial. The sequence I'm seeing repeatedly is:
On central dev system (linked to the core platform update mechanism):
Get a new version of core platform.
Commit these changes e.g. hg commit -m "New platform release"
Push to central mercurial server
On my Linux box:
Commit local changes
Pull from central mercurial server, and try to merge
Find merge conflicts on core files
The last two core files I've had to merge have no changes between the base and local versions (the access time is updated during a build, but the content is the same). The only changes are on the remote revision I'm merging with.
The only non-standard configuration I'm aware of is that the central mercurial instance is running under Rhodecode, with a commit hook setup to update a Redmine repository.
Is there anything else that can be configured in mercurial to help it figure out merges?
You can redo a merge with --debug to get more information about a merge. That is, take your repository and do
$ cd ..
$ hg clone my-project -r 123 -r 456 merge-test
where 123 and 456 is the two parents of the merge you want to examine closer. Then run
$ hg merge --debug
to see what Mercurial says. It should look like this if the file foo has only been changed in the branch you're merging in:
$ hg merge --debug
searching for copies back to rev 2
resolving manifests
overwrite: False, partial: False
ancestor: 932f5550d0ce, local: b0c286a4a76d+, remote: c491d1593652
foo: remote is newer -> g
updating: foo 1/1 files (100.00%)
getting foo
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
Here I was on revision b0c286a4a76d and merged with c491d1593652.
You can also use
$ hg status --rev "ancestor(b0c286a4a76d, c491d1593652)" --rev "c491d1593652"
M foo
$ hg status --rev "ancestor(b0c286a4a76d, c491d1593652)" --rev "b0c286a4a76d"
M bar
to double-check which files have been changed between the ancestor revision and the two changesets you're merging. Above you see that I changed foo on one branch and bar on the other.
If you see a platform file appear in both status lists, well then something went wrong in your procedures and this can explain the merge conflicts.
If this isn't enough to figure out what went wrong, then I suggest asking this question on the Mercurial mailinglist. That's a great place for discussion and bug-hunting — much better than Stack Overflow.

tortoisemerge with Hg reports all lines as changed

I'd like to use TortoiseMerge with Mercurial to resolve conflicts, but its reporting every line in theirs and mine as added as though its not comparing properly
here is my mercurial.ini:
[ui]
merge = TortoiseMerge
[merge-tools]
TortoiseMerge.executable=C:\Program Files\TortoiseSVN\bin\TortoiseMerge.exe
TortoiseMerge.args=/mine:$local /theirs:$other /base:$base -o /merged:$output
I'm using Hg 1.7.5
What's going on?
Update: When using KDiff or BeyondCompare, the base is always empty.
Thanks
Your setup appears correct.
This is symptomatic of having no copy of the file in the base revision, in which case Mercurial acts as if the file was present but empty.
There are a couple ways of figuring out what's going on here. If there are no copies or renames involved, you should be able to simply do:
$ hg log -r "ancestor(p1(), p2())"
..to determine the ancestor of the merge, then:
$ hg manifest -r <rev> | grep <your file>
..to determine if the file was in fact present.
Alternately, you can run 'hg merge --debug' or 'hg update --debug' to see what changeset and file it's choosing for the merge (including rename/copy details).
If you find that the file is present in the common ancestor Mercurial chooses, then you should report a bug (including your debug output) at:
https://www.mercurial-scm.org/wiki/BugTracker

Mercurial: how to merge changes to a file that's renamed in the other branch?

I have a Mercurial repository with four branches in it. One is the "common" branch, the other three are "specific" branches which consist of some cosmetic changes applied to the common branch. One of those cosmetic changes consisted of renaming some files.
So the common branch has "file.txt", and the first specific branch has "file-01.txt" which is the same file, used for the same purpose but has a different name and slightly different contents. It was renamed to file-01.txt on the specific branch, and "hg log -f file-01.txt" correctly shows the history going back to before the rename.
When I make a change to file.txt on the common branch, I need to be able to merge that change into file-01.txt on the specific branch. But Mercurial doesn't understand that the files are the same. It tells me:
remote changed file.txt which local deleted
use (c)hanged version or leave (d)eleted?
If I pick "c" then I get a new file.txt containing exactly what's in the common branch's version. If I pick "d" then the change isn't merged at all.
What can I do to get this right?
EDIT: I can make it work correctly in a fresh test repository, but not my actual repo. Here's what I get (note that rev 118 is on the specific branch, just before the original rename, so I'm going through the rename process again to illustrate):
C:\...> hg update -C 118
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
C:\...> hg merge default
merging file.txt
merging anotherfile.txt
0 files updated, 2 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
So it works without the rename. But if I rename, it fails:
C:\...> hg update -C 118
2 files updated, 0 files merged, 0 files removed, 0 files resolved
C:\...> hg rename file.txt file-01.txt
C:\...> hg commit -m "renamed"
created new head
C:\...> hg merge default
remote changed file.txt which local deleted
use (c)hanged version or leave (d)eleted?
EDIT 2: Here's what I get at that last step from hg merge --debug default:
searching for copies back to rev 115
unmatched files in local:
file-01.txt
all copies found (* = to merge, ! = divergent):
file-01.txt -> file.txt
checking for directory renames
resolving manifests
overwrite None partial False
ancestor 9d979018c2df local f842fdbc252b+ remote 05fc75e480da
anotherfile.txt: versions differ -> m
remote changed file.txt which local deleted
use (c)hanged version or leave (d)eleted?
I ended up tracking the problem down to one particular revision in the history: I could merge across the rename as long as that revision wasn't involved. Still not sure what went wrong with that revision, but I redid the changes and it's working now.
The problem is with how you handled the rename in the branch. From the looks of it you (or your GUI) did a 'remove' on the old name, file.txt, and then did an add of a copy of that file named file-01.txt.
When you do it that way, mercurial has no idea they're linked. If, however, you had, in the branch, used the command:
hg rename file.txt file-01.txt
then rather than the message you're seeing the changes from file.txt would be applied to file-01.txt. However, without your help mercurial can't know they're linked.