Mercurial requiring manual merges unexpectedly - mercurial

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.

Related

Mercurial diff/patch by example

I have read only permission to an hg repo and am trying to develop and test changes to it locally. The problem is that I am in the middle of changing dev machines and am caught in a weird/akward state across the two machines.
On my old machine I made lots of changes to the repo, locslly. I just cloned the repo on my new machine, but obviously that doesn't contain the changes from my old machine. I need a way to createe a patch/diff from my local working copy on my old machine, and then apply them to my local working copy on my new machine. The problem is that I already commited (hg commit -m "Blah") the changes on my old machine to the distributed repo on it.
What set of specific commands can I use to create a patch/diff of my old machine and then apply it to the repo on my new one?
Update
I commited all changes on my old machine and then ran hg serve, exposing http://mymachine.example.com:8000.
On my new machine, where I had made some different changes (locally) than the changes from my old machine, I ran hg pull http://mymachine.example.com:8000 and got:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg pull http://mymachine.example.com:8000
pulling from http://mymachine.example.com:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 16 changes to 10 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
So I run hg merge:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg merge
abort: uncommitted changes
(use 'hg status' to list changes)
What do I do now?!?
You can use:
$ hg diff > changes.patch
To create a patch file, then:
$ patch -p1 < changes.patch
To apply that patch file on your new machine.
Well, that's actually fantastic, mercurial is a distributed version control system and you do not need to go via any patch file at all: simply pull the changes from your old machine to your new machine:
hg pull URL
where URL can be any network URL or also ssh-login, e.g.
hg pull ssh://mylogin#old.maschine.box or hg pull path/to/old/repository/on/nfs/mount
`
Alternatively you can also use bundle and unbundle. They create bundles which can be imported in the new mercurial easily and keep all meta-information.
hg bundle -r XXX --base YYY > FILENAME
where YYY is a revision you know you have in your new repository. You import it into your new repo with hg unbundle FILENAME. Of course you can bundle several changesets at once by repeating the -r argument or giving a changeset range like -r X:Y.
The least comfortable method is a via diff or export:
hg export -r XXX > FILENAME or equivalent hg diff -c XXX > FILENAME where you need to import the result with patch -p1 < FILENAME or hg import FILENAME.
The easiest way is to do this is to ensure that all work on your old machine is committed. Then use this command on it from the base of your repo:
hg serve
which creates a simple http server on this repo. The monitor should state the name of the http URL it is serving.
On your new machine, just pull from that URL.
Once you've pulled your old changes you can stop the hg serve process with ^C.
The advantages of this method are that it is very quick, and that it works on just about any system. The ssh method is also quick, but it won't work unless your system is configured to use ssh.
Answer to Update
The OPs update is asking an orthogonal question about how to merge changes pulled from a server with local changes. If you haven't already done so, try to digest the information in this merge doc and this one.
Merging is for merging changesets. The error is happening because you have local changes that haven't been committed which mercurial can't merge. So the first thing to do is to commit your local changes, then you will be able to merge.
But before you merge, I strongly recommend that you are merging what you think you are merging. Either ensure there are only 2 heads, or specify which head you are merging with. When merging, you have to be at one of the heads you wish to merge; it's usually better to be at the head with the most changes since the common ancestor because the diffs are simpler.
After you've merged, don't forget to commit the merge. :-)

Mercurial merge repository as branch

I have two Mercurial repositories that are for different major revisions of the same project. The latter version is a massive change to the functionality, and especially the UI, of the project, but it will still have a lot of common code with the earlier version. (For shorthand I'll call these versions 4.6 and 5.0 and the repositories project-4.x and project-5.x going forward; that's basically what I'm dealing with.)[1]
As we thought more carefully about the structure of our repository, and thinking especially about how to handle the related code, it became apparent that we wanted to simply pull the repositories together and used named branches for the ongoing work in each (from which people can branch or bookmark and merge as necessary). To do that, we decided we basically need to pull the project-5.x repository into the project-4.x repository. From what I can see, combining the repositories should be fairly straightforward:
$ hg pull -f project-5.x # in project-4.x
$ hg merge
So far, so good. My concern is handling the branching issue.[2] These are going to come in as two completely unrelated chains (which is fine), but I'd like the branch structure to look something like this:
---4.6----- }
\ } original project-4.x
5.0----- }
/
------- } original project-5.x
The problem is, I'm not exactly sure how to do it.
Edit: See below; the answer I devised worked.
Footnotes
If you're wondering why this is only coming up now… well, the project only got version controlled as of starting 4.6. Which, yes, is a little bit crazy. And I'd never been in charge of a major version change like this before, so I decided originally to make a new repo entirely, which I of course now regret. Live and learn.
Answers I've already read on the subject (but which left me unsure how to do this exactly):
Mercurial - merging branches
How do I merge two Mercurial repos into a single one
How can I import a mercurial repo (including history) into another mercurial repo as a subdirectory, without using subrepos?
I originally thought I'd need some way to pull into just the branch, but after chewing on it some more, I concluded the best way to do this is roughly as follows:
Create the desired new branch structure (i.e. create the 4.6 and 5.0 branches).
Remove the old default branch into the 4.6 branch in the base repository.
Pull the project-5.x repository into the project-4.x repository.
Merge the default (or in the case of this repository, experimental) baseline, which is pulled in during the merge, into the 5.0 branch, closing out the experimental branch along the way.
Restrict write access to the old repository's central push/pull location; we still have it for historical reasons, but people can't accidentally push to it.
Preparation (steps 1–2)
$ cd <project-4.x directory>
$ hg branch 4.6
$ hg ci -m "New 4.0 baseline"
$ hg branch 5.0
$ hg ci -m "New 5.0 baseline"
$ hg up default
$ hg ci --close-branch -m "Close default branch going forward.
$ hg up 4.6
$ hg merge default
$ hg ci -m "branch merge default -> 4.6"
At this point, the repository is set up: it has the new baseline branches and has removed the old default branch we wanted to get rid of.
After this, I made the changes to get the repository structure looking more the way it needed to for the 5.0 branch in the project-4.x repository (since massive restructuring is part of the version change effort).
Repository merge (steps 3–4)
The next step was actually merging the repositories together and pushing the content from the old repository into the desired branch.
$ hg pull -f <path to project-5.x repository> # still in project-4.x repository
$ hg merge -m "Merge in project-5.x repository"
$ hg up experimental # experimental is the name of the "default" branch
$ hg ci --close-branch -m "Close experimental branch"
$ hg up 5.0
$ hg merge experimental
$ hg ci -m "Merge old experimental into new 5.0 baseline"
This proceeded perfectly, with no merge conflicts whatsoever (except that I needed to resolve some small differences in my .hgignore file).

switch branches in hg while preserving files

While developing my software i create a set of test-cases which an be automatically done via make tests. To keep things organized i put those in a sub-directory tests. To keep my commits organized as well and not to clutter my development branches, i created an extra branch tests where i commit the test units.
My problem is: when i commit the units to the test branch and switch back to development, said tests are deleted
D:\Project>hg branch test
D:\Project>edit...
D:\Project>hg add
D:\Project>hg commit
D:\Project>hg up dev
2 files updated, 0 files merged, 3 files removed, 0 files unresolved
How can i preserve those files?
(i tried the solution for Mercurial: Switch working directory to branch without losing changes? but it still deletes the files)
EDIT See my own answer below
Those test files don't exist in your development branch, so when you check out the development branch they won't be in the working directory. DVCSs like Mercurial and git don't let you have one directory checked out at one revision/branch and another one at another revision/branch.
The answers to which you linked are for bringing the changed and their files over into another branch, they're not what you're asking for.
So the way you want to do it (separate branches) isn't going to work, but there are plenty of other/better options
One choice would be to make your tests a patch that's managed by a mq (Mercurial Queues) repository, which can itself be versioned. Then when you where in your dev branch and wanted to run the tests you'd do:
hg qpush # tests show up
... run tests, edit tests ..
hg qrefresh # save the changes you made to the test
hg qpop # tests vanish again
MQ is poweful, but sometimes a little hard to wrap your head around.
Another choice would be to make your tests a parent repository and your actual code a child repository of that parent. Your disk layout would look like:
parent/
tests/
existingrepo/ # <-- the repo you already have w/o tests
Then people could clone and you could push the existingrepo w/o tests, but the outer repo would include a pointer to it and the two would be versioned in lockstep. Again, sort of tricky, but has some nice results.
The third option, and my preferences is to get over the "To keep my commits organized as well and not to clutter my development branches" mentality. Tests are just as important as the primary code, they should be versioned with the code, and they're not cluttering anything, they're providing valuable tools to help comprehend what the code is doing. You can always use hg log --exclude tests/ to see a history that excludes them when that's convenient.
To take that plunge just do:
hg update development
hg merge tests
and you're good to go.
when i commit the units to the test branch and switch back to development, said tests are deleted
It's expected and correct result: branches store diverged lines of development, you add something only in test branch, before merge this data will exist only in branch on creation
In order "To keep my commits organized as well and not to clutter my development branches...", but have tests in development branch you can use at least two ways:
Periodically merge tests branch to development (all changes in tests will appear in development), but use log only for changesets in development branch, maybe without mergesets from tests. It's rather simply revset, you can even write log command with revset into aliases and use aliased command when needed
As Ry4an mention, you can instead of branch-separtion, perform repository-separation with subrepo|guestrepo technique - if tests are stored in subdir of main repo, convert /tests into nested repository -> subrepository and have two independent, but linked repos (future reading: Subrepository in Mercurial wiki and Subrepositories in Mercurial Kick Start Exercises)
to achive what i wanted i eventually created a subdirectory for the repo:
project/
main.cpp
makefile
.repo/
.hg/
and created a new make target:
REPO := .repo
init: $(REPO) $(REPO)/.hg
$(REPO):
mkdir -p $(REPO)
$(REPO)/.hg:
hg init $(REPO)
commit : | $(REPO) $(REPO)/.hg
ifdef BRANCH
hg -R $(REPO) update -C $(BRANCH)
endif
find . -regex "^\./[^.].*" -exec cp --parents {} ./$(REPO) \;
# the regex prevents "hidden" dot-folder from copying
# one could use --link to save time and drive usage/space
# but i am concerned about hg auto merging and overriding (per hardlink)
# my actual changes
hg -R $(REPO) commit $(EXTRA)
so i could just issue make commit BRANCH=tests to commit to arbitrary branch without losing all changes not relevant to the branch. Implementing of hg add as wipe .repo, copy file there hg -R .repo add $(filename) is left as exerciser for the reader

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: How to compact/combine specified old revisions into one?

I've got a repository. In the middle of its life-cycle I deleted a lot of unnecessary files from it (I decided to keep them unversioned).
hg remove
hg commit
The repo grows bigger and bigger.
And I decided to get rid of old revisions the from initial one to the revision where lot of files were removed (let's name it X).
Other words I want combine these revisions (from the initial to the X) into one initial revision.
But same time to keep the history of the following revisions (X+1, etc..) as they are.
I googled for the solution, but failed.
And found nothing clever than do this:
hg init newrepo
cd oldrepo
hg archive -r X newrepo
hg export -r X+1: -o "~/patches/%R-%h.diff"
cd newrepo
hg commit -A -m 'initial release (after archiving)'
hg import ~/patches/*.diff
And damn it, after few successfully applied patches
I receive:
Hunk #1 FAILED at xxx
Hunk #2 FAILED at xxx
2 out of 2 hunks FAILED -- saving rejects to file xxx.rej
abort: patch failed to apply
What I do wrong?
I've got 1 repo without branches (to be more exact to the revision X all branches were merged).
The second solution was
* hg convert to svn
* hg convert to mercurial from revisiob X+1
Failed with python backtrace (probably it was caused by our repo has about 3K files).
To filter out files from repository, you want to use hg convert (Mercurial to Mercurial) with --filemap argument (see documentation for more details). Keep in mind the affected changeset IDs (and those of all their descendants) will change.
Take a look at the Collapse extension which seems to do what you want.
You can fold changesets with MQ, or use histedit extension