How to handle merges with hgsubversion? - version-control

I am trying to contribute to a project that uses Subversion. I used Mercurial and its hgsubversion extension to clone the repo. My work takes place on a feature branch.
How do I keep the feature branch up to date with stuff that happens on the default branch (hg speak) aka the trunk (svn speak)?
So I used hg up feature to update to the feature branch, then hg pull which gave me changesets on the default branch. So I did hg merge default, the committed the merge, then tried hg push to send my changesets to Subversion. And Mercurial said: "Sorry, can't find svn parent of a merge revision."

I have finally figured out how to get my repository un-wedged after an event like that described in the question, so that I can continue work without having to re-clone the parent repository (which is, obviously, a quite slow operation when you are pulling from Subversion!). If the "tip" of Subversion outruns you so that you cannot push any more, just make sure that you have the built-in "rebase" extension activated in your Mercurial through a $HOME/.hgrc line like this:
[extensions]
rebase =
And then you should be able to run this command when your repository gets wedged:
$ hg rebase --svn
If I understand this correctly, it dissolves your current branch that has taken you away from Subversion HEAD, and rebuilds it atop the branch "tip" in Mercurial that corresponds to the HEAD in Subversion. From there, you can keep working and successfully do pushes again. It has always worked for me so far; let me know if you run into any problems!

Mercurial as a few different branching modes: http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
The one you're describing is 'named branches', which is the most popular when you're working with a repo that's accessed only via mercurial (or hg-git).
However, when you're using hg-subversion so that you're pushing changes to/from subversion, which only nominally has branches, you're better off keeping all of your mercurial changes in the 'default' named branch, and using the 'clones and branches' pattern (which I prefer anyway).
Specifically, that message Sorry, can't find svn parent of a merge revision. isn't a descendant of a revision that has a direct match in subversion.
Were I you, I'd reclone from svn, and then move my work into that repo's 'default' branch with the 'transplant' command (packaged extension). If you want multiple features in parallel w/ hg-subversion use separate clones (they're so cheap), as it's more in line with how subversion thinks about branches.

I needed to figure this out for myself and wrote it up here:
http://notebook.3gfp.com/2010/05/pushing-a-new-feature-from-a-mercurial-repo-into-an-svn-repo/
I haven't yet figured out how to close a branch in subversion and have the mercurial graph look correct.

Related

How best to clean up Mercurial repository with many old open branches?

I have inherited a code base stored in a mercurial repository.
The repo has about thirty open branches, including:
old release branches for releases that have long been superseded.
old feature branches that have been merged into trunk(*) but not closed.
old feature branches that have been abandoned (not merged anywhere).
Many of these old branches have not been used for years.
I would like to close these old branches so that hg branches will give me an accurate picture of current ongoing work.
If I close so many old branches, I imagine that's going to mess up my graph in TortoiseHg and make it harder to follow what's been going on in the past.
That's not a massive problem, but it has me wondering is there a better way to clean up a mercurial repo with many old and inactive branches?
(*) default was abandoned and replaced with a primary branch named 'trunk'.
Closing branch in Mercurial just hide head of this branch from hg heads output, nothing more: merged branch with not have head anyway
If you perform partial clone, you'll get in clone only needed|used parts of source repo: hg clone -r tip ... will clone only ancestors of current tip, all unmerged branches will be ignored (deleting merged branches is, anyway, bad idea)

How should I structure my git-svn workflow to avoid "revision1 is merged into revision2, but does not have git-svn metadata"

I am using git-svn in my workplace since our current version control server is subversion and switching completely to git does not seem to be on the horizon for now (*cry*)
My workflow is as follows
I have the following branches
master tracks remotes/trunk
local/0.4 tracks remotes/0.4
work is my development branch for the master branch
work-0.4 is my development branch for the local/0.4 branch
I work in my work branches, then I merge to master and local/0.4 using
git merge --no-ff <branchname>
After that I check in to svn via
git svn dcommit
and I use
svn.pushmergeinfo=true
to update the svn:mergeinfo properties so my colleagues won't get angry with me messing up that metadata for them :)
However, I just had the following problem which stumps me.
I had done two commits on the work-0.4 branch, then I merged these to my local/0.4 branch with git merge --no-ff work-0.4. After this, I did git svn dcommit and recieved the following message
Committing to https://svn-server ...
e138050f6ebd2f2ca99cbefc5e48acae412e1f86 is merged into revision f5f2345e8e5fc64
20423bdc00397b5853b3759c4, but does not have git-svn metadata. Either dcommit the
branch or use a local cherry-pick, FF merge, or rebase instead of
an explicit merge commit.
After some rebasing and reset'ing of branches I managed to push everything to svn, but my solution entailed doing a rebase of my local/0.4 branch to the work-0.4 branch which in turn meant that I did not get to squash my two git-commits into one svn-commit :/
I feel that I'm probably doing something wrong with my workflow here, and it might be related to svn.pushmergeinfo. The docs for svn.pushmergeinfo says
config key: svn.pushmergeinfo
+
This option will cause git-svn to attempt to automatically populate the
svn:mergeinfo property in the SVN repository when possible. Currently, this can
only be done when dcommitting non-fast-forward merges where all parents but the
first have already been pushed into SVN.
and to be honest, I'm not quite sure that I understand that correctly? Am I doing something weird here that makes svn.pushmergeinfo not work correctly? How should I structure my workflow to optimally work with git-svn correctly (setting proper mergeinfos etc)?

Mercurial: Merging from unknown divergant 'branch'

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.

SVN: Synchronize branch with trunk in Eclipse?

I have an SVN branch and a trunk. The trunk changes regularly and the branch doesn't.
Every now and then (let's say once per week) I want to update the local working copy of the branch with the latest changes of the trunk.
Ideally I would want to do this the same way as I do it with the latest version of the branch: with Eclipse : Team->Synchronize, so I can review all changes before updating.
Is this also possible with a different repository (for example : trunk) ?
If not, how do people review the changes before updating then??
I looked at Team->Merge, but this seems to update the changes directly to my working copy, without the possibility to review the changes first (the Preview-function is confusing, I think, and doesn't provide the nice side-by-side view of changes/conflicts that Synchronize has).
The right way to do this is with Merge. Subclipse includes a merge client that makes this easy to do. You are right that it does not give you a true preview, but the way it works is better from a Subversion perspective. The Merge Results view UI is basically the same as the Synchronize view. It lets you easily examine every change that the merge made in your working copy and the Eclipse compare editor that it opens makes it very easy to take out any parts of the change that you do not want in your code before you commit.
The problem with trying to do this from the Synchronize view is that you are then doing the merge yourself using code editors and Subversion has no awareness of what is merged. If you let Subversion first do the merge, then it can update all of its metadata properly and it is perfectly fine for you to then fixup the code to be the way you want it before you commit the results of the merge.
I'd checkout both branch and trunk as a separate eclipse projects into workspace. Then use some merging tool, for example meld to merge changes between them. After merge you can refresh branch in Eclipse and synchronize it with svn repository - now you can review all changes. (it's how I do it, since I do not believe svn eclipse plugin ;))
I agree that it is not really intuitive by design, but Mark is right, you "synchronize" your changes when committing them back to the trunk:
first make sure your local branch is completely synchronized with your repository branch (no changes)
Team -> Merge... your local copy of the branch with the repository trunk
you now have a local version of that merge
you can locally edit this version, make sure tests are working and there are no compiler errors
finally you synchronize your local merged branch version with the repository branch and commit all changes that have been made
besides, the same way you'll merge your branch back into the repository trunk
make sure all changes of your branch are committed to the repository branch
switch to the trunk Team -> Switch...
merge your trunk with your branch Team -> Merge... (Tab 'Reintegrate')
you now have a local version of the merge, you may edit the changes and review them, make sure that you have a working version now
synchronize your local trunk (merged version) with the repository trunk
commit all changes that you want to appear in the trunk
i recommend to commit all changes that you've made locally to your merge, since you've tested them locally. if you commit just a few changes, make sure the repository version is still working then with missing changes

Merge two checkouts in bazaar

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.