ensure that commits use intended base blobs for changes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
diff --git a/include/got_error.h b/include/got_error.h
index 640ad15..785766a 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -86,6 +86,7 @@
#define GOT_ERR_BAD_REF_TYPE 70
#define GOT_ERR_COMMIT_NO_AUTHOR 71
#define GOT_ERR_COMMIT_HEAD_CHANGED 72
+#define GOT_ERR_COMMIT_OUT_OF_DATE 73
static const struct got_error {
int code;
@@ -164,6 +165,8 @@ static const struct got_error {
{ GOT_ERR_COMMIT_NO_AUTHOR,"GOT_AUTHOR environment variable is not set" },
{ GOT_ERR_COMMIT_HEAD_CHANGED, "branch head in repository has changed "
"while commit was in progress" },
+ { GOT_ERR_COMMIT_OUT_OF_DATE, "work tree must be updated before these "
+ "changes can be committed" },
};
/*
diff --git a/lib/worktree.c b/lib/worktree.c
index 51b1885..d29a9bd 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -2833,7 +2833,29 @@ got_worktree_commit(struct got_object_id **new_commit_id,
if (err)
goto done;
- /* TODO: out-of-dateness check */
+ /* Out-of-dateness check against branch head. */
+ TAILQ_FOREACH(pe, &commitable_paths, entry) {
+ struct commitable *ct = pe->data;
+ struct got_object_id *id_in_head;
+
+ err = got_object_id_by_path(&id_in_head, repo,
+ head_commit_id, ct->in_repo_path);
+ if (err) {
+ if (err->code == GOT_ERR_NO_TREE_ENTRY &&
+ ct->status == GOT_STATUS_ADD) {
+ err = NULL;
+ id_in_head = NULL;
+ } else
+ goto done;
+ }
+ if (id_in_head &&
+ got_object_id_cmp(id_in_head, ct->base_id) != 0) {
+ err = got_error(GOT_ERR_COMMIT_OUT_OF_DATE);
+ free(id_in_head);
+ goto done;
+ }
+ free(id_in_head);
+ }
err = got_object_open_as_tree(&head_tree, repo, head_commit->tree_id);
if (err)
diff --git a/regress/cmdline/commit.sh b/regress/cmdline/commit.sh
index a69fc89..d9093b3 100755
--- a/regress/cmdline/commit.sh
+++ b/regress/cmdline/commit.sh
@@ -138,7 +138,47 @@ function test_commit_single_file {
test_done "$testroot" "$ret"
}
+function test_commit_out_of_date {
+ local testroot=`test_init commit_out_of_date`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "modified alpha"
+
+ echo "modified alpha" > $testroot/wt/alpha
+
+ (cd $testroot/wt && got commit -m 'test commit_out_of_date' \
+ > $testroot/stdout 2> $testroot/stderr)
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo -n > $testroot/stdout.expected
+ echo "got: work tree must be updated before these" \
+ "changes can be committed" > $testroot/stderr.expected
+
+ cmp $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cmp $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_commit_basic
run_test test_commit_new_subdir
run_test test_commit_subdir
run_test test_commit_single_file
+run_test test_commit_out_of_date