commit - 69844fbab193c41fa361eefe874f37ed2f7d26a3
commit + 64c6d99023a672f220d1de2662dfe52300f51ea2
blob - 1780abc217ffcc573874381bf38a884d642ed56e
blob + f5918cd2aab9138de84e3108140aac04a83037df
--- got/got.1
+++ got/got.1
.Cm got update .
If the work tree contains local changes, these changes must be committed
or reverted first.
+If the
+.Ar branch
+contains changes to files outside of the work tree's path prefix,
+the work tree cannot be used to rebase this branch.
.Pp
The
.Cm got update
blob - 178e89a6d7544bc1ba03c425048f3307dd462312
blob + 26e1d49401834d67cbff109f6d3e09cd46be8449
--- got/got.c
+++ got/got.c
done:
got_object_commit_close(commit);
return error;
+}
+
+struct check_path_prefix_arg {
+ const char *path_prefix;
+ size_t len;
+};
+
+static const struct got_error *
+check_path_prefix(void *arg, struct got_blob_object *blob1,
+ struct got_blob_object *blob2, struct got_object_id *id1,
+ struct got_object_id *id2, const char *path1, const char *path2,
+ struct got_repository *repo)
+{
+ struct check_path_prefix_arg *a = arg;
+
+ if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
+ (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
+ return got_error(GOT_ERR_REBASE_PATH);
+
+ return NULL;
+}
+
+static const struct got_error *
+rebase_check_path_prefix(struct got_object_id *parent_id,
+ struct got_object_id *commit_id, const char *path_prefix,
+ struct got_repository *repo)
+{
+ const struct got_error *err;
+ struct got_tree_object *tree1 = NULL, *tree2 = NULL;
+ struct got_commit_object *commit = NULL, *parent_commit = NULL;
+ struct check_path_prefix_arg cpp_arg;
+
+ if (got_path_is_root_dir(path_prefix))
+ return NULL;
+
+ err = got_object_open_as_commit(&commit, repo, commit_id);
+ if (err)
+ goto done;
+
+ err = got_object_open_as_commit(&parent_commit, repo, parent_id);
+ if (err)
+ goto done;
+
+ err = got_object_open_as_tree(&tree1, repo,
+ got_object_commit_get_tree_id(parent_commit));
+ if (err)
+ goto done;
+
+ err = got_object_open_as_tree(&tree2, repo,
+ got_object_commit_get_tree_id(commit));
+ if (err)
+ goto done;
+
+ cpp_arg.path_prefix = path_prefix;
+ cpp_arg.len = strlen(path_prefix);
+ err = got_diff_tree(tree1, tree2, "", "", repo, check_path_prefix,
+ &cpp_arg);
+done:
+ if (tree1)
+ got_object_tree_close(tree1);
+ if (tree2)
+ got_object_tree_close(tree2);
+ if (commit)
+ got_object_commit_close(commit);
+ if (parent_commit)
+ got_object_commit_close(parent_commit);
+ return err;
}
static const struct got_error *
if (error)
goto done;
} else {
+ error = rebase_check_path_prefix(parent_id, commit_id,
+ got_worktree_get_path_prefix(worktree), repo);
+ if (error)
+ goto done;
+
error = got_object_qid_alloc(&qid, commit_id);
if (error)
goto done;
blob - 4a4ef0bdd9c32b7b02ae4cccbc6f721e54dfcc43
blob + 48ede3e31fd5acad44260af32cff4957fb97fdad
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_EMPTY_REBASE 86
#define GOT_ERR_REBASE_COMMITID 87
#define GOT_ERR_REBASING 88
+#define GOT_ERR_REBASE_PATH 89
static const struct got_error {
int code;
{ GOT_ERR_REBASE_COMMITID,"rebase commit ID mismatch" },
{ GOT_ERR_REBASING, "a rebase operation is in progress in this "
"work tree and must be continued or aborted first" },
+ { GOT_ERR_REBASE_PATH, "cannot rebase branch which contains "
+ "changes outside of this work tree's path prefix" },
};
/*
blob - 91b9ba8be58e42753c9f676acbdaa9514e14bddb
blob + 7ea64d7ebe0847c750649789dc27c2f0d8a27428
--- regress/cmdline/rebase.sh
+++ regress/cmdline/rebase.sh
return 1
fi
done
+
+ test_done "$testroot" "$ret"
+}
+
+function test_rebase_path_prefix {
+ local testroot=`test_init rebase_path_prefix`
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified delta on branch" > $testroot/repo/gamma/delta
+ git_commit $testroot/repo -m "committing to delta on newbranch"
+
+ local orig_commit1=`git_show_parent_commit $testroot/repo`
+ local orig_commit2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q master)
+ echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+ git_commit $testroot/repo -m "committing to zeta on master"
+ local master_commit=`git_show_head $testroot/repo`
+
+ got checkout -p epsilon $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+ (cd $testroot/wt && got rebase newbranch \
+ > $testroot/stdout 2> $testroot/stderr)
+
+ echo -n > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n "got: cannot rebase branch which contains changes outside " \
+ > $testroot/stderr.expected
+ echo "of this work tree's path prefix" >> $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ fi
test_done "$testroot" "$ret"
}
run_test test_rebase_abort
run_test test_rebase_no_op_change
run_test test_rebase_in_progress
+run_test test_rebase_path_prefix