summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2012-09-05 19:46:44 +0100
committerJannis Pohlmann <jannis.pohlmann@codethink.co.uk>2012-09-10 10:59:39 +0000
commit586aacfe5b6c5f9b0d18ffa3fd9fe00f6692fe83 (patch)
tree45a1d26bbc4f330ec0d25ba1de198d1a4600d88d
parentfb2e08f81d96741c05597208fdab196ec0c1b584 (diff)
downloadmorph-586aacfe5b6c5f9b0d18ffa3fd9fe00f6692fe83.tar.gz
Rewrite 'merge' command
'merge' now traverses every system in the branch root (baserock:morphs) and merges any chunk or stratum that was changed with 'morph edit'. It also takes care of updating the refs in the target branch.
-rw-r--r--morphlib/git.py1
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py100
-rw-r--r--tests.branching/merge-explicitly-named-repos.stdout1
-rwxr-xr-xtests.branching/merge.script (renamed from tests.branching/merge-explicitly-named-repos.script)27
-rwxr-xr-xtests.branching/workflow.script7
5 files changed, 103 insertions, 33 deletions
diff --git a/morphlib/git.py b/morphlib/git.py
index 70915770..0a4b01f4 100644
--- a/morphlib/git.py
+++ b/morphlib/git.py
@@ -150,7 +150,6 @@ def checkout_ref(runcmd, gitdir, ref):
'''Checks out a specific ref/SHA1 in a git working tree.'''
runcmd(['git', 'checkout', ref], cwd=gitdir)
-
def reset_workdir(runcmd, gitdir):
'''Removes any differences between the current commit '''
'''and the status of the working directory'''
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index d44ccacc..c2401631 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -49,7 +49,7 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.add_subcommand('show-branch-root', self.show_branch_root,
arg_synopsis='')
self.app.add_subcommand('merge', self.merge,
- arg_synopsis='BRANCH REPO...')
+ arg_synopsis='BRANCH')
self.app.add_subcommand('edit', self.edit,
arg_synopsis='SYSTEM STRATUM [CHUNK]')
self.app.add_subcommand('build', self.build,
@@ -536,24 +536,92 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.print_changelog('The following changes were made but have not '
'been comitted')
+ def merge_repo(self, name, from_dir, from_branch, to_dir, to_branch,
+ is_morphs_repo = False):
+ '''Merge changes for a system branch in a specific repository'''
+
+ if self.get_uncommitted_changes(from_dir) != []:
+ raise cliapp.AppException('repository %s has uncommitted '
+ 'changes', name)
+ # repo must be made into a URL to avoid ':' in pathnames confusing git
+ from_url = urlparse.urljoin('file://', from_dir)
+ if is_morphs_repo:
+ # We use --no-commit in this case, so we can then revert the refs
+ # that were changed for the system branch in the merge commit
+ self.app.runcmd(['git', 'pull', '--no-commit', '--no-ff', from_url,
+ from_branch], cwd=to_dir)
+ else:
+ self.app.runcmd(['git', 'pull', '--no-ff', from_url, from_branch],
+ cwd=to_dir)
+
def merge(self, args):
- '''Merge specified repositories from another system branch.'''
+ '''Pull and merge changes from a system branch into the current one.'''
- if len(args) < 2:
- raise cliapp.AppException('morph merge must get a branch name '
- 'and some repo names as arguments')
+ if len(args) != 1:
+ raise cliapp.AppException('morph merge requires a system branch '
+ 'name as its argument')
workspace = self.deduce_workspace()
- other_branch, other_branch_dir = \
- args[0], self.find_system_branch(workspace, args[0])
- this_branch, this_branch_dir = self.deduce_system_branch()
-
- for repo in args[1:]:
- pull_dir = self.find_repository(other_branch_dir, repo)
- pull_url = urlparse.urljoin('file://', pull_dir)
- repo_dir = self.find_repository(this_branch_dir, repo)
- self.app.runcmd(['git', 'pull', pull_url, other_branch],
- cwd=repo_dir)
+ from_branch = args[0]
+ from_branch_dir = self.find_system_branch(workspace, from_branch)
+ to_branch, to_branch_dir = self.deduce_system_branch()
+
+ root_repo = self.get_branch_config(from_branch_dir, 'branch.root')
+ other_root_repo = self.get_branch_config(to_branch_dir, 'branch.root')
+ if root_repo != other_root_repo:
+ raise cliapp.AppException('branches do not share a root '
+ 'repository : %s vs %s' %
+ (root_repo, other_root_repo))
+
+ def _merge_chunk(ci):
+ from_repo = self.find_repository(from_branch_dir, ci['repo'])
+ to_repo = self.make_repository_available(
+ to_branch, to_branch_dir, ci['repo'], to_branch)
+ self.merge_repo(
+ ci['repo'], from_repo, from_branch, to_repo, to_branch)
+
+ def _merge_stratum(si):
+ if si['repo'] == root_repo:
+ to_repo = to_root_dir
+ else:
+ from_repo = self.find_repository(from_branch_dir, si['repo'])
+ to_repo = self.make_repository_available(
+ to_branch, to_branch_dir, si['repo'], to_branch)
+ self.merge_repo(
+ si['repo'], from_repo, from_branch, to_repo, to_branch,
+ is_morphs_repo=True)
+ # We will do a merge commit in this repo later on
+ morphs_repo_list.add(to_repo)
+
+ stratum = self.load_morphology(to_repo, si['morph'])
+ for ci in stratum['chunks']:
+ if ci['ref'] == from_branch:
+ _merge_chunk(ci)
+ ci['ref'] = to_branch
+ self.save_morphology(to_repo, si['morph'], stratum)
+
+ from_root_dir = self.find_repository(from_branch_dir, root_repo)
+ to_root_dir = self.find_repository(to_branch_dir, root_repo)
+ self.app.runcmd(['git', 'checkout', to_branch], cwd=to_root_dir)
+ self.merge_repo(root_repo, from_root_dir, from_branch, to_root_dir,
+ to_branch, is_morphs_repo = True)
+ morphs_repo_list = set([to_root_dir])
+
+ for f in glob.glob(os.path.join(to_root_dir, '*.morph')):
+ name = f[:-len('.morph')]
+ morphology = self.load_morphology(to_root_dir, name)
+
+ if morphology['kind'] == 'system':
+ for si in morphology['strata']:
+ if si['ref'] == from_branch:
+ _merge_stratum(si)
+ si['ref'] = to_branch
+ self.save_morphology(to_root_dir, name, morphology)
+
+ for repo in morphs_repo_list:
+ msg = "Merge system branch '%s'" % from_branch
+ self.app.runcmd(['git', 'commit', '--all', '--message="%s"' % msg],
+ cwd=repo)
def build(self, args):
if len(args) != 1:
@@ -674,7 +742,7 @@ class BranchAndMergePlugin(cliapp.Plugin):
except:
return None
- def get_uncommitted_changes(self, repo_dir, env):
+ def get_uncommitted_changes(self, repo_dir, env={}):
status = self.app.runcmd(['git', 'status', '--porcelain'],
cwd=repo_dir, env=env)
changes = []
diff --git a/tests.branching/merge-explicitly-named-repos.stdout b/tests.branching/merge-explicitly-named-repos.stdout
deleted file mode 100644
index cd2122c4..00000000
--- a/tests.branching/merge-explicitly-named-repos.stdout
+++ /dev/null
@@ -1 +0,0 @@
-newfile.txt
diff --git a/tests.branching/merge-explicitly-named-repos.script b/tests.branching/merge.script
index 7dfd5780..7c433519 100755
--- a/tests.branching/merge-explicitly-named-repos.script
+++ b/tests.branching/merge.script
@@ -14,34 +14,37 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-# Check that "morph merge" merges explicitly named repositories.
-
+# Check that "morph merge" merges a system branch into master
set -eu
-
# Create system branch.
cd "$DATADIR/workspace"
"$SRCDIR/scripts/test-morph" init
-"$SRCDIR/scripts/test-morph" branch baserock:morphs newbranch
+"$SRCDIR/scripts/test-morph" branch baserock:morphs baserock/newbranch
# Make a change to a chunk.
"$SRCDIR/scripts/test-morph" edit hello-system hello-stratum hello
-cd newbranch/baserock:hello
+cd baserock/newbranch/baserock:hello
touch newfile.txt
git add newfile.txt
git commit -m foo --quiet
-# Merge changes to a new system branch.
+# Commit in morphs repo
+cd ../baserock:morphs
+git commit --all --quiet -m "Update morph refs for baserock/newbranch"
+
+# Merge changes back to master
cd "$DATADIR/workspace"
-"$SRCDIR/scripts/test-morph" branch baserock:morphs otherbranch
-cd otherbranch
-"$SRCDIR/scripts/test-morph" edit hello-system hello-stratum hello
-"$SRCDIR/scripts/test-morph" merge newbranch baserock:hello
+"$SRCDIR/scripts/test-morph" checkout baserock:morphs master
+cd master
+"$SRCDIR/scripts/test-morph" merge baserock/newbranch
# Check results.
cd baserock:hello
git status --short # make sure all changes are committed
-ls newfile.txt # make sure the new file is there
+[ -e newfile.txt ] # make sure the new file is there
+# Make sure all refs to the merged branch have gone.
+cd ../baserock:morphs
+! grep "\"ref\": \"baserock/newbranch\"" *.morph
diff --git a/tests.branching/workflow.script b/tests.branching/workflow.script
index cb79c3c5..68da4f4a 100755
--- a/tests.branching/workflow.script
+++ b/tests.branching/workflow.script
@@ -30,9 +30,10 @@ echo > README yoyoyo
git add README
git commit -m "Fix README, yo!" --quiet
+cd ../baserock:morphs
+git commit --quiet --all -m "Commit changes for system branch"
+
cd "$DATADIR/workspace"
"$SRCDIR/scripts/test-morph" checkout baserock:morphs master
cd master
-"$SRCDIR/scripts/test-morph" edit hello-system hello-stratum hello
-"$SRCDIR/scripts/test-morph" merge me/readme-fix baserock:hello
-
+"$SRCDIR/scripts/test-morph" merge me/readme-fix