commit - 3c575567b5033b0e9595bc208a5ce0b3f65627b6
commit + 5c1e53bc728ac0524d0471886bbc19f0b95e6c55
blob - b137227fb4832d96bf7b2366e8798731d9f68879
blob + 035a4e65253b48d82854f14665a3b2406de2bac6
--- got/got.1
+++ got/got.1
.It Cm rv
Short alias for
.Cm revert .
-.It Cm commit [ Fl m Ar message ] [ path ]
+.It Cm commit [ Fl m Ar message ] [ path ... ]
Create a new commit in the repository from local changes in a work tree
and use this commit as the new base commit for the work tree.
-If a
+If no
.Ar path
-is specified, only commit local changes at or within this path.
+is specified, commit all local changes in the work tree.
+Otherwise, commit local 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 - 2f130ca8f5f07aa7e457fc8cffa91f54ab350e37
blob + 41f97f73c98b213f120d4ad393a9b1a6316bec7a
--- got/got.c
+++ got/got.c
__dead static void
usage_commit(void)
{
- fprintf(stderr, "usage: %s commit [-m msg] [path]\n", getprogname());
+ fprintf(stderr, "usage: %s commit [-m msg] [path ...]\n",
+ getprogname());
exit(1);
}
const struct got_error *error = NULL;
struct got_worktree *worktree = NULL;
struct got_repository *repo = NULL;
- char *cwd = NULL, *path = NULL, *id_str = NULL;
+ char *cwd = NULL, *id_str = NULL;
struct got_object_id *id = NULL;
const char *logmsg = NULL;
const char *got_author = getenv("GOT_AUTHOR");
struct collect_commit_logmsg_arg cl_arg;
char *editor = NULL;
int ch, rebase_in_progress;
+ struct got_pathlist_head paths;
+
+ TAILQ_INIT(&paths);
while ((ch = getopt(argc, argv, "m:")) != -1) {
switch (ch) {
"unveil", NULL) == -1)
err(1, "pledge");
#endif
- if (argc == 1) {
- path = realpath(argv[0], NULL);
- if (path == NULL) {
- error = got_error_from_errno2("realpath", argv[0]);
- goto done;
- }
- got_path_strip_trailing_slashes(path);
- } else if (argc != 0)
- usage_commit();
-
if (got_author == NULL) {
/* TODO: Look current user up in password database */
error = got_error(GOT_ERR_COMMIT_NO_AUTHOR);
error = got_error(GOT_ERR_REBASING);
goto done;
}
+
+ error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
+ if (error)
+ goto done;
error = got_repo_open(&repo, got_worktree_get_repo_path(worktree));
if (error != NULL)
cl_arg.branch_name += 6;
cl_arg.repo_path = got_repo_get_path(repo);
cl_arg.logmsg_path = NULL;
- error = got_worktree_commit(&id, worktree, path, got_author, NULL,
+ error = got_worktree_commit(&id, worktree, &paths, got_author, NULL,
collect_commit_logmsg, &cl_arg, print_status, NULL, repo);
if (error) {
if (cl_arg.logmsg_path)
got_repo_close(repo);
if (worktree)
got_worktree_close(worktree);
- free(path);
free(cwd);
free(id_str);
free(editor);
blob - 105bebdfb14c771c8bb51d8ab106cf8540208344
blob + f4f431a41a6b1d33399a3974a26880899d231b80
--- include/got_worktree.h
+++ include/got_worktree.h
* current base commit.
* An author and a non-empty log message must be specified.
* The name of the committer is optional (may be NULL).
- * If an on-disk path is specified, only commit changes at or within this path.
*/
const struct got_error *got_worktree_commit(struct got_object_id **,
- struct got_worktree *, const char *, const char *, const char *,
- got_worktree_commit_msg_cb, void *,
+ struct got_worktree *, struct got_pathlist_head *, const char *,
+ const char *, got_worktree_commit_msg_cb, void *,
got_worktree_status_cb, void *, struct got_repository *);
/* Get the path of a commitable worktree item. */
blob - 1103157f40a2fc20de0d14bda891787ffdfeeaad
blob + 77022f311e883e0e67963e20af490976c2e29719
--- lib/worktree.c
+++ lib/worktree.c
commit_worktree(struct got_object_id **new_commit_id,
struct got_pathlist_head *commitable_paths,
struct got_object_id *head_commit_id, struct got_worktree *worktree,
- const char *ondisk_path, const char *author, const char *committer,
+ const char *author, const char *committer,
got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
got_worktree_status_cb status_cb, void *status_arg,
struct got_repository *repo)
}
return err;
}
+
+static const struct got_error *
+check_path_is_commitable(const char *path,
+ struct got_pathlist_head *commitable_paths)
+{
+ struct got_pathlist_entry *cpe = NULL;
+ size_t path_len = strlen(path);
+ TAILQ_FOREACH(cpe, commitable_paths, entry) {
+ struct got_commitable *ct = cpe->data;
+ const char *ct_path = ct->path;
+
+ while (ct_path[0] == '/')
+ ct_path++;
+
+ if (strcmp(path, ct_path) == 0 ||
+ got_path_is_child(ct_path, path, path_len))
+ break;
+ }
+
+ if (cpe == NULL)
+ return got_error_path(path, GOT_ERR_BAD_PATH);
+
+ return NULL;
+}
+
const struct got_error *
got_worktree_commit(struct got_object_id **new_commit_id,
- struct got_worktree *worktree, const char *ondisk_path,
+ struct got_worktree *worktree, struct got_pathlist_head *paths,
const char *author, const char *committer,
got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg,
got_worktree_status_cb status_cb, void *status_arg,
{
const struct got_error *err = NULL, *unlockerr = NULL, *sync_err;
struct got_fileindex *fileindex = NULL;
- char *fileindex_path = NULL, *relpath = NULL;
+ char *fileindex_path = NULL;
struct got_pathlist_head commitable_paths;
struct collect_commitables_arg cc_arg;
struct got_pathlist_entry *pe;
if (err)
goto done;
- if (ondisk_path) {
- if (strcmp(ondisk_path, worktree->root_path) == 0) {
- relpath = strdup("");
- if (relpath == NULL) {
- err = got_error_from_errno("strdup");
- goto done;
- }
- } else {
- err = got_path_skip_common_ancestor(&relpath,
- worktree->root_path, ondisk_path);
- if (err)
- return err;
- }
- }
-
err = open_fileindex(&fileindex, &fileindex_path, worktree);
if (err)
goto done;
cc_arg.commitable_paths = &commitable_paths;
cc_arg.worktree = worktree;
cc_arg.repo = repo;
- err = worktree_status(worktree, relpath ? relpath : "",
- fileindex, repo, collect_commitables, &cc_arg, NULL, NULL);
- if (err)
- goto done;
+ TAILQ_FOREACH(pe, paths, entry) {
+ err = worktree_status(worktree, pe->path, fileindex, repo,
+ collect_commitables, &cc_arg, NULL, NULL);
+ if (err)
+ goto done;
+ }
if (TAILQ_EMPTY(&commitable_paths)) {
err = got_error(GOT_ERR_COMMIT_NO_CHANGES);
goto done;
+ }
+
+ TAILQ_FOREACH(pe, paths, entry) {
+ err = check_path_is_commitable(pe->path, &commitable_paths);
+ if (err)
+ goto done;
}
TAILQ_FOREACH(pe, &commitable_paths, entry) {
}
err = commit_worktree(new_commit_id, &commitable_paths,
- head_commit_id, worktree, ondisk_path, author, committer,
+ head_commit_id, worktree, author, committer,
commit_msg_cb, commit_arg, status_cb, status_arg, repo);
if (err)
goto done;
if (fileindex)
got_fileindex_free(fileindex);
free(fileindex_path);
- free(relpath);
unlockerr = lock_worktree(worktree, LOCK_SH);
if (unlockerr && err == NULL)
err = unlockerr;
return got_error_from_errno("strdup");
err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id,
- worktree, NULL, got_object_commit_get_author(orig_commit),
+ worktree, got_object_commit_get_author(orig_commit),
got_object_commit_get_committer(orig_commit),
collect_rebase_commit_msg, logmsg, rebase_status, NULL, repo);
if (err)
blob - a8ec799b172f52f573b64c7d8fb59eadb12ffc58
blob + 579f23ddfca6faf4a1e9709eecf9394ab27b2f18
--- regress/cmdline/commit.sh
+++ regress/cmdline/commit.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_commit_selected_paths {
+ local testroot=`test_init commit_selected_paths`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha" > $testroot/wt/alpha
+ echo "modified delta" > $testroot/wt/gamma/delta
+ echo "modified zeta" > $testroot/wt/epsilon/zeta
+ (cd $testroot/wt && got rm beta >/dev/null)
+ echo "new file" > $testroot/wt/new
+ (cd $testroot/wt && got add new >/dev/null)
+ (cd $testroot/wt && got commit -m 'many paths' nonexistent alpha \
+ > $testroot/stdout 2> $testroot/stderr)
+ ret="$?"
+ if [ "$ret" == "0" ]; then
+ echo "commit succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ echo "got: nonexistent: bad path" > $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
+
+ (cd $testroot/wt && got commit -m 'many paths' \
+ beta new gamma > $testroot/stdout)
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo "A new" > $testroot/stdout.expected
+ echo "D beta" >> $testroot/stdout.expected
+ echo "M gamma/delta" >> $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"
+}
+
run_test test_commit_basic
run_test test_commit_new_subdir
run_test test_commit_subdir
run_test test_commit_added_and_modified_in_same_dir
run_test test_commit_path_prefix
run_test test_commit_dir_path
+run_test test_commit_selected_paths