Committing to a different branch with commit -r - version-control

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.

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.

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

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.

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.

Mercurial: Getting changed files from revision?

I can't get my head around how I can get only the files that were changed in my last revision, and not the complete repo, which i get by using Clone. This would be super helpful to for instance, deploy the last changed files.
What do I do?
Thanks
You cannot transfer just some files -- you must always have a full clone locally. So I suggest you make that once and then pull in changes incrementally.
You should then use hg status to show the names of files changes been revisions. You normally use hg status to see which files are changes compared to the working copy parent revision, but you can pass --rev to status to see changes between any two revisions!
So use
$ hg status --change tip
to see which files were changed in the tip changeset. Use
$ hg pull
$ hg status --rev .:tip
to see what files will be changed when you do a hg update after a pull. The update will take you from the current working directory parent, denoted by ., to the tip, assuming you are on the same named branch as tip. Otherwise hg update will take you to the tip-most changeset on your current branch.
You can use a template to hg log or hg tip to get all filenames:
hg tip --template '{files}'
or to get e.g. all files changed/added/modified by changeset 5:
hg log -r5 --template '{files}'
You can read more about templates Mercurial: The Definitive Guide, Chapter 11. Customizing the output of Mercurial or short help with hg help templating`
If you want to do something to the files e.g grep through them:
hg tip --template '{files}' | xargs grep foo
Careful this will break with filenames containing spaces!
To process all kinds of filenames something more complicated is needed (thanks to mg on #mercurial for the tip):
We need multiline styles for this suppose a file named zerosep contains:
changeset = "{files}"
file = "{file}\0"
Then you can use this to produce a \0 separated list of filenames and process it with xargs -0:
hg tip --style zerosep | xargs -0 grep foo
Information how this works can be found in: Listing files on multiple lines
Martin has the right way to get a list of what files have changed in a revision, and I've upvoted his answer, but just to expand on why your question is a little off:
In Mercurial every location has a full copy with all changes. If you're going to use Mercurial to deploy to your server then you have to clone everything to your server -- once. After that push/pull will move over only the (compressed) changesets that the server doesn't already have.
If you don't want to have everything that ever was on the server, then you need to use something other than mercurial for your deployment, perhaps something fed from the status commands Martin showed or a snapshot created from hg archive.
Personally, I'm okay with having full history on my servers, and just do a hg pull ; hg update on the server for each new deployment. It's tidy and efficient.

Mercurial (hg) commit only certain files

I'm trying to commit only certain files with Mercurial.
Because of of hg having auto-add whenever I try to commit a change it wants to commit all files. But I don't want that because certain files are not "ready" yet.
There is
hg commit -I thefile.foo
but this is only for one file. The better way for me would be if I can turn off auto-add as in Git. Is this possible?
You can specify the files on the command line, as tonfa writes:
$ hg commit foo.c foo.h dir/
That just works and that's what I do all the time. You can also use the --include flag that you've found, and you can use it several times like this:
$ hg commit -I foo.c -I "**/*.h"
You can even use a fileset to select the files you want to commit:
$ hg commit "set:size(1k - 1MB) and not binary()"
There is no setting that will turn off the auto-add behavior and make Mercurial work like Git does. However, the mq extension might be of interest. That's an advanced extension, but it allows you do to
$ hg qnew feature-x # create new patch
$ hg qrefresh -s foo.c # add a file to the current patch
$ hg qrefresh -s bar.c # add another file to the patch
$ hg qfinish -a # convert applied patches to normal changesets
I don't really use MQ for this purpose myself, though, since I think it's enough to just specify the filenames on the command line.
If you want to commit a few files, and exclude many others, explicitly list the files you want to commit. -I is only needed if you want to use patterns instead of files.
If you want to commit many files, and exclude only a few files, using -X is more convenient.
E.g. given a repository containing "file_1", "file_2" and "file_3", the following are equivalent, but the latter is easier / faster to type:
hg commit file_1 file_2
hg commit -X file_3
As of 3.8 you can also use hg commit --interactive to select the files (before 3.8 you can use crecord extension for similar functionality). The --interactive (or just -i) flag will cause hg to prompt you for the files you want to include in the commit. As an added bonus you can even include/exclude chunks within the files.
Here is an example of what the interface looks like. Note this is an old screenshot (of crecord actually) so interface has changed slightly (but basics are the same).
Note to get that interface you need the curses interface enabled. You can do that for single run with hg commit --config ui.interface=curses --interactive or generally by adding the the following to your .hgrc:
[ui]
interface = curses