UPDATE : Repository bloat (at least in the merge-then-merge-back scenario) can be solved very easily : "bzr pack --clean-obsolete-packs". The content of this article is interesting in the things it examines, but somewhat outdated by this update. Read at own risk...
Bazaar is awesome. I say that almost every time I talk about Bazaar. I love it.
However, there are some use cases where you can end up with repository bloat, completely unnecessarily.
Repository bloat occurs when Bazaar decides - for whatever reason - to make a new version of an existing revision, and thereby duplicate data that was in the revision.
So for example, you have a 5MB file and you add it to a branch, and then merge the branch with the trunk. Trunk's repository size should increase by roughly 5MB, you say? Well, should, you're right, but depending on how you do it, you can actually end up with a 10MB increase instead.
Repository bloat.
So how do you avoid it?
Well, I've noticed repository bloat in two main situations (although there are likely more). Both situations involve the trunk and branch diverging - so if your workflow is such that the trunk and branch are always sync'ed before divergence happens (i.e. when there are only changes on one side or the other but not both), then repository bloat won't be a problem for you (but rare will be workflows where you can guarantee that!)
Here are the two repository bloat scenarios I've noticed :
1) rebase : your revisions get rewritten to your local repository.
e.g.
md trunk
cd trunk
bzr init
echo Hi>readme.txt
bzr add
bzr commit -m "trunk commit"
cd..
bzr branch --stacked trunk branch
cd branch
(put 5MB file called BigFile.dat in branch folder)
bzr add
bzr commit -m "Added BigFile.dat in branch"
So far so good. And if you rebase at this point, you're fine ('coz nothing will happen).
But if we continue :
cd ../trunk
echo A change in trunk>>readme.txt
bzr commit -m "Another trunk commit"
cd ../branch
bzr rebase
... well, the rebase runs just fine, but if you check the size of the .bzr folder in the branch, it is around 10MB, not 5!
Repository bloat!
How to avoid repository bloat when rebasing?
Well, the conslusion I've come to is : let the repository bloat, and merge or push to trunk, and then follow my instructions on purging stacked branches to remove the bloat. (The bloat in rebase cases is only in the branch, not the trunk. And fortunately, it seems that pushing the bloated repository to the trunk only pushes the new versions of the affected revisions instead of pushing both old and new versions - i.e. the bloat is fortunately not propagated back to the trunk in this case.)
(Not using stacked branches? Sorry, not my use case, so I haven't investigated further and thus can't tell you for sure what will work - although if you get really really desperate you can make a new branch --no-tree and then delete the .bzr folder in your existing branch and replace it with the .bzr folder in the new branch. Again - only do that at a point where trunk and branch are in-sync.)
2) merge to branch then merge to trunk
This is a pretty standard operation if you've been working on your branch for a while and the trunk has changed in the meantime.
You can't pull the trunk changes into the branch. Once the two are out-of-sync, you're forced to use merge or rebase. The rebase scenario is covered above, and results in duplication of data in branch revisions from the point of divergence onwards.
The merge scenario is what we're covering here. Its repository bloat characteristics are more interesting. Whereas rebase results in duplication of data in BRANCH revisions from the point of divergence onwards, merge can result in duplication of data in TRUNK revisions from the point of divergence onwards, assuming that you proceed to merge branch back into trunk. (If you PUSH branch back into trunk, I suspect (but haven't tested) that you'll get away without repository bloat - but then you lose the trunk's unique perspective on the change history - i.e. your log and qlog are thereafter from the branch's perspective instead of from the trunk's perspective.)
e.g.
md trunk
cd trunk
bzr init
echo Hi>test.txt
(add 5MB file into trunk folder)
bzr add
bzr commit -m "Initial commit in trunk"
cd..
bzr branch --stacked trunk branch
cd branch
echo bla>test2.txt
bzr add
bzr commit -m "First commit in branch"
cd ..
cd trunk
(replace 5MB file in trunk folder with a different 5MB file of same name)
bzr commit -m "Modified BigFile.dat"
cd ..
cd branch
OK - so far so good - but trunk and branch have diverged and now we're at the point we want to make them converge. Normally we might do :
bzr merge ../trunk
bzr commit -m "Merged trunk changes into branch"
cd ..
cd trunk
bzr merge ../branch
bzr commit -m "Merged branch into trunk"
... but if you do that, you'll get our lovely friend Repository Bloat(TM)!
Why?
Well, it seems that merging the 5MB file's modification revision in from trunk to branch, which requires a commit, results in that 5MB file's data ending up in a second revision, and when we merge back into trunk, that second revision ends up in the trunk's repository. (Interestingly, does not happen if the file was newly created in the trunk - just if it was already known to the branch and was updated in the trunk.)
10MB repository growth for a 5MB file. Baaaaad.
(To emphasize : the final trunk repository size is 15MB : 5MB after initial commit of the 5MB file, then a further 5MB totalling 10MB after second commit to trunk, and finally a third 5MB totalling 15MB after merging in from branch and committing again.)
We saw how to get around it with the rebase bloat problem. How to get around it with the merge bloat problem?
One way is to avoid the merge-then-merge-back entirely. If trunk has changed and you can't pull the changes into the branch because trunk and branch have diverged, then rebase instead. You might/will end up with branch repository bloat, but I cover how to deal with that in the preceding section on repository bloat caused by the rebase operation.
All a bit tedious? Perhaps. But easily scriptable.
Of course, if your workflow relies on the merge process, you might just have to accept the bloat. Not ideal. You might be able to avoid the bloat by using the merge -c option when merging back into trunk, to "cherry-pick" only the branch revisions that are not themselves merge-from-trunk commits. And there are yet more desperate approaches one could take if needed - e.g. export branch changes to a patch set, delete branch, recreate it from trunk and apply patches!!! Well y'know, it would probably work.......
And maybe I need my head checked, but even with a few little problems like this, I still absolutely love Bazaar. (Yes - relatively little. In practice, does it matter if your repository is twice the size it needs to be? Sometimes yes, usually no. For me, it's a little more critical than for others due to certain peculiar circumstances, and hence my investigations in how to avoid/resolve repository bloat.) Thanks for stopping by! :o)
Showing posts with label Bazaar. Show all posts
Showing posts with label Bazaar. Show all posts
Thursday, April 14, 2011
Purging stacked branches in Bazaar
Stacked branches are awesome!
Shared repositories go so far, but don't work so well if the parent and child branches are far away from each other in the file system (nor if they are on different volumes), and shared repositories have the weakness that if you create a revision, it lives on forever, even if you later delete the branch associated with that revision. (You can't actually get the revision back, not by any way I've found (UPDATE : "bzr heads --all" looks like it lets you find "lost" revisions.), but the shared repository's size never goes down - it just keeps accruing more and more data, never letting any of it go. (UPDATE : I'm no longer entirely sure when the repository's size changes - "bzr pack --clean-obsolete-packs" does wonders))
In contrast, stacked branches can be used at any time both the parent and child branch are simultaneously accessible (even if they're on different hard disks or even one on a URL), and best of all, if you make an experimental branch and decide to kill it, bam! - its history is gone forever and your trunk repository isn't forever bloated by the revisions you decided to nuke.
And they're extremely useful if you want the same library to be in multiple apps (in different Bazaar repositories) and want to be able to edit the source code in each copy of the library independently but have them all closely associated.
And did I mention they save a lot of storage space?
But thence cometh the problem : stacked branches start out tiny, because they aren't carrying the five decades of history that the trunk contains, but after that they grow.
And grow.
What if you just want the stacked branch repositories to stay nice and trim, like they were when you made them?
There doesn't seem to be any built-in feature in Bazaar to do that.
push, pull, merge, do whatever you want - the stacked branch's repository only grows.
So we resort to a little bit of - very effective - skullduggery.
FIRST UP, ENSURE YOU TRY THIS EXPERIMENTALLY FIRST. It worked for me, but might destroy you and your world and your company's beautiful source code and get you fired. THIS USES UNDOCUMENTED TRICKS. So it could stop working when new versions of Bazaar roll out. I have and accept no responsibility for what happens to you if you try this yourself!
1) Purging the stacked branch history obviously needs to be done at times that the stacked branch is in-sync with the trunk. So make sure you've merged or pushed the branch into the trunk.
2) In the branch, delete all files in these two folders :
.bzr\repository\indices
.bzr\repository\packs
3) Still in the branch, locate this file :
.bzr\repository\pack-names
... and change its content to the following five lines :
B+Tree Graph Index 2
node_ref_lists=0
key_elements=1
len=0
row_lengths=
Voila! Do a bzr status or bzr log and the history is all there - its just now coming from the stacked-on branch like you wanted all along. You have successfully purged the stacked branch's history.
Shared repositories go so far, but don't work so well if the parent and child branches are far away from each other in the file system (nor if they are on different volumes), and shared repositories have the weakness that if you create a revision, it lives on forever, even if you later delete the branch associated with that revision. (You can't actually get the revision back, not by any way I've found (UPDATE : "bzr heads --all" looks like it lets you find "lost" revisions.), but the shared repository's size never goes down - it just keeps accruing more and more data, never letting any of it go. (UPDATE : I'm no longer entirely sure when the repository's size changes - "bzr pack --clean-obsolete-packs" does wonders))
In contrast, stacked branches can be used at any time both the parent and child branch are simultaneously accessible (even if they're on different hard disks or even one on a URL), and best of all, if you make an experimental branch and decide to kill it, bam! - its history is gone forever and your trunk repository isn't forever bloated by the revisions you decided to nuke.
And they're extremely useful if you want the same library to be in multiple apps (in different Bazaar repositories) and want to be able to edit the source code in each copy of the library independently but have them all closely associated.
And did I mention they save a lot of storage space?
But thence cometh the problem : stacked branches start out tiny, because they aren't carrying the five decades of history that the trunk contains, but after that they grow.
And grow.
What if you just want the stacked branch repositories to stay nice and trim, like they were when you made them?
There doesn't seem to be any built-in feature in Bazaar to do that.
push, pull, merge, do whatever you want - the stacked branch's repository only grows.
So we resort to a little bit of - very effective - skullduggery.
FIRST UP, ENSURE YOU TRY THIS EXPERIMENTALLY FIRST. It worked for me, but might destroy you and your world and your company's beautiful source code and get you fired. THIS USES UNDOCUMENTED TRICKS. So it could stop working when new versions of Bazaar roll out. I have and accept no responsibility for what happens to you if you try this yourself!
1) Purging the stacked branch history obviously needs to be done at times that the stacked branch is in-sync with the trunk. So make sure you've merged or pushed the branch into the trunk.
2) In the branch, delete all files in these two folders :
.bzr\repository\indices
.bzr\repository\packs
3) Still in the branch, locate this file :
.bzr\repository\pack-names
... and change its content to the following five lines :
B+Tree Graph Index 2
node_ref_lists=0
key_elements=1
len=0
row_lengths=
Voila! Do a bzr status or bzr log and the history is all there - its just now coming from the stacked-on branch like you wanted all along. You have successfully purged the stacked branch's history.
Sunday, April 5, 2009
Graphical add/commit in Bazaar without the slowness of TortoiseBZR
How can you quickly & easily pick which files you want to add to Bazaar?
I've had too many painful experiences (not Bazaar's fault) of going "bzr add", and then discovering that amidst the dozens of files I DID want to add, there were a whole bunch that I DIDN'T.
Removing them is a bit of a pain - I tend to use very long self-descriptive folder names and file names, so if a big "bzr add" operation added dozens of files, and I needed to manually remove perhaps a dozen or more, it was very time inefficient.
Fortunately, Bazaar has the answer! I just didn't discover it until yesterday.
bzr qadd
That little "q" at the beginning of the "add" command brings up a GUI window, allowing you to very quickly & easily select exactly which files you want added.
Bazaar, I love you! :o)
P.S. You can also use "bzr qcommit", which is a FABULOUS way to do a partial commit. And "bzr qdiff" if you want a diff that is easier to read than "bzr diff".
I've had too many painful experiences (not Bazaar's fault) of going "bzr add", and then discovering that amidst the dozens of files I DID want to add, there were a whole bunch that I DIDN'T.
Removing them is a bit of a pain - I tend to use very long self-descriptive folder names and file names, so if a big "bzr add" operation added dozens of files, and I needed to manually remove perhaps a dozen or more, it was very time inefficient.
Fortunately, Bazaar has the answer! I just didn't discover it until yesterday.
bzr qadd
That little "q" at the beginning of the "add" command brings up a GUI window, allowing you to very quickly & easily select exactly which files you want added.
Bazaar, I love you! :o)
P.S. You can also use "bzr qcommit", which is a FABULOUS way to do a partial commit. And "bzr qdiff" if you want a diff that is easier to read than "bzr diff".
UPDATE : The preceding works fine if you used the Windows installer for Bazaar. If you are using Linux, you need to install a Bazaar plugin called QBzr - see bialix's comments on this article.
Friday, April 3, 2009
Merging unrelated branches in Bazaar
The skinny : 'cd <working-tree-to-merge-into>', then 'bzr merge <branch-to-merge-with> -r0..-1', and then 'bzr commit "Merged with {bla}"'.
I continue to love Bazaar.
I've wondered for a while : "How can I merge two completely unrelated branches?"
Scenario : I'm working on a large website with an extensive ASP.NET section, and an extensive Flash section. The ASP.NET section is very mature. The Flash section has just begun. I want to be able to version control the Flash stuff in the same repository as the ASP.NET stuff, but in unrelated branches, and eventually merge the branches once the Flash stuff matures somewhat.
Can do! But it took a bit of figuring out.
Along the way, I kept bumping my head against this error message from Bazaar :
bzr: ERROR: Branches have no common ancestor, and no merge base revision was specified.
Suppose my folders were :
C:\BzrRepo\AspDotNetStuff
and
C:\BzrRepo\FlashStuff
I was trying to do :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
That wasn't working, so I tried using the --revision= option to specify a base revision (as hinted by the error message) :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --revision=1
Still no go.
So I looked at the --change= option.
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1..27
(27 being the latest revision number in the FlashStuff branch.)
Still no go - it tells me that the --change= option cannot handle revision ranges - it can only handle one specific revision number.
OK, so what if I try to integrate just the very latest change?
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=27
That didn't work either. Instead, it created lots of conflicts.
Ah - finally I think I see the light!
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1
Yes! Progress! It worked! i.e. I have to start with the very first change in the unrelated branch.
Now will it let me merge the remaining changes?
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
Nope - it complains that I have uncommitted changes.
Easily fixed :
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"
Good.
And now let's try the merge again :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
Bonanza! It worked!
And I have now successfully merged two COMPLETELY UNRELATED branches that lived under the same repository.
In summary, the quick way to do it :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged fully with FlashStuff"
And I'm a happy camper. :o)
UPDATE : Thanks to bialix (in the comments) for pointing out a simpler way to accomplish the same thing :
Slightly different syntax, accomplishes the same thing, but more concise. Did I mention I love Bazaar?
I continue to love Bazaar.
I've wondered for a while : "How can I merge two completely unrelated branches?"
Scenario : I'm working on a large website with an extensive ASP.NET section, and an extensive Flash section. The ASP.NET section is very mature. The Flash section has just begun. I want to be able to version control the Flash stuff in the same repository as the ASP.NET stuff, but in unrelated branches, and eventually merge the branches once the Flash stuff matures somewhat.
Can do! But it took a bit of figuring out.
Along the way, I kept bumping my head against this error message from Bazaar :
bzr: ERROR: Branches have no common ancestor, and no merge base revision was specified.
Suppose my folders were :
C:\BzrRepo\AspDotNetStuff
and
C:\BzrRepo\FlashStuff
I was trying to do :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
That wasn't working, so I tried using the --revision= option to specify a base revision (as hinted by the error message) :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --revision=1
Still no go.
So I looked at the --change= option.
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1..27
(27 being the latest revision number in the FlashStuff branch.)
Still no go - it tells me that the --change= option cannot handle revision ranges - it can only handle one specific revision number.
OK, so what if I try to integrate just the very latest change?
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=27
That didn't work either. Instead, it created lots of conflicts.
Ah - finally I think I see the light!
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1
Yes! Progress! It worked! i.e. I have to start with the very first change in the unrelated branch.
Now will it let me merge the remaining changes?
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
Nope - it complains that I have uncommitted changes.
Easily fixed :
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"
Good.
And now let's try the merge again :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
Bonanza! It worked!
And I have now successfully merged two COMPLETELY UNRELATED branches that lived under the same repository.
In summary, the quick way to do it :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff --change=1
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff revision 1"
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged fully with FlashStuff"
And I'm a happy camper. :o)
UPDATE : Thanks to bialix (in the comments) for pointing out a simpler way to accomplish the same thing :
C:\BzrRepo\AspDotNetStuff> bzr merge ..\FlashStuff -r0..-1
C:\BzrRepo\AspDotNetStuff> bzr commit -m "Merged with FlashStuff"
Slightly different syntax, accomplishes the same thing, but more concise. Did I mention I love Bazaar?
Monday, March 16, 2009
Bazaar - managing local feature branches with lightweight checkouts
Bazaar is the BEST source code versioning system in the world, or at least, the best non-commercial one (I can't comment on commercial ones except Visual SourceSafe, which epitomises dog-ness).
Well, that's my opinion, after using SVN and Visual SourceSafe, and reading fairly extensively about other systems.
But it can be hard to get started, just because it is SO powerful and has SO many options and can be used in SO many different ways.
If you're a single developer who just uses it to track their own work, and never makes feature branches, life is very simple.
bzr init
bzr add
bzr commit -m "My project is now in Bazaar! Woot, woot!"
... edit your project ...
bzr add
bzr commit -m "I just made edits to my project, and Bazaar has been updated accordingly."
It's really sweet. Suppose you ship a new version, and you want to be able to access the exact source code that was used in that version :
bzr tag "Released version 1.2.3"
And to review previous tags? Simple :
bzr tags
If you mucked up?
bzr revert
(Throws away your changes since the last commit.)
That's all very sweet and simple. (Sure beats SVN and Visual SourceSafe!!!!!!!!!!!!!!!)
But I wanted to use feature branches.
There are various ways to do it, but here's a simplified version of how I'm doing it, with great success :
Create a root development folder. For sake of demonstration, let's call it "src".
src> bzr init-repo --no-trees
src> md trunk
src> cd trunk
src\trunk> bzr init
At this point, you have a trunk, with nothing in it. Not much use, but press on...
src\trunk> cd..
src> md wt
Here, "wt" is an acronym I've chosen somewhat arbitrarily. It stands for "working tree". It's the only place I'm going to have a copy of the (often extensive) set of files in the project.
Get it?
Bazaar lets you have as many branches as you want, without clogging your hard disk! THAT is AWESOME!
Now any time you embark on a change, you can afford to do it in a branch. That keeps your work well organised, and means you don't end up stuck with half-finished changes in your trunk. Very nice!
Did I mention that Bazaar is the best source code versioning system in the world? :o)
Ah - but we're not done yet. It's still useless at this point. Press on...
src> cd wt
src\wt> bzr checkout ..\trunk --lightweight
Woot, woot! At this point, copy any existing files for the project into src\wt, then proceed.
src\wt> bzr add
src\wt> bzr commit -m "Initial commit, directly into trunk. After this point, we will work on branches, not on the trunk."
Extra wootness! Now we have a trunk, and a working tree, and we are ready to start branching.
src\wt> cd..
src> bzr branch trunk "Branch001 - completely revolutionise colour scheme"
src> bzr branch trunk "Branch002 - add new powerful print-preview system"
src> bzr branch trunk "Small changes"
Yep - you guessed it. If you think there's a reasonable chance you'll get stuck halfway through a set of changes, and not have them finished before you have to work on some other aspect of the source code, then that's a good candidate for a branch. But if it's a REALLY small change (e.g. update the copyright notice in a single file), no need to create a new branch just for that. You could conceivably make that change directly in the trunk (although I advise against it, for reasons that are beyond the scope of this article). My solution? I have a permanent branch called "Small changes", and that's where I make small changes! :o)
So now, let's start work!
src> cd wt
src\wt> bzr switch "..\Branch001 - completely revolutionise colour scheme"
src\wt> bzr revert
At this point, the working tree matches the contents of Branch001.
Start work on that colour scheme.
Oh no! The boss has walked in and said the new print-preview system has to take priority.
Gotta change to a different branch.
Easy done :
src\wt> bzr commit -m "These are my changes so far."
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Voila! Now the working tree matches Branch002. Code away merrily...
In comes the accounts lady. "The last digit on the bank account number should be seven, not three."
This change should be done immediately. No point waiting two weeks for the new uber-funky print-preview system, nor five months for the new colour scheme to finally be done.
src\wt> bzr commit -m "Well, working on Branch002 was fun and all, but necessity demands my (temporary) departure."
src\wt> bzr switch "..\Small changes"
src\wt> bzr revert
Now fix that account number. And then proceed...
src\wt> bzr commit -m "Maggie informed me that the account number was incorrect. Fixed now."
Now, chances are, we want that change to go into the trunk right now. Let's do that.
A clue : BAZAAR IS NOT INTUITIVE WHEN IT COMES TO COMBINING FEATURE BRANCHES INTO THE TRUNK.
Oh - don't flame me. The problem is that most documentation talks about the 'bzr push" and "bzr pull" options.
But these will destroy everything. You'll lose the farm, the house, the boat...
There is a very simple rule to keep in mind when working on feature branches on your own computer :
bzr merge!!!!!!!
Yes - Bazaar's merging features are second-to-none. They are truly impressive.
So despite the myriad examples out there telling you to "bzr push" your changes to the central server - ignore it! Those instructions apply in certain common situations, but do not apply for our current purposes.
So here's how we get the latest changes from a branch into the trunk :
src\wt> bzr merge ..\trunk
That's the first step. Remember - whilst we've been busily working away on a branch, there might have been other branches committed to trunk. So the trunk we once knew is not necessarily the current trunk. We need to ensure that what we're about to commit to the trunk is compatible with the current version of the trunk.
And the way we do that is to first merge the latest changes from the TRUNK back into the current branch.
Having done that, we run our unit tests. If everything compiles and runs fine, we're happy chaps. If not, fix it! :o)
When we're happy with the merge :
src\wt> bzr commit -m "Merged with trunk"
Cool. So now we know that our changes in this branch are compatible with the trunk. That means it's safe to merge this branch into the trunk.
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge "..\Small changes"
There shouldn't be any conflicts or other problems at this point, because we already merged the trunk into our branch, and any problems should have been encountered then not now.
src\wt> bzr commit -m "Merged with branch 'Small changes'"
Woot, woot!
Oh - there's the boss again. I'd forgotten about the print preview. Better get back onto it :
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Code away.
Oh no! I just discovered that the print preview cannot possibly work unless the account number is correct - but the account number was fixed in a different branch!
Not a problem.
src\wt> bzr merge "..\Small changes"
src\wt> bzr commit -m "Merged with branch 'Small changes'"
Ah - wonderful. Now the changes in the "Small changes" branch are also in Branch002.
What's better yet is that Bazaar is so smart that you can merge those two branches together as many times as you want, and Bazaar will keep a record of what has been previously merged and what hasn't been, so that you'll never have trouble with the one change being included multiple times!
THAT is POWERFUL.
In fact, suppose we made Branch003 for some purpose or other :
src\wt> cd..
src> bzr branch trunk Branch003
src> cd wt
src\wt> bzr switch ..\Branch003
src\wt> bzr revert
Suppose it adds some cool new features to our library of helper functions.
Suppose we finish with the branch :
src\wt> bzr merge ..\trunk
... compile and run unit tests ...
src\wt> bzr commit -m "Merged with trunk"
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge ..\Branch003
src\wt> bzr commit -m "Merged with Branch003"
At this point, Branch003, trunk, and "Small changes" ALL contain the account number change, and Branch003 and trunk both contain the new helper functions.
We don't need Branch003 any more, so we're going to switch away from it and delete it. (We could switch to any branch, but hey, for the time being, I'll switch to the trunk, 'coz I don't know where I'm going next.)
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> rd ..\Branch003 /s
... and type "y" and Enter to confirm that you want to mercilessly annihilate Branch003.
Now, in some other source code versioning systems, you have to manually track which changes have been merged where. (Not mentioning any names... <cough - SVN> )
But with Bazaar, things just work, and they work perfectly!
We return to the print preview branch :
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Oh - turns out we need those new helper functions.
If Branch003 still existed, we could get those new helper functions by merging it in to Branch002.
Or we can merge the trunk into Branch002.
But Bazaar is so cool, that it doesn't matter which one we do, or even if do both, or even if we do both multiple times! It just works!
src\wt> bzr merge ..\trunk
src\wt> bzr commit -m "Merged with trunk, to get those wonderful new helper functions."
So, merge is your friend.
See, because I grew up with Visual SourceSafe and SVN, "merge" had a negative connotation. I assumed that the change history, including the detailed comments I leave with every commit, would be marred by merging.
But with Bazaar, the history is preserved!
It's easy to prove :
src\wt> cd ..\trunk
src\trunk> bzr log
And now you get a nice big listing of all the changes that have happened. It doesn't matter how many times you merged, all changes and all commit messages are preserved.
THAT'S what I call a good source code versioning system (aka "revision control system").
So many branches and can't remember which one the working tree is currently bound to?
src\trunk> cd ..\wt
src\wt> bzr info
Ah! It tells us which branch we're bound to. Very nice.
Now, my setup is actually considerably more elaborate than this. I have multiple development machines that I switch between - one laptop for the road, and a much more powerful desktop that I prefer using when I can.
I wanted a "central trunk" from which I could run automated unit tests, and which could be my controlled release point. Plus, I have other developers help out here and there. So I really wanted a system that works this simply and this well, but works across multiple computers.
And I needed each computer to have its own "local trunk" so that the respective developers could branch away happily even when they were not connected to the internet and the central trunk.
So, in effect (although I accomplished it slightly differently), I have a folder called "central-trunk", on my controlled-release computer.
I have found that the Bazaar logs look nicest when you only have one level of indirection with merges. Since I like nice, readable logs, this is what I do :
I merge finished branches into the CENTRAL trunk, and I never delete a branch until I have merged it with that CENTRAL trunk (unless I'm abandoning the branch).
The LOCAL trunk exists ONLY TO ENSURE I CAN CREATE NEW LOCAL BRANCHES EASILY.
And to keep the local trunk in-sync with the central trunk, I run the following when connected :
src\trunk> bzr pull Z:\central-trunk
I NEVER merge or commit into my LOCAL trunk. If I'm working on two branches that need features from each other, I merge them into each other.
So basically there are three levels - the central trunk, the local trunk, and each feature branch.
The changes are "bzr pull"ed from the central trunk into the local trunk.
"bzr branch" from the local trunk creates local feature branches.
"bzr merge", NOT "bzr push", takes my local feature branch into the central trunk.
And "bzr merge" also handles inter-branch updates along the way.
-
Bazaar changed my programming life. It is a source code versioning system that works, and works brilliantly well, and isn't cumbersome. It is a pleasure to use. I enjoy the feeling of committing a change, and I enjoy merging a feature branch into the trunk. It feels like hammering another peg into the cliff face, as I climb the metaphorical cliff of whichever crazy software development endeavour I've embarked on. (And I usually embark on difficult ones! :o) )
It changed my life, even long before I started using feature branches. For a long time, I just used (and loved) the ability to track each version of the trunk, and tag releases.
Now with feature branches, things are even better again.
If I'd been given this information when I first found Bazaar, I would have accomplished more. Feature branches are a produtivity tool.
But the documentation was more focussed on contributing to open-source projects where you always branch directly off the head revision from a read-only URL somewhere, and where only specially-privileged people can commit to trunk. That's fine - that's a very powerful and very common use of Bazaar.
But it can do so much more! I hope in this article that I've helped some of you get up-to-speed with Bazaar in ways that will transform your programming life for the better.
Well, that's my opinion, after using SVN and Visual SourceSafe, and reading fairly extensively about other systems.
But it can be hard to get started, just because it is SO powerful and has SO many options and can be used in SO many different ways.
If you're a single developer who just uses it to track their own work, and never makes feature branches, life is very simple.
bzr init
bzr add
bzr commit -m "My project is now in Bazaar! Woot, woot!"
... edit your project ...
bzr add
bzr commit -m "I just made edits to my project, and Bazaar has been updated accordingly."
It's really sweet. Suppose you ship a new version, and you want to be able to access the exact source code that was used in that version :
bzr tag "Released version 1.2.3"
And to review previous tags? Simple :
bzr tags
If you mucked up?
bzr revert
(Throws away your changes since the last commit.)
That's all very sweet and simple. (Sure beats SVN and Visual SourceSafe!!!!!!!!!!!!!!!)
But I wanted to use feature branches.
There are various ways to do it, but here's a simplified version of how I'm doing it, with great success :
Create a root development folder. For sake of demonstration, let's call it "src".
src> bzr init-repo --no-trees
src> md trunk
src> cd trunk
src\trunk> bzr init
At this point, you have a trunk, with nothing in it. Not much use, but press on...
src\trunk> cd..
src> md wt
Here, "wt" is an acronym I've chosen somewhat arbitrarily. It stands for "working tree". It's the only place I'm going to have a copy of the (often extensive) set of files in the project.
Get it?
Bazaar lets you have as many branches as you want, without clogging your hard disk! THAT is AWESOME!
Now any time you embark on a change, you can afford to do it in a branch. That keeps your work well organised, and means you don't end up stuck with half-finished changes in your trunk. Very nice!
Did I mention that Bazaar is the best source code versioning system in the world? :o)
Ah - but we're not done yet. It's still useless at this point. Press on...
src> cd wt
src\wt> bzr checkout ..\trunk --lightweight
Woot, woot! At this point, copy any existing files for the project into src\wt, then proceed.
src\wt> bzr add
src\wt> bzr commit -m "Initial commit, directly into trunk. After this point, we will work on branches, not on the trunk."
Extra wootness! Now we have a trunk, and a working tree, and we are ready to start branching.
src\wt> cd..
src> bzr branch trunk "Branch001 - completely revolutionise colour scheme"
src> bzr branch trunk "Branch002 - add new powerful print-preview system"
src> bzr branch trunk "Small changes"
Yep - you guessed it. If you think there's a reasonable chance you'll get stuck halfway through a set of changes, and not have them finished before you have to work on some other aspect of the source code, then that's a good candidate for a branch. But if it's a REALLY small change (e.g. update the copyright notice in a single file), no need to create a new branch just for that. You could conceivably make that change directly in the trunk (although I advise against it, for reasons that are beyond the scope of this article). My solution? I have a permanent branch called "Small changes", and that's where I make small changes! :o)
So now, let's start work!
src> cd wt
src\wt> bzr switch "..\Branch001 - completely revolutionise colour scheme"
src\wt> bzr revert
At this point, the working tree matches the contents of Branch001.
Start work on that colour scheme.
Oh no! The boss has walked in and said the new print-preview system has to take priority.
Gotta change to a different branch.
Easy done :
src\wt> bzr commit -m "These are my changes so far."
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Voila! Now the working tree matches Branch002. Code away merrily...
In comes the accounts lady. "The last digit on the bank account number should be seven, not three."
This change should be done immediately. No point waiting two weeks for the new uber-funky print-preview system, nor five months for the new colour scheme to finally be done.
src\wt> bzr commit -m "Well, working on Branch002 was fun and all, but necessity demands my (temporary) departure."
src\wt> bzr switch "..\Small changes"
src\wt> bzr revert
Now fix that account number. And then proceed...
src\wt> bzr commit -m "Maggie informed me that the account number was incorrect. Fixed now."
Now, chances are, we want that change to go into the trunk right now. Let's do that.
A clue : BAZAAR IS NOT INTUITIVE WHEN IT COMES TO COMBINING FEATURE BRANCHES INTO THE TRUNK.
Oh - don't flame me. The problem is that most documentation talks about the 'bzr push" and "bzr pull" options.
But these will destroy everything. You'll lose the farm, the house, the boat...
There is a very simple rule to keep in mind when working on feature branches on your own computer :
bzr merge!!!!!!!
Yes - Bazaar's merging features are second-to-none. They are truly impressive.
So despite the myriad examples out there telling you to "bzr push" your changes to the central server - ignore it! Those instructions apply in certain common situations, but do not apply for our current purposes.
So here's how we get the latest changes from a branch into the trunk :
src\wt> bzr merge ..\trunk
That's the first step. Remember - whilst we've been busily working away on a branch, there might have been other branches committed to trunk. So the trunk we once knew is not necessarily the current trunk. We need to ensure that what we're about to commit to the trunk is compatible with the current version of the trunk.
And the way we do that is to first merge the latest changes from the TRUNK back into the current branch.
Having done that, we run our unit tests. If everything compiles and runs fine, we're happy chaps. If not, fix it! :o)
When we're happy with the merge :
src\wt> bzr commit -m "Merged with trunk"
Cool. So now we know that our changes in this branch are compatible with the trunk. That means it's safe to merge this branch into the trunk.
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge "..\Small changes"
There shouldn't be any conflicts or other problems at this point, because we already merged the trunk into our branch, and any problems should have been encountered then not now.
src\wt> bzr commit -m "Merged with branch 'Small changes'"
Woot, woot!
Oh - there's the boss again. I'd forgotten about the print preview. Better get back onto it :
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Code away.
Oh no! I just discovered that the print preview cannot possibly work unless the account number is correct - but the account number was fixed in a different branch!
Not a problem.
src\wt> bzr merge "..\Small changes"
src\wt> bzr commit -m "Merged with branch 'Small changes'"
Ah - wonderful. Now the changes in the "Small changes" branch are also in Branch002.
What's better yet is that Bazaar is so smart that you can merge those two branches together as many times as you want, and Bazaar will keep a record of what has been previously merged and what hasn't been, so that you'll never have trouble with the one change being included multiple times!
THAT is POWERFUL.
In fact, suppose we made Branch003 for some purpose or other :
src\wt> cd..
src> bzr branch trunk Branch003
src> cd wt
src\wt> bzr switch ..\Branch003
src\wt> bzr revert
Suppose it adds some cool new features to our library of helper functions.
Suppose we finish with the branch :
src\wt> bzr merge ..\trunk
... compile and run unit tests ...
src\wt> bzr commit -m "Merged with trunk"
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge ..\Branch003
src\wt> bzr commit -m "Merged with Branch003"
At this point, Branch003, trunk, and "Small changes" ALL contain the account number change, and Branch003 and trunk both contain the new helper functions.
We don't need Branch003 any more, so we're going to switch away from it and delete it. (We could switch to any branch, but hey, for the time being, I'll switch to the trunk, 'coz I don't know where I'm going next.)
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> rd ..\Branch003 /s
... and type "y" and Enter to confirm that you want to mercilessly annihilate Branch003.
Now, in some other source code versioning systems, you have to manually track which changes have been merged where. (Not mentioning any names... <cough - SVN> )
But with Bazaar, things just work, and they work perfectly!
We return to the print preview branch :
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert
Oh - turns out we need those new helper functions.
If Branch003 still existed, we could get those new helper functions by merging it in to Branch002.
Or we can merge the trunk into Branch002.
But Bazaar is so cool, that it doesn't matter which one we do, or even if do both, or even if we do both multiple times! It just works!
src\wt> bzr merge ..\trunk
src\wt> bzr commit -m "Merged with trunk, to get those wonderful new helper functions."
So, merge is your friend.
See, because I grew up with Visual SourceSafe and SVN, "merge" had a negative connotation. I assumed that the change history, including the detailed comments I leave with every commit, would be marred by merging.
But with Bazaar, the history is preserved!
It's easy to prove :
src\wt> cd ..\trunk
src\trunk> bzr log
And now you get a nice big listing of all the changes that have happened. It doesn't matter how many times you merged, all changes and all commit messages are preserved.
THAT'S what I call a good source code versioning system (aka "revision control system").
So many branches and can't remember which one the working tree is currently bound to?
src\trunk> cd ..\wt
src\wt> bzr info
Ah! It tells us which branch we're bound to. Very nice.
Now, my setup is actually considerably more elaborate than this. I have multiple development machines that I switch between - one laptop for the road, and a much more powerful desktop that I prefer using when I can.
I wanted a "central trunk" from which I could run automated unit tests, and which could be my controlled release point. Plus, I have other developers help out here and there. So I really wanted a system that works this simply and this well, but works across multiple computers.
And I needed each computer to have its own "local trunk" so that the respective developers could branch away happily even when they were not connected to the internet and the central trunk.
So, in effect (although I accomplished it slightly differently), I have a folder called "central-trunk", on my controlled-release computer.
I have found that the Bazaar logs look nicest when you only have one level of indirection with merges. Since I like nice, readable logs, this is what I do :
I merge finished branches into the CENTRAL trunk, and I never delete a branch until I have merged it with that CENTRAL trunk (unless I'm abandoning the branch).
The LOCAL trunk exists ONLY TO ENSURE I CAN CREATE NEW LOCAL BRANCHES EASILY.
And to keep the local trunk in-sync with the central trunk, I run the following when connected :
src\trunk> bzr pull Z:\central-trunk
I NEVER merge or commit into my LOCAL trunk. If I'm working on two branches that need features from each other, I merge them into each other.
So basically there are three levels - the central trunk, the local trunk, and each feature branch.
The changes are "bzr pull"ed from the central trunk into the local trunk.
"bzr branch" from the local trunk creates local feature branches.
"bzr merge", NOT "bzr push", takes my local feature branch into the central trunk.
And "bzr merge" also handles inter-branch updates along the way.
-
Bazaar changed my programming life. It is a source code versioning system that works, and works brilliantly well, and isn't cumbersome. It is a pleasure to use. I enjoy the feeling of committing a change, and I enjoy merging a feature branch into the trunk. It feels like hammering another peg into the cliff face, as I climb the metaphorical cliff of whichever crazy software development endeavour I've embarked on. (And I usually embark on difficult ones! :o) )
It changed my life, even long before I started using feature branches. For a long time, I just used (and loved) the ability to track each version of the trunk, and tag releases.
Now with feature branches, things are even better again.
If I'd been given this information when I first found Bazaar, I would have accomplished more. Feature branches are a produtivity tool.
But the documentation was more focussed on contributing to open-source projects where you always branch directly off the head revision from a read-only URL somewhere, and where only specially-privileged people can commit to trunk. That's fine - that's a very powerful and very common use of Bazaar.
But it can do so much more! I hope in this article that I've helped some of you get up-to-speed with Bazaar in ways that will transform your programming life for the better.
Subscribe to:
Posts (Atom)