commit - 13ff9e901c193017bf37229e261588b7bdbfe446
commit + 927df6b74a3358d1eaa0f2482cac2204a4f8f9fa
blob - 8a6407f100352d662d8260e1d3fcb69ddadc5a8f
blob + 5d11ec962e2aa555e428742810acdc50377403a6
--- got/got.1
+++ got/got.1
.Ar commit .
The expected argument is a SHA1 hash which corresponds to a commit object.
.El
-.It Cm status [ Ar worktree-path ]
+.It Cm status [ Ar path ]
Show the current modification status of files in a worktree,
using the following status codes:
.Bl -column YXZ description
.Nm
.El
.Pp
-If the
-.Ar work tree path
-is omitted, use the current working directory.
+If a
+.Ar path
+is specified, only show modifications within this path.
.It Cm log [ Fl c Ar commit ] [ Fl C Ar number ] [ Fl f ] [ Fl l Ar N ] [ Fl p ] [ Fl r Ar repository-path ] [ path ]
Display history of a repository.
If a
.Nm
work tree, use the repository path associated with this work tree.
.El
-.It Cm diff [ Fl C Ar number ] [ Fl r Ar repository-path ] [ Ar object1 Ar object2 ]
-Display differences between blobs in the repository and files in the
-work tree, or between two specified objects in a repository.
-If specified, each
-.Ar object
-argument is a SHA1 hash which corresponds to the object.
+.It Cm diff [ Fl C Ar number ] [ Fl r Ar repository-path ] [ Ar object1 Ar object2 | Ar path ]
+When invoked within a work tree with less than two arguments, display
+uncommitted changes in the work tree.
+If a
+.Ar path
+is specified, only show changes within this path.
+.Pp
+If two arguments are provided, treat each argument as a SHA1 hash which
+corresponds to an object in the repository, and display differences
+between these objects.
Both objects must be of the same type (blobs, trees, or commits).
.Pp
The options for
blob - 38251537f753faed2f94818ddb4bd42c5780eb6d
blob + ca784f2d06a5b67919ef72127efe1ce8215efb01
--- got/got.c
+++ got/got.c
usage_diff(void)
{
fprintf(stderr, "usage: %s diff [-C number] [-r repository-path] "
- "[object1 object2]\n", getprogname());
+ "[object1 object2 | path]\n", getprogname());
exit(1);
}
if (f2)
fclose(f2);
free(abspath);
+ return err;
+}
+
+static const struct got_error *
+get_status_path(char **status_path, struct got_worktree *worktree,
+ const char *arg)
+{
+ const struct got_error *err = NULL;
+ char *resolved, *path = NULL;
+ size_t len;
+
+ *status_path = NULL;
+
+ resolved = realpath(arg, NULL);
+ if (resolved == NULL)
+ return got_error_from_errno();
+
+ if (strncmp(got_worktree_get_root_path(worktree), resolved,
+ strlen(got_worktree_get_root_path(worktree)))) {
+ err = got_error(GOT_ERR_BAD_PATH);
+ goto done;
+ }
+
+ path = strdup(resolved + strlen(got_worktree_get_root_path(worktree)));
+ if (path == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ /* XXX status walk can't deal with trailing slash! */
+ len = strlen(path);
+ while (path[len - 1] == '/') {
+ path[len - 1] = '\0';
+ len--;
+ }
+done:
+ free(resolved);
+ if (err == NULL)
+ *status_path = path;
+ else
+ free(path);
return err;
}
int type1, type2;
int diff_context = 3, ch;
const char *errstr;
+ char *path = NULL;
#ifndef PROFILE
if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
error = got_error_from_errno();
goto done;
}
- if (argc == 0) {
+ error = got_worktree_open(&worktree, cwd);
+ if (error && error->code != GOT_ERR_NOT_WORKTREE)
+ goto done;
+ if (argc <= 1) {
+ if (worktree == NULL) {
+ error = got_error(GOT_ERR_NOT_WORKTREE);
+ goto done;
+ }
if (repo_path)
errx(1,
"-r option can't be used when diffing a work tree");
- error = got_worktree_open(&worktree, cwd);
- if (error)
- goto done;
repo_path = strdup(got_worktree_get_repo_path(worktree));
- if (repo_path == NULL)
- return got_error_from_errno();
+ if (repo_path == NULL) {
+ error = got_error_from_errno();
+ goto done;
+ }
+ if (argc == 1) {
+ error = get_status_path(&path, worktree, argv[0]);
+ if (error)
+ goto done;
+ } else {
+ path = strdup("");
+ if (path == NULL) {
+ error = got_error_from_errno();
+ goto done;
+ }
+ }
} else if (argc == 2) {
id_str1 = argv[0];
id_str2 = argv[1];
arg.id_str = id_str;
arg.header_shown = 0;
- error = got_worktree_status(worktree, repo, print_diff,
+ error = got_worktree_status(worktree, path, repo, print_diff,
&arg, check_cancelled, NULL);
free(id_str);
goto done;
done:
free(id1);
free(id2);
+ free(path);
if (worktree)
got_worktree_close(worktree);
if (repo) {
__dead static void
usage_status(void)
{
- fprintf(stderr, "usage: %s status [worktree-path]\n", getprogname());
+ fprintf(stderr, "usage: %s status [path]\n", getprogname());
exit(1);
}
const struct got_error *error = NULL;
struct got_repository *repo = NULL;
struct got_worktree *worktree = NULL;
- char *worktree_path = NULL;
+ char *cwd = NULL, *path = NULL;
int ch;
while ((ch = getopt(argc, argv, "")) != -1) {
NULL) == -1)
err(1, "pledge");
#endif
+ cwd = getcwd(NULL, 0);
+ if (cwd == NULL) {
+ error = got_error_from_errno();
+ goto done;
+ }
+
+ error = got_worktree_open(&worktree, cwd);
+ if (error != NULL)
+ goto done;
+
if (argc == 0) {
- worktree_path = getcwd(NULL, 0);
- if (worktree_path == NULL) {
+ path = strdup("");
+ if (path == NULL) {
error = got_error_from_errno();
goto done;
}
} else if (argc == 1) {
- worktree_path = realpath(argv[0], NULL);
- if (worktree_path == NULL) {
- error = got_error_from_errno();
+ error = get_status_path(&path, worktree, argv[0]);
+ if (error)
goto done;
- }
} else
usage_status();
- error = got_worktree_open(&worktree, worktree_path);
- if (error != NULL)
- goto done;
-
error = got_repo_open(&repo, got_worktree_get_repo_path(worktree));
if (error != NULL)
goto done;
if (error)
goto done;
- error = got_worktree_status(worktree, repo, print_status, NULL,
+ error = got_worktree_status(worktree, path, repo, print_status, NULL,
check_cancelled, NULL);
done:
- free(worktree_path);
+ free(cwd);
+ free(path);
return error;
}
blob - c28e21835670de5ae86292d65d24e0bf7139fada
blob + 3961b6d7873af2a2c046fb30c1497f452d1136f5
--- include/got_worktree.h
+++ include/got_worktree.h
* a path, and a corresponding status code.
*/
const struct got_error *
-got_worktree_status(struct got_worktree *, struct got_repository *,
- got_worktree_status_cb, void *, got_worktree_cancel_cb cancel_cb, void *);
+got_worktree_status(struct got_worktree *, const char *,
+ struct got_repository *, got_worktree_status_cb, void *,
+ got_worktree_cancel_cb cancel_cb, void *);
blob - 5d501fc0867dd9283c8d954134123191b1548362
blob + 9513f3056f3375a16cb9ccca9ebf8a3dfe294dff
--- lib/fileindex.c
+++ lib/fileindex.c
const struct got_error *
got_fileindex_diff_dir(struct got_fileindex *fileindex, DIR *rootdir,
- const char *rootpath, struct got_repository *repo,
+ const char *rootpath, const char *path, struct got_repository *repo,
struct got_fileindex_diff_dir_cb *cb, void *cb_arg)
{
struct got_fileindex_entry *min;
min = RB_MIN(got_fileindex_tree, &fileindex->entries);
- return diff_fileindex_dir(fileindex, &min, rootdir, rootpath, "",
+ return diff_fileindex_dir(fileindex, &min, rootdir, rootpath, path,
repo, cb, cb_arg);
}
blob - bb4a77afda033364d37dcdc5dd281795429bad65
blob + aa91c6643eb06a9a52b12801b94593ca38102c5b
--- lib/got_lib_fileindex.h
+++ lib/got_lib_fileindex.h
got_fileindex_diff_dir_new_cb diff_new;
};
const struct got_error *got_fileindex_diff_dir(struct got_fileindex *, DIR *,
- const char *, struct got_repository *, struct got_fileindex_diff_dir_cb *,
- void *);
+ const char *, const char *, struct got_repository *,
+ struct got_fileindex_diff_dir_cb *, void *);
blob - 9a55298bbc84d3449a19d3cb40e0b87307690de7
blob + 949678e5c0659175b5f4de710c0d32db3121fbc7
--- lib/worktree.c
+++ lib/worktree.c
struct diff_dir_cb_arg {
struct got_fileindex *fileindex;
struct got_worktree *worktree;
+ const char *status_path;
+ size_t status_path_len;
struct got_repository *repo;
got_worktree_status_cb status_cb;
void *status_arg;
};
static const struct got_error *
+report_file_status(struct got_fileindex_entry *ie, const char *abspath,
+ got_worktree_status_cb status_cb, void *status_arg,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ unsigned char status = GOT_STATUS_NO_CHANGE;
+ struct stat sb;
+ struct got_object_id id;
+
+ err = get_file_status(&status, &sb, ie, abspath, repo);
+ if (err == NULL && status != GOT_STATUS_NO_CHANGE) {
+ memcpy(id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
+ err = (*status_cb)(status_arg, status, ie->path, &id);
+ }
+ return err;
+}
+
+static const struct got_error *
status_old_new(void *arg, struct got_fileindex_entry *ie,
struct dirent *de, const char *parent_path)
{
const struct got_error *err = NULL;
struct diff_dir_cb_arg *a = arg;
char *abspath;
- unsigned char status = GOT_STATUS_NO_CHANGE;
- struct stat sb;
+ if (got_path_cmp(parent_path, a->status_path) != 0 &&
+ !got_path_is_child(parent_path, a->status_path, a->status_path_len))
+ return NULL;
+
if (parent_path[0]) {
if (asprintf(&abspath, "%s/%s/%s", a->worktree->root_path,
parent_path, de->d_name) == -1)
return got_error_from_errno();
}
- err = get_file_status(&status, &sb, ie, abspath, a->repo);
- if (err == NULL && status != GOT_STATUS_NO_CHANGE) {
- struct got_object_id id;
- memcpy(id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
- err = (*a->status_cb)(a->status_arg, status, ie->path, &id);
- }
+ err = report_file_status(ie, abspath, a->status_cb, a->status_arg,
+ a->repo);
free(abspath);
return err;
}
{
struct diff_dir_cb_arg *a = arg;
struct got_object_id id;
+
+ if (!got_path_is_child(parent_path, a->status_path, a->status_path_len))
+ return NULL;
+
memcpy(id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
return (*a->status_cb)(a->status_arg, GOT_STATUS_MISSING, ie->path,
&id);
if (de->d_type == DT_LNK)
return NULL;
+ if (!got_path_is_child(parent_path, a->status_path, a->status_path_len))
+ return NULL;
+
if (parent_path[0]) {
if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
return got_error_from_errno();
}
const struct got_error *
-got_worktree_status(struct got_worktree *worktree,
+got_worktree_status(struct got_worktree *worktree, const char *path,
struct got_repository *repo, got_worktree_status_cb status_cb,
void *status_arg, got_worktree_cancel_cb cancel_cb, void *cancel_arg)
{
FILE *index = NULL;
struct got_fileindex_diff_dir_cb fdiff_cb;
struct diff_dir_cb_arg arg;
+ char *ondisk_path = NULL;
fileindex = got_fileindex_alloc();
if (fileindex == NULL) {
goto done;
}
- workdir = opendir(worktree->root_path);
- if (workdir == NULL) {
+ if (asprintf(&ondisk_path, "%s%s%s",
+ worktree->root_path, path[0] ? "/" : "", path) == -1) {
err = got_error_from_errno();
goto done;
}
+ workdir = opendir(ondisk_path);
+ if (workdir == NULL) {
+ if (errno == ENOTDIR) {
+ struct got_fileindex_entry *ie;
+ ie = got_fileindex_entry_get(fileindex, path);
+ if (ie == NULL) {
+ err = got_error(GOT_ERR_BAD_PATH);
+ goto done;
+ }
+ err = report_file_status(ie, ondisk_path,
+ status_cb, status_arg, repo);
+ goto done;
+ } else {
+ err = got_error_from_errno();
+ goto done;
+ }
+ }
fdiff_cb.diff_old_new = status_old_new;
fdiff_cb.diff_old = status_old;
fdiff_cb.diff_new = status_new;
arg.fileindex = fileindex;
arg.worktree = worktree;
+ arg.status_path = path;
+ arg.status_path_len = strlen(path);
arg.repo = repo;
arg.status_cb = status_cb;
arg.status_arg = status_arg;
arg.cancel_cb = cancel_cb;
arg.cancel_arg = cancel_arg;
err = got_fileindex_diff_dir(fileindex, workdir, worktree->root_path,
- repo, &fdiff_cb, &arg);
+ path, repo, &fdiff_cb, &arg);
done:
if (workdir)
closedir(workdir);
+ free(ondisk_path);
free(fileindex_path);
got_fileindex_free(fileindex);
return err;