Hg: How to walk through changsets incrementally? - mercurial

I'm new to Hg. I have a feature that was working, but now isn't. I want to progressively revert changes until I get to a revision where it works. I'm not quite sure what the best way to do this is.
I tried cloning the repo to an old revision, and saw that it worked there. So... how now do I update to subsequent changes? In the cloned repo, the default and tip revision is the one that I cloned it to.
Do I need to apply patches? Shelve changes? I'm not really sure.

You should use the bisect command to quickly figure out when your feature stopped working. It works as follows:
You start by resetting the bisect state and by marking your current working directory parent revision as bad:
hg bisect --reset
hg bisect --bad
Now make a guess about when you think the feature was working. If you think it was working on June 1st, then you can do
hg update -d '<Jun 1'
The update command is what you use to update the working directory to match a given changeset. See hg help dates for the list of date formats. You should now test this revision and if the feature works here, then you mark it as good:
hg bisect --good
If the feature is not working in this changeset then mark it as bad and update even further into the past:
hg bisect --bad
hg update -d '<May 1'
Repeat this until you find a good revision. When you have found a good revision, Mercurial can begin helping you: the changesets between the good and the bad changesets must contain the bug. Mercurial will help you by keeping track of the list of candidate changesets and help you narrow the list down to a single changeset. It does this by updating you to a changeset roughly in the middle of the candidates and asking you to test this changeset.
After testing, you mark the changeset as good or bad. If you mark it as good, then you know the bug lies further in the future, and if you mark it as bad, then the bug lies further in the past. In either case, you cut away about half of the candidates in each step! This means that you only need 10 steps to test 1024 candidates -- this is the power of logarithms :-) Mercurial will keep track of the candidates and update you to a new spot after each test.
A full session could look like this (I'm just saying good/bad by random here):
% hg bisect --reset
% hg bisect --bad
% hg update -r -100
61 files updated, 0 files merged, 9 files removed, 0 files unresolved
% hg bisect --good
Testing changeset 11414:0fa4474bdc2f (99 changesets remaining, ~6 tests)
46 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --good
Testing changeset 11439:778377be3662 (50 changesets remaining, ~5 tests)
17 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --bad
Testing changeset 11428:4d03c3680400 (25 changesets remaining, ~4 tests)
6 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --bad
Testing changeset 11420:a99ef3711890 (13 changesets remaining, ~3 tests)
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --bad
Testing changeset 11417:6f1d1ed3e19a (6 changesets remaining, ~2 tests)
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --good
Testing changeset 11418:67bb9d78f05e (3 changesets remaining, ~1 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
% hg bisect --bad
The first bad revision is:
changeset: 11418:67bb9d78f05e
user: Matt Mackall
date: Mon Jun 21 13:25:42 2010 -0500
summary: merge: sort arguments to stabilize the ancestor search

I would iterate through the remaining change-sets using
hg pull -r <revision> [<original repo>]
Some docs here.

To find the revision exactly at which the feature was missing you can try hg bisect.
you can find it here.
tip the latest revision in the repo, default the name of branch which is by default in the repo when you created it. you can add the remaining changesets(changes) by pulling them.
hg help pull

Related

How to check which branch you are on with mercurial

What is the best way to check which branch I am on with mercurial?
hg log -l 5
This seems to show me the latest commits in the repo and not about working state as git would, so I'm looking for something like git status I suppose, which would tell me what branch I am on. hg status doesn't show me anything.
You can use the hg identify command with the -b for branch option:
C:\Some\Repository> hg identify -b
default
hg branch. I suggest at least reading hg help once :^)
$ hg branch
You can just always use the grep with a keyword to search.
In this case,
$ hg help | grep branch`
Gives you:
branch set or show the current branch name
branches list repository named branches
graft copy changes from other branches onto the current branch
heads show branch heads
You could use hg sum
for example, say you have two branches, A and B
[root#B6LEB1 ATS]# hg update A
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
[root#B6LEB1 ATS]# hg sum
parent: 1787:3f06e1a0260a
made A
branch: A
commit: (clean)
update: (current)
[root#B6LEB1 ATS]# hg update B
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
[root#B6LEB1 ATS]# hg sum
parent: 1788:7ff3c507efd9 tip
made B
branch: B
commit: (clean)
update: (current)
You also might want to specify the currently checked-out version explicitly. Then the output of hg log will return what you look for:
hg log -r.

Mercurial: undo automatic merge with uncommited changes

I did hg pull and hg update on a folder where I had uncommited changes. It opened the three-way compare/merge tool for a couple of files, but I closed them all since I did not remember whether the changes were older or newer than what was in the repo - I thought that this will leave the files as conflicted, like it would do in SVN .. but no, all the files got merged:
updating to branch default
25 files updated, 0 files merged, 0 files removed, 0 files unresolved
Unfortunately, the merge mixed the two versions in a way that does not work.
My question is therefore if there is a way to undo the merge and get back the local files (with the uncommited changes) as they were before I called hg update?
(I found this post, where one commenter suggests hg resolve --tool internal:local, but it does not seem to do anything in my case.)
Thanks.
As you've found out the hard way, Mercurial will merge the changes in the working copy into the target revision when you update.
If the merge was clean (from the point of view of Mercurial), the affected files are marked as "resolved". You can check this with
$ hg resolve --list
It will show a bunch of files with a R for resolved. Unresolved files are listed with U. Before hg resolve will work on a file, you have to mark it as unresolved first:
$ hg resolve --unmark your-file
Here is a full session where I create a commit with two commits:
$ hg init
$ echo x > x
$ hg commit -A -m x
adding x
$ echo xx >> x
$ hg commit -m xx
I then update to the first commit (where the file contains x) and change it to y:
$ hg up 0
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ echo y > x
Updating back to the second commit triggers the merge, which succeeds:
$ hg up
merging x
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
$ hg resolve --list
R x
$ cat x
y
xx
Before I can get my file back, I need to mark it as unresolved. I can then resolve it using the internal:local tool:
$ hg resolve --unmark x
$ hg resolve --tool internal:local x
$ cat x
y
The merge state is stored in .hg/merge. There you'll find a bunch of files names by SHA-1 hashes. I suggest making a copy of this directory before you begin playing with the above commands since Mercurial deletes the directory when it thinks it is no longer needed.

"hg push" reports "added 1 changesets with 0 changes to 0 files." Huh?

Using Mercurial, I've just done a merge/commit/push sequence, and the push reported:
remote: added 1 changesets with 0 changes to 0 files
... which had me freaking out for a few seconds.
The full sequence of commands and outputs was:
% hg merge -r that_other_branch
63 files updated, 0 files merged, 1 files removed, 0 files unresolved
(branch merge, don't forget to commit)
% hg status
... <63 files marked 'M', one marked 'R'> ...
% hg commit
% hg push
pushing to ssh://hg#bitbucket.org/mycompany/mycompany-coolwebsite
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 0 changes to 0 files
%
When I look at the remote repository (on Bitbucket), I see that it does list all 64 files, and the diffs look right. So I'm satisfied that the merge and push did what I wanted, but that last message from hg push has me mystified.
Is this a bug in Mercurial? (hg --version reports "2.6+20130507", and I'm on OS X 10.8.5)
Or is the message correct, and I'm just too dense to understand what it's trying to communicate?
(If it makes a difference, the files in the head revision of the target branch were identical to the files in the ancestor revision common to that head and 'that_other_branch' -- which accounts for why there were all 'updates' and no 'merges' resulting from the hg merge.)
Everything's probably fine. Since that 1 new changeset is a merge it's probably being excluded from those totals since every change it contains is already in one head or another that's already on the remote repo.
Other changesets that could yield a similar message are those that only alter the permissions of files, but that's clearly not the case here.

How to merge a feature branch to default with subrepositories with Mercurial

I have numerous projects with subrepositories:
/project <- Main repository
/project/src <- Source code subrepository (subrepository to /project)
/project/src/module <- Module subrepository (subrepository to /project/src repository)
I've now worked on a feature branch (feature1) which has had a few revisions, which I'd now like to merge back into the default branch. The default branch hasn't had any changes since the feature1 branch was created.
I've tried merging the branch to default however end up with some strange things happening in the subrepositories.
I've followed the instructions in this other post, and get the following results:
$ hg checkout default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge feature1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg status -S
M .hgsubstate
$ hg commit -S -m "branch merge test"
nothing changed
$ hg branches
default 19:c2398dc23428
feature1 17:98dc0efbad90 (inactive)
What's strange is that even though many files were changed in the module subrepository, the merge only stated that 1 file was updated. I'm assuming that this happens to be the .hgsubstate.
When I explicitly update the subrepository, then I get the following:
$ cd src/module
$ hg update
39 files updated, 0 files merged, 23 files removed, 0 files unresolved
$ cd ../..
$ hg commit -S -m "feature1 merge"
committing subrepository src
$ hg status -S
M .hgsubstate
So after doing a hg update to bring all the changes into the working directory, I see the changes in the module subrepository that I need to commit. However, .hgsubstate always remains in the modified state. I've tried hg remove. I've tried hg forget. But no matter what I do, it still is marked when I do a hg status.
So my questions are:
Was the process I took to merge the branch in correct (considering subrepositories are present)?
Is it necessary to do a hg update in the subrepositories to make the main repository recognize the changes?
Why is .hgsubstate misbehaving?
You don't say which version of hg you are using - subrepo support has changed a certain amount over time. I've just tried something like your test with 3 subrepo levels in hg v2.8 and it works for me.
When you got a dirty .hgsubstate at the top level, that is normal when you commit a subrepo. [If only a subrepo has been committed independently, only the .hgsubstate will be dirty at the top level.] If you then go up to the top level and commit at that level the .hgsubstate will be committed, and everything is fine. Remember, the top level repo tracks subrepos in a similar fashion to files - it commits a particular changeset from the subrepo at each top level commit.
FWIW. The recommended practice is to commit subrepos separately, i.e. avoid committing at the top level if the subrepos are dirty. The reason is that the subrepos often require a different commit message - they are subrepos for a reason after all; but you can commit at the top level if you wish. In your case with 3 levels the sequence would be:
cd src/module
hg commit -m "src/module commit reason"
cd ..
hg commit -m "src commit reason"
cd ..
hg commit -m "top level reason"
It was intended that subrepos would change infrequently, e.g. third party libraries. If your subrepos are going to change frequently, you and your team will have to be vigilant to avoid mistakes, especially when merging with other peoples work. [But given the date of the question you've probably worked that out yourself by now.]

Mercurial deleted a untracked file

In our repository we have initial version of database (binary file).
I have executed hg pull and I saw that someone committed another version of this file.
As I won't to loose my changes in dev db, I did make a copy of it (copy file.db my_file.db) in same directory.
When I runned hg up, mercurial overwrited file.db with new version and deleted my_file.db!
I'm on windows 7 x64, and tried various software that recover deleted files, but with no success.
How can I get back my version of file.db or recover my_file.db? I didn't commit it.
I really don't think mercurial deleted your untracked file. Here's the sequence you've described as I understand it:
ry4an#four:~$ mkdir zote
ry4an#four:~$ cd zote
ry4an#four:~/zote$ hg init orig
ry4an#four:~/zote$ echo text > orig/file.db
ry4an#four:~/zote$ hg -R orig commit -A -m 'initial'
adding file.db
ry4an#four:~/zote$ hg clone orig clone
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote$ mv clone/file.db clone/my_file.db
ry4an#four:~/zote$ echo more text >> orig/file.db
ry4an#four:~/zote$ hg -R orig commit -m 'new line'
ry4an#four:~/zote$ hg -R clone pull
pulling from /home/ry4an/zote/orig
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
ry4an#four:~/zote$ hg -R clone update
remote changed file.db which local deleted
use (c)hanged version or leave (d)eleted? c
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote$ ls clone/
file.db my_file.db
ry4an#four:~/zote$ cat clone/my_file.db
text
ry4an#four:~/zote$ hg -R clone status
? my_file.db
You can see that afterward my_file.db is still there. Even with --clean as Mikezx6r mentiones the file is still there:
pulling from /home/ry4an/zote/orig
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
ry4an#four:~/zote/clone$ hg update --clean
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote/clone$ ls -l
total 8
-rw-r--r-- 1 ry4an ry4an 15 2011-02-08 14:31 file.db
-rw-r--r-- 1 ry4an ry4an 5 2011-02-08 14:28 my_file.db
ry4an#four:~/zote/clone$ hg stat
? my_file.db
ry4an#four:~/zote/clone$
It's not what you want to hear, but it's much more likely you accidentally botched the 'mv' and only thought you created the copy or somehow externally deleted it. Or your antivirus app saw a pattern it didn't like a refused to create it, or some other horrible, accidental thing.
It's also not helpful now, but this is a great example of why you should commit early and often, and especially before updating -- it's just too easy to make mistakes, but once something in in the repo there's nothing you can do to accidentally remove it.