Commit Diff


commit - e75eb4dad0d15e60680bf15c957ccd6099a9e22c
commit + 819f385b2053664dbfd5c1d0201fb84bc7e3c5a6
blob - 640ad150c74800a6bd02833ddf62dbb7d2c07004
blob + 785766a030c1661d6a5e8806b18a277e3aebef8a
--- include/got_error.h
+++ 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" },
 };
 
 /*
blob - 51b188522dd96824bcdaad18e24bde7c84c81179
blob + d29a9bd8996f361ceba6c402b9cc22d20f7c0938
--- lib/worktree.c
+++ lib/worktree.c
@@ -2833,7 +2833,29 @@ got_worktree_commit(struct got_object_id **new_commit_
 	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)
blob - a69fc89299a34873881a00b21a3b20c1af9d65a2
blob + d9093b3371894b4a89fc9a496e26459e0e75f09f
--- regress/cmdline/commit.sh
+++ 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