Mercurial: Branching for releases? - version-control

Previous history: The last couple of years I used SVN. Releasing a new version of a software project included following steps:
creating a branch for the new release: /repo/branches/0.1
getting the code into a release-worthy state there
creating a tag for a release candidate: /repo/tags/0.1-RC1
creating branch for RC1 to fix bugs: /repo/branches/0.1-RC1
creating tag for a new release candidate: /repo/tags/0.1-RC2
{...}
creating a tag for v0.1 from the last RC: /repo/tags/0.1
merging 0.1 into trunk
As far as I got Mercurial sees branches and tags slightly different than SVN and this finally leads to my question:
Do I create branches (and tags) for releases? And if not: What else wants Mercurial me doing to archive something similar to the described development pattern/cycle?

You can easily keep using this method. I'm not sure what you'd need a separate RC1 branch for, but I guess there are good reasons.
There is a bit of an annoyance in the way tags are stored in Mercurial, which is a versioned file listing them one by one. As a result tag creation constitutes a changeset. You should strive to keep all such tag-creating changesets on one branch, or you will get merge conflicts (which are easily resolved, but annoying nonetheless).

You can use old workflow, but:
Branch per release really needed (in any SCM) only if you have to maintain some amount (>1) of releases in production at the same time, gor single maintained release branches-tree not needed
I see a lot of (rather complex) projects, which use two-branches method ("Stable" with mergesets only and tags + "Devel" for every-day development (short-term branch-per-task are also possible, but it's more question of tastes and habits, than "a must")

Related

Mercurial: cross-version merges / massive cherry-picking

Situation
We have 2 versions (1.0 and 2.0) of a project that are both actively maintained. It is basically the same project (as far as changes go), but being based on different base versions (base1.0 and base2.0). Everything that is changed in 1.0 has also to be ported to 2.0. The same goes for base1.0 and base2.0.
In mercurial we have 4 branches: base1.0, 1.0, base2.0 and 2.0. Something like this:
__2.0
__base2.0__/
/
__base1.0__/___1.0____________
Now everytime we change something in the base version, we make the change in base1.0 and do a hg merge to base2.0. No problems here.
Now when we do the same for 1.0 and want to merge them into 2.0, we also have to re-merge the entire base1.0 branch into 2.0, although that has already been done creating base2.0 out of base1.0.
Question
What is the most efficient way to solve this? I had a few approaches:
Merge: as explained above, this causes a lot of overhead and work to be re-done that has already been done
graft aka cherry-pick: Select every single change we make on 1.0 and port them to 2.0 using hg graft. While it does work in some cases, it creates duplicate changesets because it ports them 1:1. What I'd like would be 1 single commit containing all updates made on 1.0 grafted to 2.0.
diff export: I also tried to make a export a diff between the original 1.0 and the most recent 1.0 and then import it onto 2.0. But it's a patch, and patches are evil. And not very handy to handle.
Any ideas? Being relatively new to the whole SCM concept I just wanted to hear what others do in such scenarios. Thanks.
I actually resolved my problem. I'll add it as an answer, maybe someone else finds it useful.
What I really needed was cherry-picking all my changes from 1.0 to 2.0. hg graft does that pretty well, but creates an additional commit on 2.0 for each changeset grafted and messes up my graph.
So what I did was creating a clone of my repo and then grafting all the changesets using hg graft from 1.0 onto 2.0. Then I exported a diff of pre-graft and post-graft and imported that diff as a patch onto the original repo.
Essentially a cumulative "graft" without any information about where it came from. This was exactly what I needed and worked for me in this case.

Why is the "source" version given so much importance in Perforce while merging (resolving conflicts to be verbose)?

I don't think I even want to see it. Why do others find it so important ?
Isn't Base, Target enough for the "resolving conflicts" aka Merge tool window. What am I missing ? Are people really that bothered about the version before Base i.e. Source ?
It seems you have a fundamental misunderstanding about what each of the versions are. When you merge two branches, almost always you want to keep changes from both branches. Base is the latest common ancestor of the two branches. Base->Source shows what was changed in the branch you're merging from, and Base->Target shows what was changed in the branch you're merging to. To properly resolve a conflict, you need to know what was changed in each branch.
(Some documentation for p4merge at p4 docs - Merging Files)
When working with a merge conflict, there are four parts to it:
The common ancestor that both branches changed
Their changes (source)
Your changes (target)
The final result
(You may have an old version of p4merge - the docs show a different wording that may clear up the confusion)
The 'source' is not the revision before, but rather the incoming changes from the merge that someone else made.
Ignoring either your changes or their changes is a possible conflict resolution - many have that as a default "merge, handle conflicts by use mine." However, this has the distinct possibility of causing regressions of functionality introduced by the other branch (or worse, removing code the other branch is expecting).
For a given code block with a conflict, both your changes and their changes are important, and the ancestor of the two gives the appropriate context for what the change was.

Find all unmerged files/elements in ClearCase

We use ClearCase where I work and I'm trying to figure out how to find any files that have been modified but not merged up. We have a main branch at the very top level in ClearCase, and this is where the final source code changes are merged to and where we do our formal release builds from. We then have an integration branch under main where integration issues are worked out. When we get everything working and tested in the integration branch, we merge the integration branch up to main. For individual feature implementations and bug fixes, we create a new branch (usually named after an action, feature, or bugfix) off of the integration branch and work the issue. When we are done with it, we merge that change up to the integration branch.
I was wondering if anybody knew of a command or a way to see what files are modified in the feature/bug fix branches but were not merged back up to the integration branch. I've been looking around but I can't seem to find a way to do it. I would like to be able to run the command and have it tell me all files that have been modified on all of the sub-branches but not merged up. Thanks.
Normally, you use ct findmerge to find files to merge from one branch or view into the current view (assuming ct is an alias for cleartool).
I think you would have to identify all the branches you are interested in and do a separate ct findmerge operation for each branch - for each destination branch. That's complex. You'd also want to be able to eliminate many branches which are known to be fully merged. You can annotate a branch to indicate that it is fully merged.
So, I don't think there is a simple, single command to do this job.
You need to decide which branches are targets that you're concerned about. These would be your integration branch(es). Presumably, you have a fairly small list of these.
For each of those target branches, you need to decide which work branches are relevant to that integration branch. This is the tricky part; there is no easy way to determine whether a particular bug fix or feature branch is relevant to that integration branch using information in the VOBs; it is really only known by the users.
You then need a script that does (in outline):
for int_branch in $(list_relevant_integration_branches)
do
...create view with tag $tag for $int_branch...
ct setcs -f $(cspec_for_integration_branch $int_branch) $tag
ct setview -exec "find_outstanding_merges_for_integration_branch $int_branch" $tag
done
where find_outstanding_merges_for_integration_branch looks a bit like:
vob_list=$(list_relevant_vobs)
for mrg_branch in $(list_relevant_merge_branches $int_branch)
do
echo
echo "Merges from $mrg_branch to $int_branch"
ct findmerge $vob_list -fversion .../$mrg_branch/LATEST -print
done
Note that this command assumes (a) the current view is appropriate for the target, and (b) the integration branch name is passed as an argument.
You can get fancy and decide how to handle automatic or graphical merges instead of -print. The hard part is still the unwritten commands such as list_relevant_integration_branches and list_relevant_vobs. These might be simple:
# list_relevant_integration_branches
cat <<EOF
integration_branch_version_3_0
integration_branch_version_3_1
integration_branch_version_4_0
EOF
# list_relevant_vobs
cat <<EOF
/vobs/mainproject
/vobs/altproject
/vobs/universal
EOF
Or they might be considerably more complex. (If you only have one VOB, then your life is much simpler; the systems we work with have 20-odd VOBs visible in the cspec.)
The other unwritten script is list_relevant_merge_branches. I don't know whether there's a simple way to write that. If you define and apply appropriate attribute types (ct mkattype, ct mkattr) when the development branches are created (perhaps a 'target integration branch' attribute type, an enumeration type), you could use that to guide you. That leaves you with a retrofit problem; how to get the correct attribute onto each existing working branch. You also need a separate attribute to identify branches that no longer need merge scrutiny, unless you decide that the absence of a 'target integration branch' attribute means 'no need to scrutinize any more'. That reduces the retrofit problem to adding the target integration branch to those branches that still need merging; by default, all existing branches will be deemed fully merged.
If you know the source and destination branches (topic detailed in Jonathan's answer, which I have upvoted), then don't forget the query primitive merge:
merge (from-location , to-location)
In all cases, TRUE if the element to which the object belongs has a merge hyperlink (default name: Merge) connecting the from-location and to-location.
You can specify either or both locations with a branch pathname or a version selector.
Specifying a branch produces TRUE if the merge hyperlink involves any version on that branch.
The branch pathname must be complete (for example, /main/rel2_bugfix, not rel2_bugfix).
This thread illustrates that query in action:
How is it possible to find all the elements on a specific branch that are checked in and not merged away?
cleartool find \\view\administration\ProjectVOB \
-branch "brtype(HNH-372452) && \
!merge(...\HNH-372452\LATEST,...\main-372452\LATEST)" -print
\\view\administration\ProjectVOB\Com-API\Dll\COMFrontendDll\Mmi.cpp##\main\HNH-372452
\\view\administration\ProjectVOB\geometry\geochain\geocutterloc.cpp##\main\HNH-372452
That "merge hyperlink" is the red arrow you see in version tree:
(see article "Versioning and parallel development of requirements")

Ensuring a merge between branches happens in one direction

This morning I discovered that my co-worker had merged the wrong way between two branches in mercurial --we have a ver5 and ver6 branch, with extra files in ver6. Is there any way (a serverside hook probably) to enforce that the children of any ver5 node be from ver5?
Whether you have ver5 merged into ver6 or ver6 merged into ver5 you're still ending up with a child of ver5 that has stuff from ver6 in it.
If, however, you want to avoid a changeset whose branch name is ver5 having ancestors that are ver6 you could do that pretty easily with a hook. Just where you put that hook is the tricky part. If you make it a pretxnchangegroup hook you can prevent people from pushing an offending merge into the server-side repo, but they will have already committed it, and maybe some more changes on top of it, and they'll have a hard time figuring out what to do to fix it. If you can control their local setups you can put in a pretxncommit hook that prevents them from committing the merge, but you can't make them run that hook using only Mercurial tools.
The actual hook, whichever type you make it, could use either of these strategies:
check if the branchname is ver5 and if so make sure no specific file/content from ver6 is presnet
or
check if branchname is ver6 and if so make sure neither p1 nor p2 has branchname ver5
TL;DR: It's probably more trouble than it's worth -- stick to shaming.
Rather than post twice, would my answer to "Mercurial: allow merge from a release branch to the default one, but not vice versa" help? https://stackoverflow.com/a/19926324/1025457
This should do it. It uses a revset query to find any merges into ver5 from ver6.
hg log -r 'children(p2(::ver5 and ::ver6 and merge()) and branch(ver6)) and branch(ver5)'
::ver5 and ::ver6 and merge() finds all merges that are ancestors of both ver5 and ver6 branches
p2(...) and branch(ver6) grabs the second parent (incoming changeset) that are on the ver6 branch.
children(...) and branch(ver5) then grabs the actual merge changeset that is on the ver5 branch.
I recently needed to figure this out myself, but also needed to ensure that default wasn't indirectly merged into my release branch, i.e. default -> feature -> release.

Where does the version number come from?

I have a version control system (e.g. Subversion) and now I'd like to set up a build process. Now I have to create a version number and insert it into the system. But where does the version number come from and get into? Assume I want to use this common <major>.<minor>.<bugfix/revision> scheme. Should I pass a number to the build script? Or should I pass arguments like increaseMajor, increaseMinor, increaseRevision? Or would you recommend to create a branch with the number which will be detected by the build script?
I could imagine that the major and minor version number have to be put in manually somewhere. The revision number could be increased automaically. But still I don't know where I would place the major and minor number.
In my case I have some php files that I would like to zip, but before I have to insert some version numbers into php file.
I have edited this post to try to make my request clearer:
I do not use Subversion, that was just an example. And I don't want to discuss the version number scheme.
Imagine I want to create version 3.5.0 or 3.5.1. Would I pass this version number to a build script? Would the script create the branch in the repository with this number or would it expect that someone has already created this branch? Manually? Or would the build script look for name of the branch (e.g. '3.5.1) and use it for further things? And does the version number come from my brain or is it automatically created (I guess the major/minor number it comes from my little brain and revision number is created)? Or would you place the number into a file that may gets inserted into the repository?
I guess if would use a release management tool I would insert the version number there. But I don't use one yet.
For subversion, either take the global revision number and use that as "build" number or, even better, don't rely on it at all and manage versions with tags and/or branches. The main problem with the global revision is exactly that, it is global to the repo. It will increase even though some parts of the repo don't change.
Completely disassociate versions from the repo's revisions is IMHO better. You have tags, use them.
agreed with all previous on the use of branches and tags. Additionaly the branch names and tag names can be incorporated into a build process w/ some clever scripting.
The only tidbit I wish to add is that you should sneak your SVN revision into every build. Sometimes it's easily to get back to a certain point w/ the revision instead of knowing the tag or branch. 99% the tag/branch is good enough, but the revision is great for incremental/internal/continous/test builds.
All branches should be created manually. The build script should work off a tag and/or branch, starting with checking it out (or may be updating it). As part of teh build process, it's a good idea to create a tag on the exact snapshot that gets built.
You would normally have build number and a version. Build number can be incremented automatically and checked into version control as part of the build (except for tag-based build, where the build number has to stay outside of repository - another reason to avoid tag-based builds).
Version is usually stored in a file that you update manually once per release cycle. It's checked into th eright branch and then left alone. For example, the mainline would have version = "3" in its file, the first revision on release branch would have version = "3.5", and if a patch release becomes needed, you branch that off your release branch and check in version = "3.5.1"
The revision in svn or any other version control system is not the same thing as your product release number (or even your build number).
There are any number of ways that you can enforce the version number. Commonly in subversion you can create a branch (or tag, they are essentially the same thing) for a build and if this is a release version you create a tag for this eg svn://my-repo/releases/1.0.0
You could either pass a parameter into your build script to get the code and use that as the build number, or have a directory which your build script used, and svn switch this to the branch that you wanted to build, the script could use svn info to determine what version it was building.
x.y.i.j
Where x - Major version, y - Minor version, i - Build number, j - Revision number
Major version increments on major changes (new architecture, new UI, etc)
Minor version increments on minor changes (performance improvement, major bug fixing, etc),
Build number increments everytime you makes a public release.
Revision number increments everytime you commits changes to the project source tree.
I prefer to point 0 as revision number into AssemblyInfo.cs and point the real number in the name of release package (foo-1.1.7.110-source.zip)