hg automatic merges with diff3 - mercurial

Consider a Hg project with two central branches/clones - e.g. DEV and PRD. When someone pushes a hotfix to PRD, an automated script on the central server goes to DEV and pulls the new changes. It then tries to merge the hotfix into DEV.
The problem is that the merge tool integrated into Hg is terrible - as soon as there are parallel changes to the same file it will fail. Take the following example:
parent:3,7c
four
five
six
seven
child1:3,7c
four
five5
six6
seven7
child2:3,7c
fourmore
five
six
more
seven
As you can see, there are no actual conflicts here. If we do the merge locally with kdiff, it solves this simple case without user input!
I'd like a way to get the central server to manage these cases. I thought of using kdiff3 in silent mode, but I can't install kdiff3 on it (it's a CLI only system that we don't even have admin access to), but maybe there is a way to plug diff3 into hg merge so it can resolve simple cases like this? I tried setting "[ui] /n merge = diff3" in the hgrc, but it just spits out the three versions to stdout. Am i missing some additional configuration? Or is there an easier/better tool?
Thanks a lot

To use diff3 as your merge tool, you need to add
[merge-tools]
diff3.args = $local $base $other -m > $output
to your configuration file. You can set the priority if needed, see the wiki. You'll also find more complicated recipes for using diff3 there.
However, I tested how diff3 treats your scenario with edits on adjacent lines, and just like Mercurial, it also refused to merge this cleanly. Different merge tools have different thresholds for what they consider a "conflict" and it seems that KDiff3 is more forgiving than Mercurial and diff3.
I suggest that you let the developer who makes the hotfix on PRD be responsible for merging it into DEV locally where he has access to tools like KDiff3. Automated merging on a server is generally considered to be bad — merges should be verified just a little by a human before you commit them. It's not much extra work after having made the hotfix.

Related

How to merge in mercurial by TortoiseHG?

I have two machines, window 7 with TortoiseHG 2.6 and Linux with TortoiseHG 1.5. I use bitbucket as a website to hold my centralized repository. The window machine associates with bitbucket user account, Cassie-win and the linux machine associates with bitbucket user account, Cassie-linux. Here are the steps I have performed.
created a empty centralized repository at butbucket Cassie-linux account
create two files locally, file1.txt and file2.txt on linux machines and push them to the Cassie-linux account.
Add user Cassie-win to the repository
Clone the repository to the window machine, make changes on file2.txt there and push it back to the centralized repository.
Meanwhile, also make some changes on the file2.txt which is on the linux machine and commit locally
Then I pull changes from the centralized repository at Cassie-linux account to my local linux machine. Now my linux local repository has two heads because of different contents in file2.txt and I would like to merge them together.
I used the "merge with" tool of TortoiseHG on my linux machine to merge these two heads. However, it kept failing to do so. I tried like a hundreds times and didn't know where I got it wrong. Both file1 and file2 are test files that have only three lines. I also used a command "hg resolve file2.txt" to check the error. However, it only showed that mergeing fails and didn't shown much information. Does anyone know how to use TortoiseHG merge tool to merge two heads ? And what could be the problem to stop TortoiseHG merging two heads ?
I embedded the screenshot which I took on the Linux machine which has TortoiseHg 1.5.
I right clicked the "from Cassie-win account" and it has "merge with" option. Then, I clicked the "merge" option with "merge" tool but it failed with error messages as below.
Thank you very much,
By "merge with" in TortoiseHg, do you mean you tried "Merge with Local" from the context menu of one head after updating your working directory to the other head? If so, you should have seen a wizard taking you through the steps of a merge. TortoiseHg will expect you to intervene if it cannot automatically merge the two heads. Once it asks you to do that, you have a few options including "Mercurial Resolve" and "Tool Resolve."
If you could post more details about the errors you see when the merge "fails," we might be able to be more helpful.
First things first: A merge just creates a new file version. You must commit it before it can be seen or pushed to your other repo clones.
Now, if you're doing a merge and the same line, or adjacent lines, have been modified in both merge parents, the automatic merge won't succeed and you'll be asked to choose what to do at each conflict point. Kdiff3, the tool that TortoiseHG uses for merging the files on Windows is not terribly intuitive, so here's an overview:
If there are multiple files to merge, you'll see a directory control. Navigate to one of the files and open it so you see two file versions side by side.
Depending on the circumstances, you may now have to activate "Merge this file" (in the Merge menu and on the toolbar), which will show you a third version of the file (the merge result) below the other two.
You can now navigate from change to change, and click on the A and B buttons to select which change to use. Note that the buttons are toggles, and it is possible to activate both together (to import both versions to the merge). Note also that you'll also see diffs that could be automatically merged. In general you can leave them alone (there are navigation buttons that go directly to the next unresolved diff).
Once you've figured out how to work all this and chosen a version for each diff, you'll be able to save and go on to the next file. When you're done, your merge is ready to commit.
Edit:
So you need to do this on the Linux side, and you've got no Kdiff3. Ok, then do it the old-fashioned way: Using the commandline and a regular editor.
When a merge fails, the conflicted file turns into a context diff that includes both revisions. Open it with your favorite editor, look at it carefully and clean up each context-diff region (you'll know them when you see them) until you have a clean, usable file just as you want it to be.
Exit, drop to the command line and type hg resolve -m file2.txt. This removes the file from the list of conflicts.
When you've done this with all conflicted files (you can list them with hg resolve -l) you'll be allowed to commit, and your troubles are over.
PS. If you don't like the merge tools you've got, consider installing kdiff3 (it's available for linux, but no idea how well it works), or p4merge as #LazyBadger suggests.
Side notes
You can exchange data between your hosts without "Bitbucket-in-the-middle": just hg serve on both hosts and hg pull <PARTY> on opposite side
You could use single BB-account from both our hosts (less management on BB-side) and differentiate source of every changeset in Bitbucket interface only by usernames in changesets
To the question of merges
When (in any SCM) you try to merge two diverged lines of coding, there are two possible cases
Independent changes are not overlapped and can be combined into common descendant without user's intervention. If this case merge "just happens"
Changes are intersected and some strings are in conflicted state: i.e we have two different changes for some old data. It this case user's choice is needed and SCM or store merge-result with conflicted parts marked (and note merge as unsucceful and unfinished before appropriate user-action) or run user-defined merge-resolver (read "Visual Merge Tools")
In your situation, obviously, he have second case: some strings from 3 in merge-sources was in conflict and you haven't configured in TortoiseHG Diff/Merge tools (TortoiseHG - Global Setting - TortoiseHG)
Have and add these tools will be best choice for future. Now you have by hand edit file-in-conflict and select correct data in conflicted lines, mark conflict as resolved (check TortoiseHG context menu of file), remove temp-files and, at last, commit merge

Have Mercurial use a custom merge tool for its own merges

Mercurial docs about what mercurial does when it has to do a 3way merge:
By default, Mercurial will attempt to do a classic 3-way merge on text
files internally before trying to use an external tool.
When it invokes the external tool, that is always a "manual merge".
Not all merge tools are created equally, and as it turns out my merge tool of choice (Araxis Merge), is often able to do an automatic merge of 3 files, where mercurial's internal merge tool was not able to do so.
This leads to the scenario of big merges where maybe a bunch of files merge cleanly, done by hg's internal mergetool, and then some other files do not merge cleanly but could have if hg would let me specify its mergetool. I find this to make big merges very inefficient, as you need to context switch a lot: hg pops up my merge tool, I think "oh darn, conflict", to then realize "oh wait, theres no conflict at all"
I wonder if I'm missing something here, or if there is really no way to make hg able to use a custom merge tool for its automatic attempts at doing merges.
I think you're looking for a switch to make Araxis Merge close itself automatically if it can auto-merge. I looked at the command line reference and their SCM integration document, but I'm actually not sure what switch it would be. You'll have to experiment yourself.
From Mercurial's point of view there is no such thing as a "manual merge". Mercurial tries to merge internally first (the so-called "premerge" step) and if that fails it looks for an external tool. The merge can still be fully automatic if that tool exists with an exit code of zero (successful exit). Mercurial will then consider the merge successful and go on to the next file. Depending on the tool, you wont notice this at all: Mercurial just runs the tool in the background and you're only prompted for action when there is a serious merge conflict.
You can use a custom merge tool with Mercurial. help merge-tools shows the order in which tools are chosen to run:
1. If a tool has been specified with the --tool option to merge or
resolve, it is used. If it is the name of a tool in the merge-tools
configuration, its configuration is used. Otherwise the specified tool
must be executable by the shell.
2. If the "HGMERGE" environment variable is present, its value is used and
must be executable by the shell.
3. If the filename of the file to be merged matches any of the patterns in
the merge-patterns configuration section, the first usable merge tool
corresponding to a matching pattern is used. Here, binary capabilities
of the merge tool are not considered.
4. If ui.merge is set it will be considered next. If the value is not the
name of a configured tool, the specified value is used and must be
executable by the shell. Otherwise the named tool is used if it is
usable.
5. If any usable merge tools are present in the merge-tools configuration
section, the one with the highest priority is used.
6. If a program named "hgmerge" can be found on the system, it is used -
but it will by default not be used for symlinks and binary files.
7. If the file to be merged is not binary and is not a symlink, then
"internal:merge" is used.
8. The merge of the file fails and must be resolved before commit.
More information can be found in help config - look for merge-tools and merge-patterns

How resolve this Mercurial conflict?

I'm frustrated with Mercurial and Python since it makes easy things difficult. I have a trivial conflict and since Mercurial does not give any suggestion what to do I don't know even how to resolve this trivial file conflict:
The conflict is trivial but if I can't resolve this I can't resolve anything complicated either. Can I just edit the file to a way I want and commit it again from anywhere? Should I run hg merge? Why can't Mercurial even let me choose a version to keep? Why is something trivial near impossible to do without digging through 1000 poorly written manpages?
You need to look at the KDiff3 documentation, in particular the section on merging and the output window. To resolve the conflict, you need to decide if live or january is the right choice for the line. That decision is yours to make, no tool can know if you meant one or the other.
In KDiff3, you press Ctrl + 2 to select live, press Ctrl + 3 to select january or right-click in the margin of the bottom window and select the line you want. You can also click in the bottom window and edit the line manually.
Mercurial let's you configure your merge tool any way you like. TortoiseHg ships with a default configuration that puts KDiff3 in the top of the list, but you can use another tool if you like. A merge tool is really just a program that accepts four filenames: the three files to compare (base, parent 1, parent 2) and an output file name.
To resolve conflicts on the command-line you need to launch a suitable command-line three-way merge tool. You can for example merge with vim if you like. (I'm afraid I don't know anything about vimdiff, I use KDiff3 myself.)
If you don't like to see merge tools pop up, then you can set
[ui]
merge = internal:merge
to make Mercurial use the internal three-way merger only. It will merge files fine when the edits are not in conflicts. When there is a conflict, the file is marked as "unresolved" and conflict markers are stored in the file.
You then need to edit the file by hand to get the version you want. You can also re-merge and pick either the local (your) version:
$ hg resolve --tool internal:local your-file
or the other version:
$ hg resolve --tool internal:other your-file
You restart the merge completely with hg resolve your-file. The file needs to be marked "resolved" before you can commit it. This is done with hg resolve --mark your-file. See hg resolve --list for the status of the current merge.
Base is the previous version in your local system,
Parent 1 is your current changes,
parent 2 is the file from server.
If you need your changes need to be checked in, select B everywhere in the merge menu.
If you want the latest server version in your local machine, select C everywhere in the merge menu

How to store my binary assets with Mercurial?

I'm starting a game development project and my team and I will be using Mercurial for version control and I was wondering what a more appropriate way to store the binary assets for the game would be. Basically, I have 2 options:
Mercurial 2.1 has the largefiles extension, but I don't know too much about it. It seems like it'll solve the 'repository bloat' problem but doesn't solve binary merge conflict issues.
Keeping the binary assets in a SVN checkout, as a subrepo. This way we can lock files for editing and avoid merge conflicts, but I would really like to avoid having to use 2 version control systems (especially one that I don't really like that much).
Any insight/advice or other options I haven't thought of?
As you surmised large files will do what you need. For merging binaries you can set up a merge tool if one exists for your file type. Something like this:
[merge-tools]
mymergetool.priority = 100
mymergetool.premerge = False
mymergetool.args = $local $other $base -o $output
myimgmerge = SOME-PROGRAM-THAT-WILL-MERGE-IMAGES-FOR-YOU
[merge-patterns]
**.jpg = myimgmerge
**.exe = internal:fail
In general though, merging non-text things will always be a pain using a source control tool. Digital Asset Management applications exist to make that less painful, but they're not decentralized or very pleasant with which to work.
You're correct that the largefiles extension will avoid bloating the repository. What happens is that you only download the large files needed by the revision you're checking out. So if you have a 50 MB file and it has been edited radically 10 times, then the versions might take up 500 MB on the server. However, when you do hg update you only download the 50 MB version you need for that revision.
You're also correct that the largefiles extension doesn't help with merges. Infact, it skips the merge step completely and only prompts you like this:
largefile <some large file> has a merge conflict
keep (l)ocal or take (o)ther?
You don't get a chance to use the normal merge machinery.
To do locking, you could use the lock extension I wrote for a client. They wanted it for their documentation department where people would work with files that cannot be easily merged. It basically turns Mercurial into a centralized system similar to Subversion: locks are stored in a file in the central repository and client contact this repository when you run hg locks and before hg commit.

Branching with Mercurial SCM

So right now I'm learning Ruby on Rails, and I'm working through the book "Agile Web Development with Rails". I've also decided that I want to give Mercurial a go, because I've read up on distributed SCM's, and it seems like an ideal situation. I still, however, prefer to push my code remotely to my Linux VPS just incase my hard drive decides to take a dive.
So, my question is specific to branching in Mercurial. Right now I've got a remote repository set up and I can push changes over SSH easily (hell I even set up an Nginx FastCGI site that lets me push, too). What I'd like to do, however, is create branches for each chapter as I work on them, so I can keep a nice organized history of my progress through the book. So this is what I'm doing:
$ hg branch chapter-10
(do chapter 10 stuff)
$ hg commit -m "Chapter 10 complete"
$ hg update default
$ hg merge chapter-10
$ hg commit -m "Merging chapter 10 into default"
$ hg push
Once I execute the push statement, I get this message from Mercurial:
pushing to ssh://myserver/hg/depot
searching for changes
abort: push creates new remote branch 'chapter-10'!
(did you forget to merge? use push -f to force)
So at this point I try to do an hg merge again, and it tells me there's nothing to merge, which is obviously true because I just merged it. When I force the push with -f, everything seems fine, and even the web interface shows the appropriate branches.
To sum up, my question is simple: Am I doing this the right way? Is there a more appropriate way to do this with Mercurial (i.e. the "Mercurial way")? Honestly I just want the repository to serve as a backup. I'm a fan of the distributed SCM model, but to me it feels sorta "dirty" to force pushes. Any insight is greatly appreciated! Thanks in advance.
The push -f is the right option for your case, and there was a discussion last month to add that command when this "push creates new remote branch" warning pops up: see issue 1513.
However, issue 1974 (this month) mentions some undesirable effects (not in your case though).
See this translated article to know more about creating a second head on a remote repo.
On the more general point, you can use branch if you are writing your chapter in parallel, and you want to merge them only at certain (stable) point in time
But if your writing process is more linear, you could use only one branch, and put some tags along the way.
However, should you go back to chapter 10 and add some lines, even though you already put tags 11 and 12, that would make the history harder to read. So branches are still a good idea in this case.
I don't know about your specific problem, but from your comments it seems that you use branches where you probably wanted to use tags.
Branches are generally used when multiple people cooperate on the same project and you want to create a work separation so one person can work on a stable piece of code, while the other does something experimental that temporarily breaks functionality. Alternatively branches are used to stabilize for release, while development is going on in trunk.
Tags (or labels) are used to primarily create a marker signifying some importance to the version of code. Like for example if you want to mark a completion of chapter 10, you just tag all current versions with a 'chapter-10' tag. There is no need to branch. You can branch from a tagged version at any point in future if it would be necessary for some reason.
In this case I feel that it's totally ok to use -f for the push. It just creates new branches, not heads. Creating remote heads is another matter entirely.