[NOTE: "Perfarce" is the name of a Mercurial extension for integrating with Perforce: https://www.mercurial-scm.org/wiki/PerfarceExtension]
We're starting to evaluate Mercurial for a project that's currently stored in Perforce. Rather than abandon the P4 depot and make all changes in Hg, we'd like to primarily work in Hg and push changes to P4 periodically. There's a chance some developers will continue working in Perforce during this evaluation, but other than that we want to evaluate the workflows that DVCS makes possible such as pulling from one dev's repo to another.
I've tried the Perfarce extension, and it looks like a great way to use Hg as an advanced P4 client with more granular local history. However, when I use Perfarce to check out the same tree on two different machines, I get two Mercurial histories with different changeset IDs. It looks like the only way to share changes this way would be to go through the P4 depot.
Are there other options for keeping developers' repositories synced with P4 without making them incompatible at the Mercurial level?
Honestly - this sounds like a situation that can be the cause for nightmares. Here is how I would approach it to minimize some of the risk and pain:
Setup the Perforce workspaces to "allwrite" such that Perforce won't interfere with Hg as much.
Use a single P4 workspace to sync changes from the depot down to a mercurial repository (and from hg back to the depot), then do your mercurial push/pull work from it. Treat it kind of like the master repository on GitHub or Bitbucket.
Using the one-true-workspace sync changes back to Perforce by using the "reconcile offline work" feature of P4V and make sure to carefully review the changelists (you don't want to submit the .hg directory).
With some discipline you should be able to avoid some pitfalls, though it certainly isn't an ideal path forward. I don't think there is a single bullet that will allow you to seamlessly keep your changes properly mirrored across all the different repositories and allow everyone to just work as usual.
Related
Say I have cloned a repo to a directory called ~/trunk and I want to share a branch named my-new-branch to the directory ~/my-new-branch. How would I do that with the hg share extension?
This is what I've been doing:
cd ~
hg share trunk my-new-branch
But then when I cd into the new directory I have to hg up to the branch?
Confused.
IMO share is a very useful command which has some great advantages over clone in some cases. But I think it is unfortunately overlooked in many instances.
What share does is to re-use the 'store' of Mercurial version control information between more than one local repository. (It has nothing directly to do with branching.)
The 'store' is a bunch of files which represents all the history Mercurial saves for you. You don't interact with it directly. Its a black box 99.99% of the time.
share differs from the more commonly-used clone command in that clone would copy the information store, taking longer to run and using potentially a lot more disk space.
The "side effect" of using share rather than clone is that you will instantly see all the same commits in every shared repository. It is as if push/pull were to happen automatically among all the shared repos. This would not be true with clone, you'd have to explicitly push/pull first. This is quite useful but something to be mindful of in your workflow because it may surprise you the first time you use it if you are only used to clone.
If you want to work in multiple branches (named or unnamed) of your project simultaneously,
either clone or share will work fine. One you have created the second repository, yes you need to update it to whatever changeset you want to begin working on.
Concrete example using share:
hg clone path\to\source\repo working1 # Create local repo working1 cloned from somewhere
cd working1
hg up branchname1
cd ..
hg share working1 working2 # shares the 'store' already used for working1 with working2
cd working2
hg up branchname2 # some other branch or point to start working from
As soon as you commit something in working1 that commit will be visible in the history of working2. But since they are not on the same branch this has no real immediate effect on working2.
working2 will retain path\to\source\repo as its default push/pull location, just like working1.
My own practice has been to create numerous locally shared repositories (quick, easy, saves space) and work in various branches. Often I'll even have a few of them on the same named branch but set to different points in history, for various reasons. I no longer find much need to actually clone locally (on the same PC).
A caveat -- I would avoid using share across a network connection - like to a repo on a mapped network drive. I think that could suffer some performance or even reliability issues. In fact, I wouldn't work off a network drive with a Mercurial repo (if avoidable) in any circumstance. Cloning locally would be safer.
Secondly -- I would read the docs, there are a few weird scenarios you might encounter; but I think these are not likely just based on my own experience.
Final note: although share is implemented as an "extension" to Mercurial, it has been effectively a part of it since forever. So there is nothing new or experimental about it, don't let the "extension" deal put you off.
We collaborate with a third party (contractor) using our "master" mercurial repo on a project for a client. It appears we get a very cluttered commit history (including trail and errors). We'd like to hide these details from the client (i.e. not reveal the whole commit history). However, at the same time, we would like to use the repo to deliver our results to the client (in a orderly and more "condensed" form).
Is there a recommend work flow (and tooling/hg commands) that suit this purpose?
There's no good/easy way to do this, but there are plenty of bad/hard ways to do it. Here are a few:
Internally do all your work in Mecurial Queues and then qfinish the changesets only when done / perfect. Give them access to the repo but not the mq repo (they're optionally, separately versioned)
Use things that rewrite history like commit --ammend or histedit's collapse command to alter the repo after you like it (drawback, everyone on your team has to delete and reclone)
create a totally separate repo for them and when you're ready to give them a drop copy in a hg archive from your repo and commit
I don't think any of those are worth the hassle of hiding normal software development work, but there you go.
Using MQ is good way, using MQ with TortoiseHG is also easy way to rewriting history.
In your case you can create, have and maintain two related repository: "Dirty" and "Clean"
Clean can be created as clone of used in work Dirty (and doesn't cloned after it to developers)
In Clean you'll enable MQ extension and rewrite history in Mercurial's CLI (or with TortoiseHG)
Coming originally from SVN, I am still new to Mercurial.
I am interested in creating an experimental workflow to see if I can rewrite a troubled feature from scratch. If my attempt fails though, I wish to delete the experimental workflow - abandoning the work — with nobody else ever seeing it.
The problem is though I still need to push changes of this experimental workflow across laptops and PCs and keep working for a couple of weeks. But still keep the option open to delete that branch and fall back to the main branch, without having any trace of the experimental branch.
Is something like this possible in Mercurial and how could I achieve this?
FYI, I am using mercurialeclipse plugin on Aptana Studio 3.0. (so I
use a UI but commands should be fine too)
After changeset is pushed to the central server (assuming you have one) - there is no way to remove it from there.
So the possible (but terribly inconvenient) solution for you now could be to create a personal separated repository and synchronize your devices using it. And if you like the result - you push to the shared central repo then. Otherwise you just delete the temporary repository.
With a Distributed Version Control System like Mercurial you can sync between any clone of a repository, not just a "central" one that all users have agreed to use.
Therefore, you can:
Clone the repository to private a share that the systems "experimenting" can access.
Clone to a USB key and move that between systems.
Use hg serve to start a web server for a local repository on a system and clone and pull that history to other systems.
Use hg bundle/unbundle to package up new history and email it to another system.
To abandon work, just delete all these extra clones and clone from the common "central" repository again.
Right now, we have a small team of developers using TFS for our version control. I'm evaluating the possibility of us moving to a DVCS, and am wondering if we'd need to give up some of the stuff we like about our current system if we moved to DVCS, or if we can find a way to support it.
Right now we a Stable branch, and 1 branch for each developer (you can think of each dev's branch as a feature branch that is reused from feature to feature). The stuff we like is:
1) Each time a dev checks in changes to his branch, we do a build and test of everything on the servers, followed by automatic deployment of all projects to that developers test environment.
2) Merging from any dev's branch to Stable is done by me, so that I can have 1 last check on what is happening to our stable branch before committing the changes.
3) If I want to help a dev with something, I can just grab latest from their branch and look at it on my machine.
I'm trying to understand how this could work with a DVCS (specifically we are testing with Mercurial).
I'm hoping to be able to pull off something like this:
1) We setup a central repository, and we create Main and Release branches in addition to 1 branch for each developer.
2) All devs clone the repository to their local machine.
3) All work is done in their personal branch against the local repository.
4) When they are done, the would pull from the central repository, and perform a local forward integration merge from Main to to their branch, to integrate any changes that have happened in the past to Main.
5) They would then push their changes to the central repository.
6) Some CI service would pickup this change, causing a build/test/deploy-to-dev of all our projects in that branch.
7) If everything was ok the dev would shoot me an email saying their branch was ready for merging to Main.
8) I could then merge in their changes, either by somehow connecting directly to the remove repository, or by doing a pull->merge->push.
So to deal with our requests:
1) I'm assuming there is some CI tools that can watch a branch in Mercurial, and kick off a build/test/deploy process (like CC.Net).
2) I can still manage the final merge process from DevX to Main either by connecting to the remote repo, or by pulling, merging and pushing through my local repo.
3) I believe I could either pull changes directly from another dev's repo, or I could just pull from the central repo, and then update my working directory to work on their code.
So do I have this mostly right?
Yep, you have all that right. Regarding you final assumptions:
1) There's a Mercurial Source Control Block for CruiseControl.NET. Another CI server I've heard of in use with Mercurial is Jenkins.
2) Correct. For integration with Main, I would prefer pulling (from either) and merging on my own machine before pushing, rather than merging on the server.
3) Exactly so.
It sounds like your developers are fairly disciplined, but just in case you need better control certain aspects of your operations:
You can use hooks to issue warnings when someone tries to merge their branch to Main. In-process hooks have to be written in Python, but they have access to the Mercurial API that way. You could also place hooks on the server that reject pushes containing a merge to Main not done by certain users.
One way some organizations control integration is a pull-only scenario. Only a few developers can push to the official repository and other developers send them pull requests. The Mercurial book's Chapter 6 covers this a bit, too.
A branch per developer is good. A branch per feature is also useful, allowing each developer to work on multiple things in parallel, then merging each to their branch when done. They just have to remember to close that feature branch before doing so, so the branch name doesn't keep popping up. This can be done with with clones as well, but I find myself preferring named branches since I have to keep work/backup/laptop development clones all synced so I can work on whateve, whenever. I still do expendable work as a clone first.
I'm a Subversion user, and I think I've got my head mostly around it all now. So of course now we're thinking of switching to Mercurial, and I need to start again.
In our single repository, we have the typical branches, tags, trunk layout. When I want to create a feature branch I:
Use the repo browser to copy trunk to branches/Features/[FeatureName].
Checkout a new working copy from branches/Features/[FeatureName].
Start working on it.
Occasionally commit, merge trunk in, resolve conflicts and commit.
When complete, one more merge of trunk, then "Reintegrate" the feature branch into trunk.
(Please note this process is simplified as it doesn't take into account release candidate branches etc).
So I have questions about how I'd fulfil the same requirements (i.e. feature branches rather than working on trunk) in Mercurial:
In Mercurial, is a branch still within the repository, or is it a whole new local repository?
If we each have a copy of the whole repository, does that mean we all have copies of each other's various feature branches (that's a lot of data transfer)?
I know Mercurial is a DCVS, but does that mean we push/pull changes from each other directly, rather than via a peer repository on a server?
I recommend reading this guide
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial//
In Mercurial, is a branch still within
the repository, or is it a whole new
local repository?
The equivalent of the subversion way of working would be a repository with multiple heads in mercurial. However, this is not the idiomatic way of doing things. Typically you will have only one head in a given repository, so separate repositories for each branch.
If we each have a copy of the whole
repository, does that mean we all have
copies of each other's various feature
branches (that's a lot of data
transfer)?
Yes, if you look at the history of the head of your local repository, then you'll be able to see all the feature branches that were merged in. But mercurial repositories are remarkably space efficient. For example, I have done a hg clone https://www.mercurial-scm.org/repo/hg to get the source for mercurial itself, and it is only 34.3 MB on an NTFS file system (compared to the source code download, which is 1.8 MB). Mercurial will also make use of hardlinks if your file system supports it, so there is little overhead if you clone a repository to another location on the same disk.
I know Mercurial is a DCVS, but does
that mean we push/pull changes from
each other directly, rather than via a
peer repository on a server?
One way of working is indeed to have each developer expose a public repository in which he pushes his own changes. All other developers can then pull what they want.
However, typically you'll have one or more "blessed" repositories where all the changes are integrated. All developers then only need to pull from the blessed repository. Even if you didn't explicitly have such a blessed repository I imagine people would automatically organize themselves like that, e.g. by all pulling from a lead developer.
Steve Losh's article on branching in mercurial linked above is fantastic. I also got into some explaining of branching and how the DAG works in a presentation I gave a couple of months ago on mercurial that's out on slideshare. The pertinent slides start at slide #43.
I think that understanding that all commits to the same repository are stored in a DAG (Directed Acyclic Graph) with some simple rules really helps demystify what's going on.
a node with no child nodes is a "head"
the root node has no parents
regular nodes have a single parent
nodes that are the result of a merge have two parents
if a merge node's parents are from different branches, the child node's branch is inherited from the first parent
Named branches are really just metadata labels on commits, but really aren't any different than the anonymous branches that happen when you merge someone elses work into your repository, or if you go back to an earlier version and then make a commit there to make a new head (which you can later merge).