Skip to content. | Skip to navigation

Personal tools

Navigation

You are here: Home / Wiki / Mergebuild

Mergebuild

Merge Build System

Merge Build System

The merge build system allows you to have multiple topic branches installed on your devel tree or inner emulab. It is primary designed to allow keeping unfinished topic branches installed while working on something else.

Overview

Normally you have two trees, your source tree, and an object tree. The merge build system, introduces a third tree: the merge tree, which is a git repository which acts as a staging area where multiple branches can be brought together. Before building each branch is merged in and any uncommitted changed are applied. Emulab is then built based on the code in the merge tree. Special make rules are added so that, in most cases, this happens automatically.

Setup

In your local git repository, add the file .merge-build with the following three lines:

source-tree ../testbed
merge-tree ../testbed-merge
branches ...

The first line is the location of the source-tree relative to the merge tree, which the second is the reverse. The last line is the branches to merge together, separated by spaces.

Then run the commands:

utils/merge-build prep
utils/merge-build sync

which should set up a new git repository with all the specified branches merged as well as any uncommitted changes applied.

Finally, set up object dir. I strongly suggest you remove/rename, the old one and start with a fresh dir. Just run configure as normal but use the configure and defs file in the merge-tree instead. Ie:

   ../testbed-merge/configure --with-TBDEFS=../testbed-merge/defs-XXX ...

The configure script will automatically recognize that you are building form a merge tree and add some special rules to the Makefile and create a local sync script.

Day to day operations

Once the merge tree is set up you shouldn't need to do anything special. When it comes time to build, just do so as your normal would, make will automatically sync the merge tree when it detects any files in your source tree are newer than the ones in the merge tree.

You can manually sync the two trees by running ./sync in your object tree or calling "utils/merge-build sync".

To remove or add a new branch simply adjust .merge-build and resync. If you remove a branch that you abandoned HEAD in your merge tree will be automatically reset to a point where the abandoned changes where not merged in order to avoid unnecessary conflicts. Rebasing any of your branches will also cause an automatic reset.

Recovering Uncommitted Changes

Every time a sync is done a new temporary commit is created (similarly to git stash). A note of this commit is stored in the reflog under the build-stash reference. You can use "git reflog show build-stash" or "git log -g build-stash" to list them. You can use this to recover to a past version by using something like:

git stash
git reset --hard <commit-id>
git reset --soft HEAD^

and than after making sure that you reset to the correct version:

git stash drop

Handling Conflicts

In general your topic branches should be independent enough that they should merge cleanly. Although it is possible to resolve the conflict in the merge tree, this should be considered as a last resort and should be limited for trivial conflicts.

If the conflict happened while merging one of the branches in, simply fix the conflict and commit. Then run sync again. Git-rerere is enabled on the merge-build repository (see man git-rerere) so that even if a reset is done (automatically or manually) you should not have to resolve the conflict again.

If the conflict happened while applying the uncommitted changed, fix the conflict and then run "git rerere" which will record the resolution so the next time the changes are applied you should not need to do it again.

Normally, when git-rerere resolves a conflict, user intervention is still required since it could get it wrong. However, having to constantly review git-rerere resolution before proceeding can get annoying, especially if the conflict is due to an uncommitted change. For this reason the merge-build script will recognize when git-rerere resolves the conflict and proceed without user intervention. There is still the danger of git-rerere getting it wrong, thus, as already mentioned, conflict resolution should be limited to trivial cases to minimize this possibility.

Using the Merge Tree to push changes upstream

As written the merge-build system is designed to allow keeping unfinished topic branches installed. You should not push (or pull) the "merge" branch anywhere as it contains a lot of unnecessary garbage in the history. This includes a dummy commit to make automatic reseting easier and lots of unnecessary merge commits.

Automatic and manual resetting

As already indicated HEAD in the merge tree will be automatically reset as required. You can disable this feature by adding the line

auto-reset no

to your .merge-build file.

You can start over completely by doing a

utils/merge-build reset

which will reset your tree as if you removed the merge tree and used prep to create a new one, except that, among other things, a record of the previous state HEAD was is still in the reflog so you can undo the change if necessary.