commit 2db2652dc0454deeccc06ed928fca0fd063ef644 from: Stefan Sperling date: Wed Aug 07 16:25:46 2019 UTC make path arguments to 'got stage' optional commit - b353a198c5844a2e9b078ac654b6a61de00b5a13 commit + 2db2652dc0454deeccc06ed928fca0fd063ef644 blob - 9697e4dbb758aa0d21c5cd4e2a6cd17e2e20360c blob + 5376bbb308fc6bd0b12377dffc35db2446e62da5 --- got/got.1 +++ got/got.1 @@ -870,8 +870,12 @@ If this option is used, no further command-line argume .It Cm he Short alias for .Cm histedit . -.It Cm stage [ Fl l ] [ Fl p ] [ Fl F ] Ar file-path ... -Stage local changes at the specified paths for inclusion in the next commit. +.It Cm stage [ Fl l ] [ Fl p ] [ Fl F ] [ Ar path ... ] +Stage local changes for inclusion in the next commit. +If no +.Ar path +is specified, stage all changes in the work tree. +Otherwise, stage changes at or within the specified paths. Paths may be staged if they are added, modified, or deleted according to .Cm got status . .Pp @@ -967,6 +971,7 @@ back into non-staged status. If no .Ar path is specified, unstage all staged changes across the entire work tree. +Otherwise, unstage changes at or within the specified paths. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description blob - fefcde6d313e10e1fab631ab23cad7d8ef7aab19 blob + bf0e40f8851a802cad085d293c83bb577ed2775b --- got/got.c +++ got/got.c @@ -5160,7 +5160,7 @@ done: __dead static void usage_stage(void) { - fprintf(stderr, "usage: %s stage [-l] | [-p] [-F] file-path ...\n", + fprintf(stderr, "usage: %s stage [-l] | [-p] [-F] [file-path ...]\n", getprogname()); exit(1); } @@ -5327,8 +5327,8 @@ cmd_stage(int argc, char *argv[]) "unveil", NULL) == -1) err(1, "pledge"); #endif - if ((list_stage && pflag) || (!list_stage && argc < 1)) - usage_stage(); + if (list_stage && (pflag || patch_script_path)) + errx(1, "-l option cannot be used with other options"); if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); blob - 3bfbe160afb3d00eb393f76db0f5af2ee423f030 blob + 7de42bb2933ea1ece79a2ae3b05f4d3eec9aa4cc --- lib/worktree.c +++ lib/worktree.c @@ -5076,44 +5076,42 @@ done: return err; } -static const struct got_error * -check_stage_ok(const char *relpath, const char *ondisk_path, - struct got_object_id *head_commit_id, struct got_worktree *worktree, - struct got_fileindex *fileindex, struct got_repository *repo) +struct check_stage_ok_arg { + struct got_object_id *head_commit_id; + struct got_worktree *worktree; + struct got_fileindex *fileindex; + struct got_repository *repo; + int have_changes; +}; + +const struct got_error * +check_stage_ok(void *arg, unsigned char status, + unsigned char staged_status, const char *relpath, + struct got_object_id *blob_id, struct got_object_id *staged_blob_id, + struct got_object_id *commit_id) { + struct check_stage_ok_arg *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; - unsigned char status; - struct stat sb; - struct got_object_id blob_id, base_commit_id; - struct got_object_id *blob_idp = NULL, *base_commit_idp = NULL; + struct got_object_id base_commit_id; + struct got_object_id *base_commit_idp = NULL; char *in_repo_path = NULL, *p; - ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath)); + ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); - if (get_staged_status(ie) != GOT_STATUS_NO_CHANGE) - return NULL; - - if (asprintf(&in_repo_path, "%s%s%s", worktree->path_prefix, - got_path_is_root_dir(worktree->path_prefix) ? "" : "/", + if (asprintf(&in_repo_path, "%s%s%s", a->worktree->path_prefix, + got_path_is_root_dir(a->worktree->path_prefix) ? "" : "/", relpath) == -1) return got_error_from_errno("asprintf"); - if (got_fileindex_entry_has_blob(ie)) { - memcpy(blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH); - blob_idp = &blob_id; - } if (got_fileindex_entry_has_commit(ie)) { memcpy(base_commit_id.sha1, ie->commit_sha1, SHA1_DIGEST_LENGTH); base_commit_idp = &base_commit_id; } - err = get_file_status(&status, &sb, ie, ondisk_path, repo); - if (err) - goto done; if (status == GOT_STATUS_NO_CHANGE) { err = got_error_path(ie->path, GOT_ERR_STAGE_NO_CHANGE); goto done; @@ -5127,11 +5125,13 @@ check_stage_ok(const char *relpath, const char *ondisk goto done; } + a->have_changes = 1; + p = in_repo_path; while (p[0] == '/') p++; - err = check_out_of_date(p, status, GOT_STATUS_NO_CHANGE, - blob_idp, base_commit_idp, head_commit_id, repo, + err = check_out_of_date(p, status, staged_status, + blob_id, base_commit_idp, a->head_commit_id, a->repo, GOT_ERR_STAGE_OUT_OF_DATE); done: free(in_repo_path); @@ -5396,53 +5396,58 @@ done: return err; } -static const struct got_error * -stage_path(const char *relpath, const char *ondisk_path, - struct got_worktree *worktree, struct got_fileindex *fileindex, - struct got_repository *repo, - got_worktree_status_cb status_cb, void *status_arg, - got_worktree_patch_cb patch_cb, void *patch_arg) +struct stage_path_arg { + struct got_worktree *worktree; + struct got_fileindex *fileindex; + struct got_repository *repo; + got_worktree_status_cb status_cb; + void *status_arg; + got_worktree_patch_cb patch_cb; + void *patch_arg; +}; + +static const struct got_error * +stage_path(void *arg, unsigned char status, + unsigned char staged_status, const char *relpath, + struct got_object_id *blob_id, struct got_object_id *staged_blob_id, + struct got_object_id *commit_id) { + struct stage_path_arg *a = arg; const struct got_error *err = NULL; struct got_fileindex_entry *ie; - char *path_content = NULL; - unsigned char status, staged_status; - struct stat sb; - struct got_object_id blob_id, *staged_blob_id = NULL; + char *ondisk_path = NULL, *path_content = NULL; uint32_t stage; - ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath)); + ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) return got_error_path(relpath, GOT_ERR_FILE_STATUS); - err = get_file_status(&status, &sb, ie, ondisk_path, repo); - if (err) - return err; - staged_status = get_staged_status(ie); + if (asprintf(&ondisk_path, "%s/%s", a->worktree->root_path, + relpath)== -1) + return got_error_from_errno("asprintf"); switch (status) { case GOT_STATUS_ADD: case GOT_STATUS_MODIFY: - memcpy(&blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH); - if (patch_cb) { + if (a->patch_cb) { if (status == GOT_STATUS_ADD) { int choice = GOT_PATCH_CHOICE_NONE; - err = (*patch_cb)(&choice, patch_arg, status, - ie->path, NULL); + err = (*a->patch_cb)(&choice, a->patch_arg, + status, ie->path, NULL); if (err) break; if (choice != GOT_PATCH_CHOICE_YES) break; } else { err = create_staged_content(&path_content, - &blob_id, ondisk_path, ie->path, repo, - patch_cb, patch_arg); + blob_id, ondisk_path, ie->path, a->repo, + a->patch_cb, a->patch_arg); if (err || path_content == NULL) break; } } err = got_object_blob_create(&staged_blob_id, - path_content ? path_content : ondisk_path, repo); + path_content ? path_content : ondisk_path, a->repo); if (err) break; memcpy(ie->staged_blob_sha1, staged_blob_id->sha1, @@ -5452,18 +5457,18 @@ stage_path(const char *relpath, const char *ondisk_pat else stage = GOT_FILEIDX_STAGE_MODIFY; got_fileindex_entry_stage_set(ie, stage); - if (status_cb == NULL) + if (a->status_cb == NULL) break; - err = (*status_cb)(status_arg, GOT_STATUS_NO_CHANGE, - get_staged_status(ie), relpath, &blob_id, + err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE, + get_staged_status(ie), relpath, blob_id, staged_blob_id, NULL); break; case GOT_STATUS_DELETE: if (staged_status == GOT_STATUS_DELETE) break; - if (patch_cb) { + if (a->patch_cb) { int choice = GOT_PATCH_CHOICE_NONE; - err = (*patch_cb)(&choice, patch_arg, status, + err = (*a->patch_cb)(&choice, a->patch_arg, status, ie->path, NULL); if (err) break; @@ -5472,9 +5477,9 @@ stage_path(const char *relpath, const char *ondisk_pat } stage = GOT_FILEIDX_STAGE_DELETE; got_fileindex_entry_stage_set(ie, stage); - if (status_cb == NULL) + if (a->status_cb == NULL) break; - err = (*status_cb)(status_arg, GOT_STATUS_NO_CHANGE, + err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE, get_staged_status(ie), relpath, NULL, NULL, NULL); break; case GOT_STATUS_NO_CHANGE: @@ -5491,7 +5496,7 @@ stage_path(const char *relpath, const char *ondisk_pat if (path_content && unlink(path_content) == -1 && err == NULL) err = got_error_from_errno2("unlink", path_content); free(path_content); - free(staged_blob_id); + free(ondisk_path); return err; } @@ -5508,6 +5513,8 @@ got_worktree_stage(struct got_worktree *worktree, char *fileindex_path = NULL; struct got_reference *head_ref = NULL; struct got_object_id *head_commit_id = NULL; + struct check_stage_ok_arg oka; + struct stage_path_arg spa; err = lock_worktree(worktree, LOCK_EX); if (err) @@ -5525,29 +5532,34 @@ got_worktree_stage(struct got_worktree *worktree, goto done; /* Check pre-conditions before staging anything. */ + oka.head_commit_id = head_commit_id; + oka.worktree = worktree; + oka.fileindex = fileindex; + oka.repo = repo; + oka.have_changes = 0; TAILQ_FOREACH(pe, paths, entry) { - char *ondisk_path; - if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, - pe->path) == -1) - return got_error_from_errno("asprintf"); - err = check_stage_ok(pe->path, ondisk_path, - head_commit_id, worktree, fileindex, repo); - free(ondisk_path); + err = worktree_status(worktree, pe->path, fileindex, repo, + check_stage_ok, &oka, NULL, NULL); if (err) goto done; } + if (!oka.have_changes) { + err = got_error(GOT_ERR_STAGE_NO_CHANGE); + goto done; + } + spa.worktree = worktree; + spa.fileindex = fileindex; + spa.repo = repo; + spa.patch_cb = patch_cb; + spa.patch_arg = patch_arg; + spa.status_cb = status_cb; + spa.status_arg = status_arg; TAILQ_FOREACH(pe, paths, entry) { - char *ondisk_path; - if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, - pe->path) == -1) - return got_error_from_errno("asprintf"); - err = stage_path(pe->path, ondisk_path, - worktree, fileindex, repo, status_cb, status_arg, - patch_cb, patch_arg); - free(ondisk_path); + err = worktree_status(worktree, pe->path, fileindex, repo, + stage_path, &spa, NULL, NULL); if (err) - break; + goto done; } sync_err = sync_fileindex(fileindex, fileindex_path); blob - 7b8a5cf105fc8e4033ecdf70fa582d32a8962e93 blob + 03a13774080ceeaf4c89e1d00e6c88807d94baad --- regress/cmdline/stage.sh +++ regress/cmdline/stage.sh @@ -63,7 +63,7 @@ function test_stage_no_changes { return 1 fi - echo "got: alpha: no changes to stage" > $testroot/stderr.expected + echo "got: no changes to stage" > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret="$?" @@ -1552,10 +1552,10 @@ function test_stage_patch_quit { sed -i -e 's/^7$/b/' $testroot/wt/numbers sed -i -e 's/^16$/c/' $testroot/wt/numbers - # stage first hunk and quit + # stage first hunk and quit; and don't pass a path argument printf "y\nq\n" > $testroot/patchscript (cd $testroot/wt && got stage -F $testroot/patchscript -p \ - numbers > $testroot/stdout) + > $testroot/stdout) ret="$?" if [ "$ret" != "0" ]; then echo "got stage command failed unexpectedly" >&2