diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml
index 2c821fc1..b0c5b335 100644
--- a/man/ostree-commit.xml
+++ b/man/ostree-commit.xml
@@ -106,6 +106,15 @@ Boston, MA 02111-1307, USA.
+
+ ="REV"
+
+
+ Start from the content in a commit. This differs from --tree=ref=REV in that no commit modifiers are applied. This is usually what you want when
+ creating a derived commit. This is also used for --selinux-policy-from-base.
+
+
+
="KEY=VALUE"
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index 606af2be..72fa2841 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -58,6 +58,7 @@ static gboolean opt_selinux_policy_from_base;
static gboolean opt_canonical_permissions;
static gboolean opt_consume;
static gboolean opt_devino_canonical;
+static char *opt_base;
static char **opt_trees;
static gint opt_owner_uid = -1;
static gint opt_owner_gid = -1;
@@ -101,6 +102,7 @@ static GOptionEntry options[] = {
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
{ "no-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_no_bindings, "Do not write any ref bindings", NULL },
{ "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" },
+ { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)" },
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" },
{ "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" },
{ "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" },
@@ -600,7 +602,32 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
if (opt_link_checkout_speedup && !ostree_repo_scan_hardlinks (repo, cancellable, error))
goto out;
- mtree = ostree_mutable_tree_new ();
+ if (opt_base)
+ {
+ g_autofree char *base_commit = NULL;
+ g_autoptr(GFile) root = NULL;
+ if (!ostree_repo_read_commit (repo, opt_base, &root, &base_commit, cancellable, error))
+ goto out;
+ OstreeRepoFile *rootf = (OstreeRepoFile*) root;
+
+ mtree = ostree_mutable_tree_new_from_checksum (repo,
+ ostree_repo_file_tree_get_contents_checksum (rootf),
+ ostree_repo_file_tree_get_metadata_checksum (rootf));
+
+ if (opt_selinux_policy_from_base)
+ {
+ g_assert (modifier);
+ if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, base_commit, cancellable, error))
+ goto out;
+ /* Don't try to handle it twice */
+ opt_selinux_policy_from_base = FALSE;
+ }
+ }
+ else
+ {
+ mtree = ostree_mutable_tree_new ();
+ }
+
/* Convert implicit . or explicit path via argv into
* --tree=dir= so that we only have one primary code path below.
diff --git a/tests/archive-test.sh b/tests/archive-test.sh
index 42b232bf..1e63a35b 100644
--- a/tests/archive-test.sh
+++ b/tests/archive-test.sh
@@ -68,3 +68,11 @@ echo "ok cat-file"
cd ${test_tmpdir}
$OSTREE fsck
echo "ok fsck"
+
+mkdir -p test-overlays
+date > test-overlays/overlaid-file
+$OSTREE commit ${COMMIT_ARGS} -b test-base --base test2 --owner-uid 42 --owner-gid 42 test-overlays/
+$OSTREE ls -R test-base > ls.txt
+assert_streq "$(wc -l < ls.txt)" 14
+assert_streq "$(grep '42.*42' ls.txt | wc -l)" 2
+echo "ok commit overlay base"
diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh
index 0dccd737..c27ce03f 100755
--- a/tests/test-archivez.sh
+++ b/tests/test-archivez.sh
@@ -23,7 +23,7 @@ set -euo pipefail
. $(dirname $0)/libtest.sh
-echo '1..12'
+echo '1..13'
setup_test_repository "archive"