handle double-staging
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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
diff --git a/include/got_error.h b/include/got_error.h
index 8450cbb..462aba4 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -115,6 +115,7 @@
#define GOT_ERR_NO_MERGED_PATHS 99
#define GOT_ERR_COMMIT_BRANCH 100
#define GOT_ERR_FILE_STAGED 101
+#define GOT_ERR_STAGE_NO_CHANGE 102
static const struct got_error {
int code;
@@ -232,6 +233,7 @@ static const struct got_error {
{ GOT_ERR_COMMIT_BRANCH, "will not commit to a branch outside the "
"\"refs/heads/\" reference namespace" },
{ GOT_ERR_FILE_STAGED, "file is staged" },
+ { GOT_ERR_STAGE_NO_CHANGE, "no changes to stage" },
};
/*
diff --git a/lib/worktree.c b/lib/worktree.c
index 08c378a..67da6f9 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -4924,20 +4924,19 @@ stage_path(const char *relpath, const char *ondisk_path,
{
const struct got_error *err = NULL;
struct got_fileindex_entry *ie;
- unsigned char status;
+ unsigned char status, staged_status;
struct stat sb;
struct got_object_id blob_id, *staged_blob_id = NULL;
uint32_t stage;
ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath));
- if (ie == NULL) {
- err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
- goto done;
- }
+ if (ie == NULL)
+ return got_error_path(relpath, GOT_ERR_FILE_STATUS);
err = get_file_status(&status, &sb, ie, ondisk_path, repo);
if (err)
- goto done;
+ return err;
+ staged_status = get_staged_status(ie);
switch (status) {
case GOT_STATUS_ADD:
@@ -4949,7 +4948,7 @@ stage_path(const char *relpath, const char *ondisk_path,
memcpy(&blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
memcpy(ie->staged_blob_sha1, staged_blob_id->sha1,
SHA1_DIGEST_LENGTH);
- if (status == GOT_STATUS_ADD)
+ if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
stage = GOT_FILEIDX_STAGE_ADD;
else
stage = GOT_FILEIDX_STAGE_MODIFY;
@@ -4959,11 +4958,16 @@ stage_path(const char *relpath, const char *ondisk_path,
staged_blob_id, NULL);
break;
case GOT_STATUS_DELETE:
+ if (staged_status == GOT_STATUS_DELETE)
+ break;
stage = GOT_FILEIDX_STAGE_DELETE;
got_fileindex_entry_stage_set(ie, stage);
err = (*status_cb)(status_arg, GOT_STATUS_NO_CHANGE,
get_staged_status(ie), relpath, NULL, NULL, NULL);
break;
+ case GOT_STATUS_NO_CHANGE:
+ err = got_error_path(relpath, GOT_ERR_STAGE_NO_CHANGE);
+ break;
default:
err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
break;
diff --git a/regress/cmdline/stage.sh b/regress/cmdline/stage.sh
index 8cd9094..9eee795 100755
--- a/regress/cmdline/stage.sh
+++ b/regress/cmdline/stage.sh
@@ -44,6 +44,83 @@ function test_stage_basic {
test_done "$testroot" "$ret"
}
+function test_double_stage {
+ local testroot=`test_init double_stage`
+
+ 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 "got: alpha: no changes to stage" > $testroot/stderr.expected
+ (cd $testroot/wt && got stage alpha 2> $testroot/stderr)
+ 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
+
+ (cd $testroot/wt && got stage beta > $testroot/stdout)
+ if [ "$ret" != "0" ]; then
+ echo "got stage command failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ 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 "got: foo: no changes to stage" > $testroot/stderr.expected
+ (cd $testroot/wt && got stage foo 2> $testroot/stderr)
+ 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
+
+ echo "modified file again" > $testroot/wt/alpha
+ echo "modified new file" > $testroot/wt/foo
+
+ echo ' M alpha' > $testroot/stdout.expected
+ echo ' A foo' >> $testroot/stdout.expected
+ (cd $testroot/wt && got stage alpha beta foo > $testroot/stdout)
+ 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 ' M alpha' > $testroot/stdout.expected
+ echo ' D beta' >> $testroot/stdout.expected
+ echo ' A foo' >> $testroot/stdout.expected
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
function test_stage_status {
local testroot=`test_init stage_status`
@@ -440,6 +517,7 @@ function test_stage_revert {
}
run_test test_stage_basic
+run_test test_double_stage
run_test test_stage_status
run_test test_stage_add_already_staged_file
run_test test_stage_rm_already_staged_file