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
Related
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.
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.
I'm just starting out with bazaar, and I've found that the checkout feature is the most useful for the way I work - namely I can c/o from a "master copy", do some development and then commit my changes in the new directory. This then updates the "master copy".
But what if I'm working on (eg) two projects, changing different portions of code? Say:
~/master - master copy
bzr co master ./gui
bzr co master ./engine
So I'm doing gui-related stuff in the ./gui directory and under-the-hood stuff in ./engine. How should I commit my changes? If I commit gui first, then engine, I guess any conflicts will be flagged in engine?
Is there a way to merge gui and engine, and then do just one commit to the master copy?
To make things a little more complicated, how about if I do this:
bzr branch gui ./mouse
Now I perhaps I've been working on mouse, but also on gui. If I want to merge the code from gui AND mouse, and then commit to master, what is the best way to manage this? Or indeed, if I also:
bzr branch gui ./keyboard
If I've changed altered gui, keyboard and mouse, should I hierarchically merge - ie mouse+keyboard, then merge this with gui, then commit gui to master?
I hope it is clear what I'm trying to achieve! Thanks in advance for your time.
If you have two checkouts, any time you commit changes to one, you will first have to pull down any changes from the other one, potentially having to resolve conflicts at each step. This is generally a good idea, since it's easier to resolve conflicts over time and make sure your code doesn't diverge too much.
However, it sounds like you want to have separate developers working on "gui" and "engine", or you just want to save your conflict resolution till development on both branches has completed. In this case, you should probably create them as independent branches with "bzr branch". Each branch can use local commits and not worry about conflicts with each other. Then when it comes time to merge you can do it one of 3 ways, all of which get the same end result:
1. Merge one branch into the other, then push it up to master:
cd gui
bzr merge ../engine
# manually fix any conflicts
bzr commit
bzr push #back up to main
The downside to the above method is that your "gui" branch now has the "engine" changes in it. Which is fine if you're going to throw away both branches once they're pushed back into the mainline. But if you want to keep the branches longer, you can:
2. Merge into the mainline:
cd master
bzr merge ../gui
bzr commit
bzr merge ../engine
# manually fix conflicts
bzr commit
This has the upside that you still have "gui" and "engine" as separate branches, but you've had to commit one to master before you were sure that they would both work together. So you really probably want to:
3. Create a merge branch:
bzr branch ~/master gui-engine-merge
cd gui-engine-merge
bzr merge ../gui
bzr commit
bzr merge ../engine
# manually fix conflicts
bzr commit
bzr push ~/master
# since this branch was only for merging, you don't need it anymore:
cd ..
rm -r gui-engine-merge
Yes, bzr should prevent you from checking in changes from the engine repo if it detects conflicts. Normally, you first do "bzr up" just prior to check-in and then make sure your stuff plays nice with others.
As for the second part of your question, dealing with mouse/keyboard branches, this is how I would normally do it. Simply cd into the gui dir, and then do:
bzr merge ../mouse
After merging the changes, you can then commit from the gui directory and it will send the changeset to the "master" directory.
Note that I'm hardly a bzr expert, but this is the way I've been dealing with SVN repos.
A common scenario when using source control is to have a development branch along with versioned release branches. We use CVS, with HEAD as the development branch, and a branch named e.g. release-6-2 for the current release of a product.
Development of new features go into the development branch only, but bug fixes sometimes have to be checked into both the development branch and the current release branch. This can get quite tedious at times, so I am looking for practical ways to accomplish this.
When a file to be commited is in synch on the two branches, I am in particular looking for a quick "commit to these branches" solution.
(We use CVS as our source control system, so any CVS-specific answers are nice. However, it is also interesting to see whether other source control systems can offer a better way.
On the client side we use Eclipse, so Eclipse solutions are good. But if you have a non-Eclipse solution, that is fine too.)
Apply your fix to the oldest release branch required. Then merge the change to the next release branch and so on until you merge from the last release branch to the HEAD.
Say the oldest version of your product is 1.0 and you also have 1.1 and 1.5 releases. New features for the next release are being added to the HEAD. If a bug is found in 1.0, you apply the fix to the 1.0 branch. Merge from 1.0 to the 1.1 branch. Merge from 1.1 to the 1.5 branch, and finally merge from the 1.5 branch to the HEAD.
Merging from branch to branch is better than applying the fix manually to each branch.
With CVS you have to mannually keep track of what versions are merged, so that you do not include the same revisions when you do your next merge.
If you change to use Subversion, merging from branch to branch is easier. Eclipse's subversion tool will keep track of what revisions you have previously merged, greatly simplifying the task of doing repeated merges between two branches.
Changing to Subversion from CVS is easy(ish). You won't be the first to have made such a move.
Like awalshe said, it's better to merge between branches. To cherry-pick a merge, the method described in Pragmatic Version Control using CVS is very good:
In the branch - tag (PRE_FOO) before the change, make the changes and commit, tag after the change (POST_FOO). Then, in trunk, merge using the tags:
cvs up -j PRE_FOO -j POST_FOO
Merging between branches is much easier and safer in SVN, and it's trivial to convert your entire CVS history to SVN - see cvs2svn. You should use either SVN 1.5, or - with earlier SVN versions - svnmerge.
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.