commit - a76c42e670c040cbc63fae5cedba54de3540ce3c
commit + f0b75401029052c2613a1e5dc3882976b2ab4da9
blob - 0a2e9fc90236fca9a7c4e1c9efbd07616aa5e5c6
blob + cbf9d0673835a5bbdf1e42566551338b16037fde
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_STAGE_NO_CHANGE 102
#define GOT_ERR_STAGE_CONFLICT 103
#define GOT_ERR_STAGE_OUT_OF_DATE 104
+#define GOT_ERR_FILE_NOT_STAGED 105
static const struct got_error {
int code;
{ GOT_ERR_STAGE_CONFLICT, "cannot stage file in conflicted status" },
{ GOT_ERR_STAGE_OUT_OF_DATE, "work tree must be updated before "
"changes can be staged" },
+ { GOT_ERR_FILE_NOT_STAGED, "file is not staged" },
};
/*
blob - f7db624a62986cd2410180c91f9ad5c7bccb6962
blob + c45a95888b5015de44ca323f6dd4759e19eb36f4
--- lib/got_lib_worktree.h
+++ lib/got_lib_worktree.h
char *in_repo_path;
char *ondisk_path;
unsigned char status;
+ unsigned char staged_status;
struct got_object_id *blob_id;
struct got_object_id *base_blob_id;
+ struct got_object_id *staged_blob_id;
struct got_object_id *base_commit_id;
mode_t mode;
int flags;
blob - 0115f0622a0a1725349d74ab33e8f9c95ba22184
blob + 0f55d723f8ac61a963a08b5f6e01cce9a7b96232
--- lib/worktree.c
+++ lib/worktree.c
free(ct->ondisk_path);
free(ct->blob_id);
free(ct->base_blob_id);
+ free(ct->staged_blob_id);
free(ct->base_commit_id);
free(ct);
}
}
ct->base_commit_id = got_object_id_dup(commit_id);
if (ct->base_commit_id == NULL) {
+ err = got_error_from_errno("got_object_id_dup");
+ goto done;
+ }
+ }
+ ct->staged_status = staged_status;
+ if (ct->staged_status == GOT_STATUS_ADD ||
+ ct->staged_status == GOT_STATUS_MODIFY) {
+ ct->staged_blob_id = got_object_id_dup(staged_blob_id);
+ if (ct->staged_blob_id == NULL) {
err = got_error_from_errno("got_object_id_dup");
goto done;
}
done:
free(id);
return err;
-}
-
-static const struct got_error *
-check_ct_out_of_date(struct got_commitable *ct, struct got_repository *repo,
- struct got_object_id *head_commit_id)
-{
- const char *ct_path = ct->in_repo_path;
-
- while (ct_path[0] == '/')
- ct_path++;
-
- return check_out_of_date(ct_path, ct->status, ct->base_commit_id,
- ct->base_commit_id, head_commit_id, repo,
- GOT_ERR_COMMIT_OUT_OF_DATE);
}
const struct got_error *
return NULL;
}
+static const struct got_error *
+check_staged_file(void *arg, struct got_fileindex_entry *ie)
+{
+ int *have_staged_files = arg;
+
+ if (got_fileindex_entry_stage_get(ie) != GOT_FILEIDX_STAGE_NONE) {
+ *have_staged_files = 1;
+ return got_error(GOT_ERR_CANCELLED);
+ }
+
+ return NULL;
+}
+
const struct got_error *
got_worktree_commit(struct got_object_id **new_commit_id,
struct got_worktree *worktree, struct got_pathlist_head *paths,
struct got_pathlist_entry *pe;
struct got_reference *head_ref = NULL;
struct got_object_id *head_commit_id = NULL;
+ int have_staged_files = 0;
*new_commit_id = NULL;
if (err)
goto done;
}
+
+ err = got_fileindex_for_each_entry_safe(fileindex, check_staged_file,
+ &have_staged_files);
+ if (err && err->code != GOT_ERR_CANCELLED)
+ goto done;
TAILQ_FOREACH(pe, &commitable_paths, entry) {
struct got_commitable *ct = pe->data;
- err = check_ct_out_of_date(ct, repo, head_commit_id);
+ const char *ct_path = ct->in_repo_path;
+
+ while (ct_path[0] == '/')
+ ct_path++;
+ err = check_out_of_date(ct_path, ct->status,
+ ct->base_blob_id, ct->base_commit_id, head_commit_id,
+ repo, GOT_ERR_COMMIT_OUT_OF_DATE);
if (err)
+ goto done;
+ if (have_staged_files &&
+ ct->staged_status == GOT_STATUS_NO_CHANGE) {
+ err = got_error_path(ct_path, GOT_ERR_FILE_NOT_STAGED);
goto done;
+ }
+
}
err = commit_worktree(new_commit_id, &commitable_paths,
blob - 55bad574818603f55ad63de1e59ea2d528baa75d
blob + 385f2ae28ee8d1ea15b50cecf144752e04df7a6a
--- regress/cmdline/commit.sh
+++ regress/cmdline/commit.sh
function test_commit_out_of_date {
local testroot=`test_init commit_out_of_date`
+ local first_commit=`git_show_head $testroot/repo`
got checkout $testroot/repo $testroot/wt > /dev/null
ret="$?"
(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
ret="$?"
if [ "$ret" != "0" ]; then
diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
fi
+
+ echo "alpha" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "reset alpha contents"
+ (cd $testroot/wt && got update -c $first_commit > /dev/null)
+
+ echo "modified alpha" > $testroot/wt/alpha
+
+ (cd $testroot/wt && got commit -m 'changed alpha ' > $testroot/stdout)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "commit failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo "M alpha" > $testroot/stdout.expected
+ echo "Created commit $head_rev" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
test_done "$testroot" "$ret"
}
blob - 4d057d721979e93aa1b31d4d280ee4f9deadbab0
blob + 61e10ca408100bac2afcaedb9e1365b607e0a48b
--- regress/cmdline/stage.sh
+++ regress/cmdline/stage.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_stage_commit_non_staged {
+ local testroot=`test_init stage_commit_non_staged`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified file" > $testroot/wt/alpha
+ (cd $testroot/wt && got rm beta > /dev/null)
+ echo "new file" > $testroot/wt/foo
+ (cd $testroot/wt && got add foo > /dev/null)
+ (cd $testroot/wt && got stage alpha beta foo > /dev/null)
+ echo "modified file" > $testroot/wt/gamma/delta
+ (cd $testroot/wt && got commit -m "change delta" gamma/delta \
+ > $testroot/stdout 2> $testroot/stderr)
+ ret="$?"
+ if [ "$ret" == "0" ]; then
+ echo "got commit command succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo -n > $testroot/stdout.expected
+ echo "got: gamma/delta: file is not staged" > $testroot/stderr.expected
+
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_stage_basic
run_test test_stage_conflict
run_test test_stage_out_of_date
run_test test_stage_histedit
run_test test_stage_rebase
run_test test_stage_update
+run_test test_stage_commit_non_staged