summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-02-20 14:58:46 +0000
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-09-21 10:20:51 +0000
commit2172c4332e8ee26aba28824293faa552867c4d35 (patch)
treef139d17f1d4f7339e47cd2c47ee202573a230f53
parentf4d3cbaf1d6e5c3bdbb1b2e2c18822ecc25c1ac5 (diff)
downloadmorph-2172c4332e8ee26aba28824293faa552867c4d35.tar.gz
Revert "Remove petrify and unpetrify commands"
This reverts commit d63f41dadf5aa96a8d9254d31e92711ee160245e.
-rw-r--r--doc/branching-merging-systems.mdwn32
-rw-r--r--morphlib/morphset.py14
-rw-r--r--morphlib/morphset_tests.py15
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py98
-rwxr-xr-xtests.as-root/unimportant-morphology-contents-do-not-change-cache-keys.script45
-rwxr-xr-xtests.branching.disabled/workflow-petrify.script67
-rw-r--r--tests.branching.disabled/workflow-petrify.stdout152
-rwxr-xr-xtests.branching/ambiguous-refs.script46
-rwxr-xr-xtests.branching/build-after-petrify.script31
-rwxr-xr-xtests.branching/petrify-no-double-petrify.script34
-rw-r--r--tests.branching/petrify-no-double-petrify.stdout9
-rwxr-xr-xtests.branching/petrify.script42
-rw-r--r--tests.branching/petrify.stdout31
-rw-r--r--yarns/branches-workspaces.yarn1
14 files changed, 615 insertions, 2 deletions
diff --git a/doc/branching-merging-systems.mdwn b/doc/branching-merging-systems.mdwn
index 3bc19aab..c2e24d77 100644
--- a/doc/branching-merging-systems.mdwn
+++ b/doc/branching-merging-systems.mdwn
@@ -129,7 +129,7 @@ Also, clone the `morphs` git repository inside the system branch
directory.
cd ~/baserock/liw/foo/morphs
- edit base-system.morph devel-system.morph
+ morph petrify base-system.morph devel-system.morph
git commit -a
Modify the specified morphologies (or the stratum morphologies they
@@ -225,6 +225,36 @@ it to exist instead.
* Run `git checkout BRANCH` in the `morphs` repository.
+Implementation: `morph petrify`
+--------------
+
+Usage:
+
+ morph petrify [MORPH]...
+ morph petrify --petrify-from-system FILE
+
+This needs to be run in the `morphs` git repository in a system branch.
+
+In the first form:
+
+* read each of the given morphologies; if the morphology is a system one,
+ follow references to stratum morphologies and process those instead
+* in each stratum morphology, replace a reference to a chunk with the
+ absolute SHA-1: if the original reference was, say, `baserock/morph`,
+ get the SHA-1 of the current tip commit in that branch and replace
+ the reference in the morphology
+
+In the second form:
+
+* extract the system and stratum morphologies used in the system image file;
+ these are in a petrified form already
+* copy the morphologies to the current working directory, overwriting the
+ files from git
+
+In either case, the results need to be committed (with normal git commands)
+by the user.
+
+
Implementation: `morph edit`
--------------
diff --git a/morphlib/morphset.py b/morphlib/morphset.py
index a4cb5dae..17c9cdc4 100644
--- a/morphlib/morphset.py
+++ b/morphlib/morphset.py
@@ -244,3 +244,17 @@ class MorphologySet(object):
return True
self.traverse_specs(process_chunk_spec, wanted_chunk_spec)
+
+ def unpetrify_all(self):
+ '''If a spec is petrified, unpetrify it.
+
+ '''
+
+ def wanted_spec(m, kind, spec):
+ return ('unpetrify-ref' in spec and
+ morphlib.git.is_valid_sha1(spec.get('ref')))
+ def process_spec(m, kind, spec):
+ spec['ref'] = spec.pop('unpetrify-ref')
+ return True
+
+ self.traverse_specs(process_spec, wanted_spec)
diff --git a/morphlib/morphset_tests.py b/morphlib/morphset_tests.py
index bf726d4c..f7378d39 100644
--- a/morphlib/morphset_tests.py
+++ b/morphlib/morphset_tests.py
@@ -199,3 +199,18 @@ class MorphologySetTests(unittest.TestCase):
'unpetrify-ref': 'master',
}
])
+
+ def test_unpetrify_all(self):
+ self.morphs.add_morphology(self.system)
+ self.morphs.add_morphology(self.stratum)
+ self.morphs.petrify_chunks({('test:foo-chunk', 'master'): '0'*40})
+ self.morphs.unpetrify_all()
+ self.assertEqual(
+ self.stratum['chunks'],
+ [
+ {
+ 'repo': 'test:foo-chunk',
+ 'ref': 'master',
+ 'morph': 'foo-chunk',
+ }
+ ])
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 08589ea6..9a2851d8 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -37,6 +37,10 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.add_subcommand(
'edit', self.edit, arg_synopsis='CHUNK')
self.app.add_subcommand(
+ 'petrify', self.petrify, arg_synopsis='')
+ self.app.add_subcommand(
+ 'unpetrify', self.unpetrify, arg_synopsis='')
+ self.app.add_subcommand(
'show-system-branch', self.show_system_branch, arg_synopsis='')
self.app.add_subcommand(
'show-branch-root', self.show_branch_root, arg_synopsis='')
@@ -490,6 +494,100 @@ class BranchAndMergePlugin(cliapp.Plugin):
morphs.add_morphology(morph)
return morphs
+ def petrify(self, args):
+ '''Convert all chunk refs in a system branch to be fixed SHA1s.
+
+ This modifies all git commit references in system and stratum
+ morphologies, in the current system branch, to be fixed SHA
+ commit identifiers, rather than symbolic branch or tag names.
+ This is useful for making sure none of the components in a system
+ branch change accidentally.
+
+ Consider the following scenario:
+
+ * The `master` system branch refers to `gcc` using the
+ `baserock/morph` ref. This is appropriate, since the main line
+ of development should use the latest curated code.
+
+ * You create a system branch to prepare for a release, called
+ `TROVE_ID/release/2.0`. The reference to `gcc` is still
+ `baserock/morph`.
+
+ * You test everything, and make a release. You deploy the release
+ images onto devices, which get shipped to your customers.
+
+ * A new version GCC is committed to the `baserock/morph` branch.
+
+ * Your release branch suddenly uses a new compiler, which may
+ or may not work for your particular system at that release.
+
+ To avoid this, you need to _petrify_ all git references
+ so that they do not change accidentally. If you've tested
+ your release with the GCC release that is stored in commit
+ `94c50665324a7aeb32f3096393ec54b2e63bfb28`, then you should
+ continue to use that version of GCC, regardless of what might
+ happen in the master system branch. If, and only if, you decide
+ that a new compiler would be good for your release should you
+ include it in your release branch. This way, only the things
+ that you change intentionally change in your release branch.
+
+ '''
+
+ if args:
+ raise cliapp.AppException('morph petrify takes no arguments')
+
+ ws = morphlib.workspace.open('.')
+ sb = morphlib.sysbranchdir.open_from_within('.')
+ loader = morphlib.morphloader.MorphologyLoader()
+ lrc, rrc = morphlib.util.new_repo_caches(self.app)
+ update_repos = not self.app.settings['no-git-update']
+
+ morphs = self._load_all_sysbranch_morphologies(sb, loader)
+
+ #TODO: Stop using app.resolve_ref
+ def resolve_refs(morphs):
+ for repo, ref in morphs.list_refs():
+ # You can't resolve null refs, so don't attempt to.
+ if repo is None or ref is None:
+ continue
+ # TODO: Handle refs that are only in workspace in general
+ if (repo == sb.root_repository_url
+ and ref == sb.system_branch_name):
+ continue
+ commit_sha1, tree_sha1 = self.app.resolve_ref(
+ lrc, rrc, repo, ref, update=update_repos)
+ yield ((repo, ref), commit_sha1)
+
+ morphs.repoint_refs(sb.root_repository_url,
+ sb.system_branch_name)
+
+ morphs.petrify_chunks(dict(resolve_refs(morphs)))
+
+ # Write morphologies back out again.
+ self._save_dirty_morphologies(loader, sb, morphs.morphologies)
+
+ def unpetrify(self, args):
+ '''Reverse the process of petrification.
+
+ This undoes the changes `morph petrify` did.
+
+ '''
+
+ if args:
+ raise cliapp.AppException('morph petrify takes no arguments')
+
+ ws = morphlib.workspace.open('.')
+ sb = morphlib.sysbranchdir.open_from_within('.')
+ loader = morphlib.morphloader.MorphologyLoader()
+
+ morphs = self._load_all_sysbranch_morphologies(sb, loader)
+
+ # Restore the ref for each stratum and chunk
+ morphs.unpetrify_all()
+
+ # Write morphologies back out again.
+ self._save_dirty_morphologies(loader, sb, morphs.morphologies)
+
def status(self, args):
'''Show information about the current system branch or workspace
diff --git a/tests.as-root/unimportant-morphology-contents-do-not-change-cache-keys.script b/tests.as-root/unimportant-morphology-contents-do-not-change-cache-keys.script
new file mode 100755
index 00000000..a540cdee
--- /dev/null
+++ b/tests.as-root/unimportant-morphology-contents-do-not-change-cache-keys.script
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# Copyright (C) 2012-2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+## Some contents of morphologies (description, build-depends, chunks)
+## should not change the cache keys of those morphs because they are
+## either already considered (build-depends and chunks) or do not affect
+## building (description). This test checks that changes to these parts
+## of a morphology do not force rebuilds.
+
+# FIXME: This seems to break because the new "morph edit" makes correct
+# changes to build-dependencies, which breaks the old "morph build".
+# Disable test now, re-enable it after "morph build" is fixed. --liw
+exit 0
+
+set -eu
+
+source "$SRCDIR/tests.as-root/setup-build"
+
+# Build once.
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" build linux-system
+ARTIFACT_COUNT="$(ls "$DATADIR/cache/artifacts" | wc -l)"
+
+# Petrify the refs, so the morphologies will be different
+(set -e && cd branch1/test/morphs && git push --quiet origin HEAD)
+(set -e && cd branch1/test/kernel-repo && git push --quiet origin HEAD)
+"$SRCDIR/scripts/test-morph" petrify
+
+# Build with the petrified morphologies.
+"$SRCDIR/scripts/test-morph" build linux-system
+[ "$ARTIFACT_COUNT" -eq $(ls "$DATADIR/cache/artifacts" | wc -l) ]
diff --git a/tests.branching.disabled/workflow-petrify.script b/tests.branching.disabled/workflow-petrify.script
new file mode 100755
index 00000000..3c561d5b
--- /dev/null
+++ b/tests.branching.disabled/workflow-petrify.script
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+## Do a complete workflow test, with strata outside the main morphologies
+## repository.
+
+set -eu
+
+. "$SRCDIR/scripts/setup-3rd-party-strata"
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" branch test:morphs test/petrify
+
+cd test/petrify
+"$SRCDIR/scripts/test-morph" petrify
+
+echo "test/petrify after petrifying:"
+cat test:morphs/hello-system.morph
+cat test:external-strata/stratum2.morph
+cat test:external-strata/stratum3.morph
+
+"$SRCDIR/scripts/test-morph" edit hello
+
+echo
+echo "test/petrify after editing a chunk:"
+cat test:morphs/hello-system.morph
+cat test:external-strata/stratum2.morph
+cat test:external-strata/stratum3.morph
+
+# me/readme-fixes in test:stratum2-hello should be 'master', but
+# that's the only ref upstream so we can infer that it is if we got here
+
+cd test:morphs
+git commit --quiet --all -m "Petrify branch test/petrify"
+git push --quiet origin test/petrify
+cd ../test:external-strata
+git commit --quiet --all -m "Petrify branch test/petrify"
+git push --quiet origin test/petrify
+
+# unpetrify is easy enough. Let's try unpetrifying a different branch that
+# was forked off the original while it was petrified, instead.
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" branch test:morphs test/unpetrify test/petrify
+
+cd test/unpetrify
+"$SRCDIR/scripts/test-morph" unpetrify
+
+echo
+echo "test/unpetrify after unpetrifying:"
+cat test:morphs/hello-system.morph
+cat test:external-strata/stratum2.morph
+cat test:external-strata/stratum3.morph
diff --git a/tests.branching.disabled/workflow-petrify.stdout b/tests.branching.disabled/workflow-petrify.stdout
new file mode 100644
index 00000000..a0ce82f4
--- /dev/null
+++ b/tests.branching.disabled/workflow-petrify.stdout
@@ -0,0 +1,152 @@
+test/petrify after petrifying:
+{
+ "name": "hello-system",
+ "kind": "system",
+ "arch": "x86_64",
+ "strata": [
+ {
+ "morph": "hello-stratum",
+ "repo": "test:morphs",
+ "ref": "test/petrify"
+ },
+ {
+ "morph": "stratum2",
+ "repo": "test:external-strata",
+ "ref": "test/petrify"
+ },
+ {
+ "morph": "stratum3",
+ "repo": "test:external-strata",
+ "ref": "test/petrify"
+ }
+ ]
+}
+{
+ "name": "stratum2",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum2-hello",
+ "ref": "f4730636e429149bb923fa16be3aa9802d484b23",
+ "build-mode": "test",
+ "build-depends": [],
+ "unpetrify-ref": "master"
+ }
+ ]
+}
+{
+ "name": "stratum3",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum3-hello",
+ "ref": "f4730636e429149bb923fa16be3aa9802d484b23",
+ "build-mode": "test",
+ "build-depends": [],
+ "unpetrify-ref": "master"
+ }
+ ]
+}
+
+test/petrify after editing a chunk:
+{
+ "name": "hello-system",
+ "kind": "system",
+ "arch": "x86_64",
+ "strata": [
+ {
+ "morph": "hello-stratum",
+ "repo": "test:morphs",
+ "ref": "test/petrify"
+ },
+ {
+ "morph": "stratum2",
+ "repo": "test:external-strata",
+ "ref": "test/petrify"
+ },
+ {
+ "morph": "stratum3",
+ "repo": "test:external-strata",
+ "ref": "test/petrify"
+ }
+ ]
+}
+{
+ "name": "stratum2",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum2-hello",
+ "ref": "test/petrify",
+ "build-mode": "test",
+ "build-depends": []
+ }
+ ]
+}
+{
+ "name": "stratum3",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum3-hello",
+ "ref": "f4730636e429149bb923fa16be3aa9802d484b23",
+ "build-mode": "test",
+ "build-depends": [],
+ "unpetrify-ref": "master"
+ }
+ ]
+}
+
+test/unpetrify after unpetrifying:
+{
+ "name": "hello-system",
+ "kind": "system",
+ "arch": "x86_64",
+ "strata": [
+ {
+ "morph": "hello-stratum",
+ "repo": "test:morphs",
+ "ref": "test/unpetrify"
+ },
+ {
+ "morph": "stratum2",
+ "repo": "test:external-strata",
+ "ref": "test/unpetrify"
+ },
+ {
+ "morph": "stratum3",
+ "repo": "test:external-strata",
+ "ref": "test/unpetrify"
+ }
+ ]
+}
+{
+ "name": "stratum2",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum2-hello",
+ "ref": "test/petrify",
+ "build-mode": "test",
+ "build-depends": []
+ }
+ ]
+}
+{
+ "name": "stratum3",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "hello",
+ "repo": "test:stratum3-hello",
+ "ref": "master",
+ "build-mode": "test",
+ "build-depends": []
+ }
+ ]
+}
diff --git a/tests.branching/ambiguous-refs.script b/tests.branching/ambiguous-refs.script
new file mode 100755
index 00000000..aeec61a1
--- /dev/null
+++ b/tests.branching/ambiguous-refs.script
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+## Guard against a bug that occurs if 'git show-ref' is used to resolve refs
+## instead of 'git rev-parse --verify': show-ref returns a list of partial
+## matches sorted alphabetically, so any code using it may resolve refs
+## incorrectly.
+
+set -eu
+
+. "$SRCDIR/scripts/fix-committer-info"
+
+cd "$DATADIR/morphs"
+git mv hello-stratum.morph goodbye-stratum.morph
+sed -e '/morph: hello-stratum/s/hello-stratum/goodbye-stratum/' \
+ -i hello-system.morph
+
+git commit --quiet -am "Rename hello-system"
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+"$SRCDIR/scripts/test-morph" branch test:morphs release
+
+# Create an extra ref to confuse any users of git show-ref
+cd release/test/morphs
+git checkout --quiet -b alpha/master HEAD~1
+git checkout --quiet release
+
+# The petrify will fail if we resolved 'master' as 'alpha/master' by mistake.
+cd "$DATADIR/workspace/release/test/morphs"
+"$SRCDIR/scripts/test-morph" petrify
diff --git a/tests.branching/build-after-petrify.script b/tests.branching/build-after-petrify.script
new file mode 100755
index 00000000..d3b75f07
--- /dev/null
+++ b/tests.branching/build-after-petrify.script
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+## Verify systems can be built after "morph petrify"
+
+set -eu
+
+. "$SRCDIR/tests.branching/setup-second-chunk"
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+"$SRCDIR/scripts/test-morph" branch test:morphs test/build-petrify master
+
+"$SRCDIR/scripts/test-morph" petrify
+
+"$SRCDIR/scripts/test-morph" build hello-system
diff --git a/tests.branching/petrify-no-double-petrify.script b/tests.branching/petrify-no-double-petrify.script
new file mode 100755
index 00000000..3c9185dc
--- /dev/null
+++ b/tests.branching/petrify-no-double-petrify.script
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+## It should be impossible to lose the original refs, or we risk making
+## unpetrify impossible.
+
+set -eu
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+"$SRCDIR/scripts/test-morph" branch test:morphs test/petrify
+
+cd test/petrify/test/morphs
+git push --quiet origin HEAD
+"$SRCDIR/scripts/test-morph" petrify
+"$SRCDIR/scripts/test-morph" petrify
+"$SRCDIR/scripts/test-morph" petrify
+
+cat hello-stratum.morph
diff --git a/tests.branching/petrify-no-double-petrify.stdout b/tests.branching/petrify-no-double-petrify.stdout
new file mode 100644
index 00000000..50da61ba
--- /dev/null
+++ b/tests.branching/petrify-no-double-petrify.stdout
@@ -0,0 +1,9 @@
+name: hello-stratum
+kind: stratum
+chunks:
+- name: hello
+ repo: test:hello
+ ref: 293fa0b08f0382c63181c36b6efa602876aa8c87
+ unpetrify-ref: master
+ build-depends: []
+ build-mode: test
diff --git a/tests.branching/petrify.script b/tests.branching/petrify.script
new file mode 100755
index 00000000..f8e7c1e9
--- /dev/null
+++ b/tests.branching/petrify.script
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+## Verify "morph petrify", and ensure it doesn't petrify chunks that have
+## already been edited.
+
+set -eu
+
+. "$SRCDIR/tests.branching/setup-second-chunk"
+
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+"$SRCDIR/scripts/test-morph" branch test:morphs test/petrify master
+
+cd test/petrify/test/morphs
+git push --quiet origin HEAD
+"$SRCDIR/scripts/test-morph" edit goodbye
+(cd ../goodbye && git push --quiet origin HEAD)
+
+"$SRCDIR/scripts/test-morph" petrify
+echo "Petrified:"
+cat hello-stratum.morph
+
+"$SRCDIR/scripts/test-morph" unpetrify
+echo
+echo "Unpetrified:"
+cat hello-stratum.morph
diff --git a/tests.branching/petrify.stdout b/tests.branching/petrify.stdout
new file mode 100644
index 00000000..f9f35342
--- /dev/null
+++ b/tests.branching/petrify.stdout
@@ -0,0 +1,31 @@
+Petrified:
+name: hello-stratum
+kind: stratum
+chunks:
+- name: hello
+ repo: test:hello
+ ref: 293fa0b08f0382c63181c36b6efa602876aa8c87
+ unpetrify-ref: master
+ build-depends: []
+ build-mode: test
+- name: goodbye
+ repo: test:goodbye
+ ref: 717c4a523fb5a94ca2f0a61e665fbc2da6a1f6ac
+ unpetrify-ref: test/petrify
+ build-depends: []
+ build-mode: test
+
+Unpetrified:
+name: hello-stratum
+kind: stratum
+chunks:
+- name: hello
+ repo: test:hello
+ ref: master
+ build-depends: []
+ build-mode: test
+- name: goodbye
+ repo: test:goodbye
+ ref: test/petrify
+ build-depends: []
+ build-mode: test
diff --git a/yarns/branches-workspaces.yarn b/yarns/branches-workspaces.yarn
index 3b765b57..bd520ff1 100644
--- a/yarns/branches-workspaces.yarn
+++ b/yarns/branches-workspaces.yarn
@@ -202,6 +202,5 @@ artifact in a system. This name includes the cache key of the artifact.
SCENARIO using morph list-artifacts
GIVEN a git server
-
WHEN the user lists the artifacts which make up the system systems/test-system.morph at ref HEAD in repository test:morphs
THEN morph succeeded