I'm working in this file and I come across a piece of code which I think has changed at some point in history, and I would like to know where it changed.
It's a pretty big file with a lot of history, so when I use hg diff, I get a enormous list and I don't think it's efficient to search through that.
It would be really neat if I can look into an old revision of the file, to see what the file looked like at a certain point in time. Then I can see how the code worked back then so I can conclude how the bug evolved. Of course, I want to do this without updating the file, because I'm currently working in it and have made changes in it.
So, is there any way you can look into the history of a file without updating it?
There are a few tools to help you:
To get the history of a file you can just use hg log FILE which is probably the best starting point.
You can also use hg annotate FILE which lists every line in the file and says which revision changed it to be like it currently is. It can also take a revision using the --rev REV command tail to look at older versions of the file.
To just list the contents of a file at a given revision you can use hg cat FILE --rev REV.
If it proves too hard to track down the bug using those tools, you can just clone your repository somewhere else and use hg bisect to track it down.
hg bisect lets you find the changeset that intoduced a problem. To start the search run the hg bisect --reset command. It is well document in Mercurial: The Definitive Guide.
Related
I've recently started to work on an open source project which uses Mercurial.
I'm a new user to Mercurial, so I read the HG book and started working.
My goal was to write code and always pull and merge changes from the upstream
so I can stay up-to-date. The area that I am working on is also under heavy
development by others so I do want to merge my changes after a long period of
time. I cloned a repo. So, my workflow is like this:
I created a bookmark mybook
hg up mybook
Write code
3.1 hg commit -m 'new functions'
hg up default
hg pull
hg update
hg up mybook
hg merge default
Go to step 3.
In my mind this is the simplest workflow that allows me to stay up-to-date. I
also have only one HEAD because I always merge.
Since I am not a contributor yet, I am not allowed to push changes to remote
repo.
Recently I wanted to show my work to a project lead and he said send me a patch.
And this is where I am stuck. hg out shows 10 changesets. First of which
appeard already a month ago. They're numbers are 3341, 3342, 3345, 3346, 3349, 3356, 3360, 3365, 3366, 3368. The changeset numer 3368 is the tip.
I've recently read the chapter about the MQ extension. And this extensions seems to be what I need. But the problem is that I wrote code without using the MQ
extension.
So, how can I make use of the MQ extension on already created changesets so that
I can make a patch to send to the project lead so that he can apply it and see
my changes?
I've just issued hg qinit. What's next?
Issueing hg qimport -r 3341 gives
abort: revision 3341 has unmanaged children
Reading the book and googling further does not help me. I need an advice.
PS I've tried not using hg and MQ at all: simple diff -urN old/ new/ but I
want understand how to do it with the MQ.
Thank you.
Yeah, don't use MQ. It's a parallel system, meant for keeping things out of the history, and more important you don't need it.
You were asked for "a patch", not a complete history of your work, so I would recommend sending it in the form of a single before-after diff. hg export will give you a series of diffs, for all the work you've done, including the merges. I find it's far easier to read and review a single diff (before applying it). But instead of plain diff, use hg diff which knows to only look at tracked files, and has a number of other nice features (including the --git option, which provides richer metadata). This should do it:
hg up mybook
hg diff --git -r default > mywork.patch
Before sending it off, do an hg up default and apply the patch to check that it works without conflicts. And mention to the recipient which version of default you are patching against.
Edit: As you can read in the comments, #LazyBadger is a fan of the step-by-step patch generated by export. I prefer the single-step patch
since my history is usually TMI: Nobody cares about all the times I added a forgotten file, or noticed a bug too late and fixed in in the next commit, etc.
Take your pick.
I recently let the IDE replace a trivial text in the entire project, and recognized that mistake only after committing other changes to Mercurial. I panicked and (knowing very little about Mercurial, now after having read the definitive guide starting to get to know it better) tried every command that seemed to make my mistake "go away". It goes without saying that this was a move I am not proud of.
Of the things I remember to have tried was hg update tip and hg rollback. Since I'm using Mercurial on my local machine only and do not pull or push from any other repository, I think these commands did not cause my main problem: There are a lot of files missing now -exactly the files I let the IDE make the wrong replacements in.
What bothers me is that I have done hg status --change REV to find all files changed in a revision, and the deleted files do not show up there.
PHPStorm has a local history, which shows which files are now missing. That (only that?) enables me to hunt down the individual files and revert to their last known revision:
hg log -l 1 path/to/foo.txt
hg revert -r <my revision> path/to/foo.txt
... but that is way too time-consuming for the hundreds of files that got changed. Please tell me there's a better way. The PHPStorm history is nice and can restore the files as well, but it will restore them to the point where they had already been erroneously changed.
Your help is greatly appreciated, and I vow to learn & appreciate Mercurial as more than just a context menu item starting today.
If you are willing to lose the changes that were committed with or since the error, you may be able to go back to the revision just before the error, and start working from there. Use hg log to find out which revision you need, and hg update --rev XX to go to that revision. If you're not sure which revision you want, update to various revisions and take a look.
Once you have updated to the correct revision, you can just continue working from there. The next time you commit, you will automatically create a new branch on which you'll be working, which will not have the error in it. If you want, you can go back to the original branch and close it.
You might even be able to get back any correct commits that happened after you committed the error up to the revision you rolled back to. On the old branch, identify the revision after the error, and do a diff between that revision and the tip of that branch. Then, see if you can apply the diff as a patch on your new branch. You will still lose any changes that were in the same commit as the error, though.
I received some code as a tar archive (without the .hg directory). I know which repository this code is based on, but not which revision was used as a base for these modifications. Is there some way to find this out by just looking at the files? This is similar to Given a file, how to find out which revision in a mercurial repository this is? but I cannot reach the author of the code, so I cannot control how the files are extracted from the repository. I am also dealing with modified files here so the diff to the base revision would not be empty.
My fall-back plan would be to loop through all revisions and using the one with the smallest diff, but I'm still hoping there is a better solution.
There's no automated way to do it, but you could possibly reduce the time by using a hg bisect --command diff ... command to zero in on it.
As a tip if you (I know it probably wasn't) you ever has to give someone a snapshot again, use hg archive to make it. It includes a .hg_archive.txt file with version info that'll help if you have to do this again.
I accidentally renamed a file outside of Mercurial. When I committed the change, Mercurial treated the change as two unrelated files (ie. a remove and a add). I need to go back to diff the two revisions but I don't know how to do so when Mercurial sees them as two respective files across different revisions. What can I do to diff the files?
You didn't say what operating system you were using. The following will work with bash on Linux:
diff <(hg cat -r rev1 file1) <(hg cat -r rev2 file2)
You can replace diff with another program like vimdiff if you want a visual diff.
If you want to actually fix the history so that Mercurial is aware of the rename (and can use that information in future merges if needed), there's a way to do so documented on the Tips and Tricks page on the Mercurial wiki.
Current contents copied here for ease of use (and in case the link gets broken later):
Steps:
Update your working directory to before you did the rename
Do an actual "hg rename" which will create a new head
Merge that new head into the revision where you did the "manual" rename (not the head revision!)
Then finally merge the head revision into this merge result.
Advice:
Make a clone first and work on that, just in case!
After finishing the steps, use a file compare tool to check that the original and the clone are identical
Check the file history of any moved file to make sure it is now restored
That being said, if all you want to do is compare the contents at the point in time, you can definitely accomplish that without making Mercurial aware of the rename (as mentioned in Stephen Rasku's answer). In fact, you can use a combination of "hg cat" and an external comparison tool to compare any files, not just ones that Mercurial knows about.
Fix history:
Update to first changeset with new-filename, save file outside WC
Update to parent of bad replacement changeset, replace file correctly (with rename tracking), commit, got second head
Rebase all changesets from old anonymous branch on top of fresh good changeset
--close-branch on bad-replacement changeset or delete this unwanted changeset or leave inactive head intact
I am new to Mercurial. Just cannot find the right command. Tried update/checkout with no luck. I am using local repository. Thanks
I think you want hg revert -r<rev> <file> (this will change that file to be as it was at the given revision).
As djc said revert alters a file in place to match a prior revision. If you want it not in place you can use hg cat -r revisionid filename (substituting revisionid and filename of course) which will output the file to stdout, suitable for redirecting anyplace you'd like.
hg revert does indeed solve this problem. But I think that you are confused about a broader range of things than simply the answer to your question and want to try to answer more fully.
hg update is a whole repository command and will not work on individual files. It is unlike the subversion svn update in this way. If you do hg --help update you can see that this is the case because the command takes no file argument. It can be used to move your whole repository to a particular snapshot, but cannot be used to do that to just one file.
If you type hg --help you see a list of commands. It's a rather large and somewhat daunting list, but if you read through it, you'll find this line:
revert restore individual files or directories to an earlier state
Now, if you just want the last state for comparison purposes, there is another command you may be interested in, and that's hg cat. That will allow you to print out the contents of a file at any particular revision. You can then redirect its output into some other file. Then you can have the previous known good version of your file and the old version to compare side-by-side.
The reason why Mercurial has a separate update command is that it is possible to do something in Mercurial that is impossible in Subversion. You can update to an earlier version, make changes, then commit. This will create a branch. The update command has the effect of also changing the parent revision of the current working directory as well as changing the contents of all the files in that directory to that parent revision's versions.
That means revert changes the contents of a file (or even the whole repository if you give the command the right arguments) but leaves the parent revision of the current working copy the same.
You can find out the parent revision (or revisions in the case of a merge) of the current working copy by using the hg parents command.
In Subversion revisions are a strictly linear progression. Mercurial creates branches at the drop of a hat, and they are almost as easy to merge. Revisions form a DAG, not a strictly linear progression.
To extract a specific revision of a specific file you can do this on Windows:
hg cat "<FileToBeExtractedPath>" -r 9 > "<ExtractionPath>"
Here, 9 is the revision number.
Or even better:
hg cat "<FileToBeExtractedPath>" -r 9 -o "<ExtractionPath>"
Came here trying to get the previous version, so here is the exact command:
hg revert -r .~1 <file>