Diffing a file against last Mercurial changeset, should it be different? - version-control

I'm seeing something I don't expect in my Mercurial repo. A change that has been made in a branch is showing up in default. There is no changeset in the log, merge or otherwise, accounting for the change moving into default from the branch.
I checked the basics: I'm in default, did an 'hg pull', 'hg update -C', 'hg purge', and an 'hg st' which came back clean.
If I look at the file locally the change I am expecting is not there. If I do an 'hg diff -r ' then it tells me that my local file is missing the change I expect to see. The file does not show as modified in 'hg st' and a simple 'hg diff' on it shows no differences.
I would expect that whenever doing a diff with an unmodified file explicity against the last changeset in whatever branch I'm in with '-r' it should come back with no differences. Am I wrong? Am I misunderstanding this basic concept?
Thanks,
Scott

I think hg has an internal cache of which files it thinks are modified, and somehow this has got out of sync. This happened to me before, but I can't remember whether I deleted the file first or just used hg revert.

Related

How to properly revert from botched merges in Mercurial?

Sometimes a merge will cause the manual diff tool (in my case KDiff) to open, and sometimes it's not possible to resolve the merge properly manually. If I close the diff tool without saving, then I get something like
1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
I'm not really sure what state my workspace is in at this point.
Is there any easy way after this happens to get back to the state I was in before I issued hg merge?
You can revert the recent merge using hg update -C -r . But be informed that it will also remove any uncommitted changes.
The . after -r refers to last revision number.

How can I remove files that were changed and then reverted on a branch from a merge

I have a branch in Perforce on which I have checked in changes to several thousand files, and then later backed out the changes to approximately half of those files - so the latest revision of some of the files on the branch is unchanged from the baseline, but there are intermediate revisions with changes.
In many cases there have also been out-merges from mainline in the meantime, so the history is a bit more complicated, but the eventual result is that there are no content changes left to merge back to mainline.
I now want to merge that branch to mainline, but I don't want to check in "null" changes to the files that in the end were not modified on the branch.
Normally one can avoid checking in unchanged files with "Revert unchanged files" in p4v, but in this case it won't revert the files, because it believes that the file needs to be checked in to update the integration record. The help for p4 revert confirms this:
The -a flag reverts only files that are open for edit or integrate
and are unchanged or missing. Files with pending integration records
are left open. The file arguments are optional when -a is specified.
Is there any way I can avoid checking these files in without going through them one by one? I'm happy to do whatever is necessary on the branch, and I'm not too worried about it it causes future merges to the branch as I will be abandoning it soon after this merge.
If you're looking to revert files that have no differing content (i.e., where the only change is to update the integration record) you can do something like this batch file (you'll need to translate to a shell script if running on Linux):
for /f "tokens=2 delims=# " %%x in ('p4 diff -Od //depot/path/you/care/about/... 2^>nul ^| findstr /c:"//depot"') do (
p4 revert %%x
)
We use something similar where I work because we have a number of files that are marked +l and if we're doing an integration that takes a while to validate, the people that need to work on those files are locked out.
Assuming that the changes that got reverted were actually checked into the branch, and then backed out, my suggestion would be to (using extreme caution) obliterate the two revisions of the files that got reverted (the initial change, and the change that put it back to the initial state). I think that should prevent them from getting merged back into the mainline.
I would strongly suggest testing this out on a test branch before trying it on your live branch.

Deleting tracked file from the file system vs hg remove

I'd like to know if there are any consequences when deleting a tracked file from file system (e.g. via windows explorer) in comparison with when using hg remove to delete it from file system and untrack it.
In both cases, I'll commit afterwards, just in the first case tortoise HG marks the file as missing with exclamation mark, with the second it marks it as clean and ready for removal.
Besides this are there any differences?
If you go the file system path and don't make any other changes to tracked files, hg will give you an error when you try to commit:
nothing changed (1 missing files, see 'hg status')
(This is just a special case of nothing changed.)
If you have changed something else, hg won't complain at that point, but the file's status will continue to show up as missing with hg status. This has the negative effect of cluttering up your (mental) workspace and making it harder to tell at a glance what your working directory's current status is. Moreover, the file remains in the repository and will be restored by hg update for any revisions where it is still being tracked!
hg remove will return an error if the file was already deleted from the filesystem; in this case you should use hg forget to tell Mercurial to stop tracking the file.
If you prefer doing big changes with external utilities (like Windows Explorer), you can use the nifty hg addremove which automatically detects additions and removals. (The downside is that you might remove and untrack accidentally deleted files.)

Mercurial workflow for updating with uncommitted changes?

So i've made the switch from CVS to mercurial for my website.
The biggest issue I am having is that if i'm working on some files that I don't want to commit, I just save them.. I then have other files I want to push to the server, however if someone else has made changes to the repository, and I pull them down.. It asks me to merge or rebase.. either of these options will cause me to lose my local changes that I have not committed.
I've read that I should clone the repository for each project on my local host and merge it into the live when it's ready to do so. This not only seems tedious, but also takes a long time as it's a large repository.
Are there better solutions to this?
I would have hoped that Mercurial would see that I haven't committed my changes (even though I have changed the file from what's on the server) so it'd just overlook the file.
Any input on this would be greatly appreciated. Thank you!
Also, i'm using the hg eclipse plugin to work on my files and push/pull from the server.
hg shelve is your friend here I think.
which comes from the shelve extention (maybe - see below)
from the overview:
The shelve extension provides the
shelve command to lets you choose
which parts of the changes in a
working directory you'd like to set
aside temporarily, at the granularity
of patch hunks. You can later restore
the shelved patch hunks using the
unshelve command.
The shelve extension has been adapted
from Mercurial's RecordExtension.
or maybe its the attic extension
This module deals with a set of
patches in the folder .hg/attic. At
any time you can shelve your current
working copy changes there or unshelve
a patch from the folder.
it seems to have the same syntax as the shelve extension, so I'm not certain which one I've used
I second #Sam's answer. However, if you prefer to use standard Mercurial, a simple workflow is to
save your working dir changes in a temporary file,
sync your working dir with a specific revision, then
push, pull, merge .. whatever you want to do and which requires a clean working copy, and
get back your changes from the temporary file into the working dir.
For instance:
$ hg diff > snapshot.patch # save your uncommited changes
$ hg up -C # get a clean working copy
$ hg pull # do things ..
$ hg merge # .. you need a clean ..
$ hg commit -m "merge" # .. working copy for
$ hg import snapshot.patch # get back your uncommited work
First, are you working from the commandline, or using something like Tortoise?
If you're working from the commandline, and you've done a pull, mercurial will not ask you to do anything, as it merely updates your local repository.
If you then do an hg update and have local changes, it should do what you're used to from CVS. It will update to the tip of the current branch, and attempt to merge your outstanding changes in. There are some caveats to that, so refer to the official docs at http://www.selenic.com/mercurial/hg.1.html#update.
Also, for temporarily storing changes, I would recommend MQ over shelve. Shelve only provides one storage area, whereas MQ provides as many as you need. MQ takes some getting used to, but worth the investment.

Committing to a different branch with commit -r

Does CVS allow committing a file to a different branch than the one it was checked out from? The man page and some sites suggest that we can do a cvs ci -r branch-1 file.c but it gives the following error:
cvs commit: Up-to-date check failed for `file.c'
cvs [commit aborted]: correct above errors first!
I did a cvs diff -r branch-1 file.c to make sure that contents of file.c in my BASE and branch-1 are indeed the same.
I know that we can manually check out using cvs co -r branch-1, merge the main branch to it (and fix any merge issues) and then do a check in. The problem is that there are a number of branches and I would like to automate things using a script. This thread seems to suggest that -r has been removed. Can someone confirm that?
If ci -r is not supported, I am thinking of doing something like:
Make sure the branch versions and base version are the same with a cvs diff
Check in to the current branch
Keep a copy of the file in a temp file
For each branch:
Check out from branch with -r
replace the file with the temp file
Check in (it'll go the branch as -r is sticky)
Delete the temp file
The replacing part sounds like cheating to me - can you think of any potential issues that might occur? Anything I should be careful about? Is there any other way to automate this process?
Note that a file may not be up-to-date even if diff shows zero output. For example, if you add a line of text to a file in one commit and remove it in the next you have zero difference along the path of two revisions.
As for the commit -r -issue. To me it seems like an experimental feature, and actually one you are better off by just using:
cvs update -r <branch> <file>
cvs update -j <ver> -j <ver> <file>
cvs commit <file>
Besides, propagating a single commit to all other branches programatically like the way you suggested is slightly questionable business since you usually need a quite a bit of human brain to resolve the conflicts.