We have two heads. One is our main development head and the other is one that I forgot about until today. We found a bug and fixed it in our main development branch, and I just realized it should be fixed in the older branch as well.
I think it would have been better to make the change on the older branch and merge that with the up-to-date branch, but we didn't do it that way. Can mercurial handle this? We haven't tried to do anything like this and I can't really wrap my head around how it would be done.
Yes, you have two good options:
Graft: new in Mercurial 2.0
This version introduced the graft command which can backport changes in an intelligent way. The "intelligence" is that it will use merges internally and this means that you get
Support for renames: Imagine that you fixed the bug in file foo.c on the development branch. In the older maintenance branch foo.c was called bar.c. Using hg graft, the change to foo.c can be correctly merged into the old bar.c.
Three-way merges: Grafting involves twisting the graph around and merging in that temporary graph. The advantage of three-way merges is that you can use your normal graphical merge tool to resolve conflicts.
To copy the tip of default onto old-branch you simply run
$ hg update old-branch
$ hg graft default
Transplant: older versions
Before we had the graft command, the transplant extension was the way to go. This simple extension will export a changeset as a patch and try to apply the patch onto some other revision.
Because we're dealing with "dumb" patches things like renames will not be taken into account and you will not get support for your merge tool since there is no three-way merge. Despite of this, I've found that transplant works really well in practice.
Using transplant is simple:
$ hg update old-branch
$ hg transplant default
This is very close to running
$ hg update old-branch
$ hg export default | hg import -
except that transplant also adds a piece of meta data that records the original changeset in the transplanted changeset. This can be used to skip future transplants.
Related
We've just spent two weeks working down the wrong path on a problem (with all the commits to our SVN repository that go with that). We've now come up with the right solution (which needs our code base to go back to what it was two weeks ago). We should have branched two weeks ago, but that is irrelevant now.
Clearly, I can make a second checkout of the project and then copy that over the current version of the repository and check that in.
Is there a cleaner way to do this without a second checkout?
There are many ways to do what you want. The simplest would be to check out a new copy of the codebase to a dev machine, specifying the revision for the commit made just before you went down the wrong development path. Then, simply check that code back in as the latest revision. Not only do you effectively "revert" the codebase to that revision, if you find out that some element of your wrong solution was useful after all, you still have easy access to those elements.
Also, as was said, you can branch the codebase at any time, at any revision. Simply cut a branch of the revision before you began your work, and continue along your new dev path. Keep in mind that merging this branch back into the trunk could be problematic; you'd want the end result of development in the branch to replace the codebase of the trunk wholesale. That's possible but it can get messy.
There are a few ways of handling this:
Revert your changes:
$ svn merge -r$rev2:$rev1 .
This is assuming that $rev2 > $rev1. This will back out the changes between these two revisions. If you're backing out a single revision, you can use this:
$ svn merge -c -$rev .
That is, the revision should be a negative number. This will back out just that one revision.
Recreate the Branch
If this work was not done on trunk, but on a branch, and you pretty much want to toss out that branch, you can simply recreate the branch, and even delete the old bad one. Branches (and tags) can be created from any point in time:
$ svn cp -r$rev $REPO/branches/$bad_branch/$proj $REPO/branches/$new_branch
$ svn delete $REPO/branches/$bad_branch
The solution provided by Mike works for me.
In a separate branch
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
(this undoes the change between 302 and 303).
Then you can commit the changes in your branch, test and then merge back to the trunk as normal.
I've been using source control systems for about 10 years, each obviously with their own idioms and practises.
I am currently using Mercurial for .NET development and have a particular requirement that I wonder what your opinions would be to best achieve my goal.
We develop a baseline product that is a kind of rolling release. Some customers need the product slimmed down (due to getting cheaper licenses) or bespoke work done. I tend to branch the "trunk" (default branch in Mercurial), do the bespoke work and create a build.
When new work is done in "trunk" and I need a new build from the bespoke branch, I will merge the changes using hg merge -r CHANGESET_NUM_FROM_DEFAULT_HERE and then do a build.
This works fine, but the bespoke branch quickly gets filled with commits that are related to "trunk" and not really bespoking features. This means when I need to look through the changesets for this branch they are cluttered.
What I really want it to shift where the branch "junction point" begins, so the bespoke changelist only contains bespoke check-ins, but the parent of the bespoke branch changes.
I tried to use the rebase extension as this looks like it should do this, but it instead does many merges and still clutters up my bespoke branch.
Is there a way of keeping my bespoke branch clean? Or am I going about things the wrong way?
Your bespoke branch is clean now. But - if you want don't see mergesets in branch log, just skip in log
hg help log
options:
...
-M --no-merges do not show merges
hg log -r 55:tip --template "{branch}:{rev}\n" -b default
default:55
default:56
default:57
default:60
default:61
default:63
default:65
default:66
hg log -r 55:tip --template "{branch}:{rev}\n" -b default -M
default:55
default:56
default:57
default:61
default:65
default:66
and screenshot of graph from THG
I'm trying to do some work on a project called NS-3, but my problem isn't project specific so I thought I'd ask here as well as the relevant mailing list.
Basically, a copy of the then current project code was made, and a fresh repo made of that code. Work was done on both the 'forked' version and the trunk.
So cloned the forked source, cd in, and hg pull <latest-dev>, hg merge, and while it wasn't a perfect merge, the changes that were unmergable were all related to one library change, so easily fixed (in theory). Naturally this optimistic attempt failed to build.
Now I'm not entirely sure where to go from here, I'm new to DCVS so please; ideas directed towards a 5 year old!
How can I find out which changeset of the forked version was last merged against the dev-trunk since they're separate but related repos?
The Case Where You Started With a Copy Not a Clone:
If this is what happened:
Project Exists
Copy (not clone) of project is made
hg init is run in each separate copy, creating two unrelated repositories
work is done in both copies
Then to merge them you want to do this in the newest of the two unrelated repos:
hg update 0, which jumps the repository back to its earliest point -- the point where it last looked identical to the other
copy in the contents of the working directory from the other repository
hg commit, which creates a new head
hg merge, which merges the two heads and also provides a base revision, which helps the merge process.
The key is getting a base revision involved if possible. What DVCS systems bring to the table that CVS and SVN don't is that every merge is a 3-way merge between two heads and the most recent common ancestor. Faking that common ancestor by creating the new head off the last point the two repos looked the same (revision 0 in the copy) simulates a base revision.
The Case Where You Started With a Clone Not a Copy
This is the classic DVCS case and there shouldn't be much you need to do. Just go into one of the clones, hg pull from the other and fire off the hg merge. If the merge requires input you'll use hg resolve to provide it, and when you're done hg commit.
If at this point your code isn't building/running then you need to just start debugging. Use hg blame to see what was being done near the lines that won't compile and try to suss out what was being done and how to work on it.
The merge process is much easier the more frequently you do it. Pull in up-stream changes daily, not monthly.
You can turn on the GraphLog extension and use the hg log -G command to see the point at which the two lines of development diverged, but in the end merging is development, and you just need to approach a non-building merge like you would any other software defect.
Scenario: After your last commit, you decided to do some extensive refactoring of the codebase. After a time, you realize it is taking longer than expected, and you'd really rather put off the refactoring for another time, and work on more pressing tasks. But you don't want to lose all of the refactoring work you've done so far.
So, is there a way to "archive" or "branch" the working copy (essentially, set it aside but keep it in the repository for later access), and then revert to the last good commit and resume from there, without fear of creating multiple heads or getting the two mixed up?
Don't worry about "the fear of two heads". Two heads is a very normal state. It's called anonymous branches, and it's one of the ways people do temporary branches in Mercurial.
Just commit, and then update to tip-1 and you're ready to go:
hg commit -m "working on XXX"
hg update -r "tip-1"
and away you go. If you want to drop a bookmark (less permanent than a tag) on that head you can, but there's no need to worry about it.
You can always push one head without pushing another using hg push -r HEAD where that can even be hg push -r .
Don't fear heads -- they're what makes a DAG based VCS powerful.
You can do this with the mq, attic or shelve extensions.
Assign a tag to your refactor revision
Commit the tag
Clone the repository again
Revert to the stable version
Work from the stable version
Don't worry about multiple heads, you can easily merge later
Since mercurial uses hard links, you can keep both repositories on your local machine with minimal space used.
commands:
$hg tag Refactor
$cd ..
$hg clone Refactor Stable
$cd Stable
$hg revert -r REVISION_NUMBER
extra help:
http://hgbook.red-bean.com/
http://kiln.stackexchange.com/
You can do it the simple way:
$ hg diff -g > tmp
$ hg revert --all
Your changes will now be stored in tmp. You can restore them with
$ hg patch --no-commit tmp
and you'll be back where you were. There are extensions like shelve that automates the above for you.
In git you would do a 'stash'. According to This hg has 'shelve', but it requires an extension.
How do I get a patch from a commit in order to send it to another developer? And how do I best avoid a merge conflict with this patch when merging our trees at a later date?
If you know how please explain how to do this in your VCS of choice such as subversion, git, Mercurial, bzr or etc.
In git you can pipe the output of git-diff between two commits like this:
git diff fa1afe1 deadbeef > patch.diff
Send the patch.diff to the developer and let him git-apply it to his workspace like this:
git apply patch.diff
If the other developer already has the commits available in his repository he could always pipe it in himself without merging like this:
git apply < git diff fa1afe1 deadbeef
You can then add and commit the changes in the diff the usual way.
Now here comes the interesting part when you have to merge the patch back to the master branch (that is public). Consider the following revision tree where C* is the applied patch from C in the master branch:
A---B---C---D master, public/master
\
E---C*---F feature_foo
You can use git-rebase to update the topic branch (in this example named feature_foo) with it's upstream head. What that means is when you type in the following:
git rebase master feature_foo
Git will rearrange the revision tree like this and will also apply the patch itself:
A---B---C---D master, public/master
\
E*---F* feature_foo
Merging to the upstream branch will now be an easy fast-forward merge. Also check that the new commits E* and F* work as the previous E and F respectively.
You can do the same thing against another developer's branch using the same steps but instead of doing it on a public repo, you'll be fetching revisions from the developer's repository. This way you won't have to ask the other developer for a patch if it is already available from what he published at his repo.
Please note to never rebase a public branch because the command will rewrite git history which is something you don't want to do on branches that people depend on and will create a mess when merging to remote repositories. Also never forget to integrate often so others in your team can take part of your changes.
In SVN you can simply make your changes then before commiting, pipe the output of the svn diff to a file as such
svn diff > mypatch.diff
you can then revert your changes and apply the patch at a later date using
patch -p0 -i mypatch.diff
As always don't blindly apply patches to your code and always inspect them first.
You may also find that the patch will break your source code if the source files have changed significantly enough since the patch was taken.
You also can not guarantee that there will not be merge conflicts when you attempt to check in the code.
Bzr handles sending a "merge directive", meaning it sends the patch for you so that the other party can simply click "OK" to merge and there's less futzing around with patch/apply etc.
just:
$ bzr send -o mycode.patch
In Subversion there is no nice way of doing this. Yes, you can use svn diff + patch but this will only postpone your problems until you are going to merge and by then chances are that you've forgotten about it.
The way you would do it in Subversion would be to create a branch, do the commit on the branch and ask the recipient of the patch to switch to the branch. Then you can merge the branch back to trunk in the usual way.