commit - 14e5d4dcac6e70e8ce1dc7434f4e4f5aa6dbf963
commit + b72f483a5d3d0699d6ff221cd44f8853eded0a32
blob - f755ddbe785f844e0f4a12a7a9a92106f64fdd5f
blob + 6c2d08f4242ad98d6f9d4ce5c88fb3a806671493
--- got/got.1
+++ got/got.1
.Nm
work tree, use the repository path associated with this work tree.
.El
-.It Cm diff [ Fl C Ar number ] [ Ar repository-path ] Ar object1 Ar object2
-Display the differences between two objects in the repository.
-Each
+.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.
Both objects must be of the same type (blobs, trees, or commits).
-If the
-.Ar repository path
-is omitted, use the current working directory.
.Pp
The options for
.Cm got diff
.It Fl C Ar number
Set the number of context lines shown in the diff.
By default, 3 lines of context are shown.
+.It Fl r Ar repository-path
+Use the repository at the specified path.
+If not specified, assume the repository is located at or above the current
+working directory.
+If this directory is a
+.Nm
+work tree, use the repository path associated with this work tree.
.El
.It Cm blame [ Fl c Ar commit ] [ Fl r Ar repository-path ] Ar path
Display line-by-line history of a file at the specified path.
blob - d7e55d3b7bbc5195d9c895b68af79a5dd25b7e1e
blob + 096c8f7fac1d8b3fd9d1ea2bc25096b07b9ee4ae
--- got/got.c
+++ got/got.c
__dead static void
usage_diff(void)
{
- fprintf(stderr, "usage: %s diff [-C number] [repository-path] "
- "object1 object2\n", getprogname());
+ fprintf(stderr, "usage: %s diff [-C number] [-r repository-path] "
+ "[object1 object2]\n", getprogname());
exit(1);
}
+struct print_diff_arg {
+ struct got_repository *repo;
+ struct got_worktree *worktree;
+ int diff_context;
+};
+
static const struct got_error *
+print_diff(void *arg, unsigned char status, const char *path,
+ struct got_object_id *id)
+{
+ struct print_diff_arg *a = arg;
+ const struct got_error *err = NULL;
+ struct got_blob_object *blob1 = NULL;
+ FILE *f2 = NULL;
+ char *abspath = NULL;
+ struct stat sb;
+
+ if (status != GOT_STATUS_MODIFIY)
+ return NULL;
+
+ err = got_object_open_as_blob(&blob1, a->repo, id, 8192);
+ if (err)
+ goto done;
+
+ if (asprintf(&abspath, "%s/%s",
+ got_worktree_get_root_path(a->worktree), path) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ f2 = fopen(abspath, "r");
+ if (f2 == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ if (lstat(abspath, &sb) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = got_diff_blob_file(blob1, f2, sb.st_size, path, a->diff_context,
+ stdout);
+done:
+ if (blob1)
+ got_object_blob_close(blob1);
+ if (f2)
+ fclose(f2);
+ free(abspath);
+ return err;
+}
+
+static const struct got_error *
cmd_diff(int argc, char *argv[])
{
const struct got_error *error;
struct got_repository *repo = NULL;
- char *repo_path = NULL;
+ struct got_worktree *worktree = NULL;
+ char *cwd = NULL, *repo_path = NULL;
struct got_object_id *id1 = NULL, *id2 = NULL;
char *id_str1 = NULL, *id_str2 = NULL;
int type1, type2;
err(1, "pledge");
#endif
- while ((ch = getopt(argc, argv, "C:")) != -1) {
+ while ((ch = getopt(argc, argv, "C:r:")) != -1) {
switch (ch) {
case 'C':
diff_context = strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr != NULL)
err(1, "-C option %s", errstr);
break;
+ case 'r':
+ repo_path = realpath(optarg, NULL);
+ if (repo_path == NULL)
+ err(1, "-r option");
+ break;
default:
usage();
/* NOTREACHED */
argc -= optind;
argv += optind;
+ cwd = getcwd(NULL, 0);
+ if (cwd == NULL) {
+ error = got_error_from_errno();
+ goto done;
+ }
if (argc == 0) {
- usage_diff(); /* TODO show local worktree changes */
- } else if (argc == 2) {
- repo_path = getcwd(NULL, 0);
+ 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();
+ } else if (argc == 2) {
id_str1 = argv[0];
id_str2 = argv[1];
- } else if (argc == 3) {
- repo_path = realpath(argv[0], NULL);
- if (repo_path == NULL)
- return got_error_from_errno();
- id_str1 = argv[1];
- id_str2 = argv[2];
} else
usage_diff();
- error = apply_unveil(repo_path, NULL);
+ if (repo_path == NULL) {
+ repo_path = getcwd(NULL, 0);
+ if (repo_path == NULL)
+ return got_error_from_errno();
+ }
+
+ error = apply_unveil(repo_path,
+ worktree ? got_worktree_get_root_path(worktree) : NULL);
if (error)
goto done;
if (error != NULL)
goto done;
+ if (worktree) {
+ struct print_diff_arg arg;
+ char *id_str;
+ error = got_object_id_str(&id_str,
+ got_worktree_get_base_commit_id(worktree));
+ if (error)
+ goto done;
+ arg.repo = repo;
+ arg.worktree = worktree;
+ arg.diff_context = diff_context;
+
+ printf("diff %s %s\n", id_str,
+ got_worktree_get_root_path(worktree));
+ error = got_worktree_status(worktree, repo, print_diff,
+ &arg, check_cancelled, NULL);
+ free(id_str);
+ goto done;
+ }
+
error = got_object_resolve_id_str(&id1, repo, id_str1);
if (error)
goto done;
done:
free(id1);
free(id2);
+ if (worktree)
+ got_worktree_close(worktree);
if (repo) {
const struct got_error *repo_error;
repo_error = got_repo_close(repo);
exit(1);
}
-static void
-print_status(void *arg, unsigned char status, const char *path)
+static const struct got_error *
+print_status(void *arg, unsigned char status, const char *path,
+ struct got_object_id *id)
{
printf("%c %s\n", status, path);
+ return NULL;
}
static const struct got_error *
blob - 01e0ac643704c52d2defe4e6e2bffdc0b8b5f8e4
blob + f80b6b9455be8bea47ca7815749d16720a267a51
--- include/got_diff.h
+++ include/got_diff.h
struct got_blob_object *, const char *, const char *, int, FILE *);
/*
+ * Compute the differences between a blob and a file and write unified diff
+ * text to the provided output file. The file's size must be provided, as
+ * well as a const char * diff header label which identifies the file.
+ * The number of context lines to show in the diff must be specified as well.
+ */
+const struct got_error *
+got_diff_blob_file(struct got_blob_object *, FILE *, size_t, const char *, int,
+ FILE *);
+
+/*
* Compute the differences between two trees and write unified diff text
* to the provided output FILE. Two const char * diff header labels may
* be provided which will be used to identify each blob in the diff output.
blob - 768ca6a234213e1f696abed31c0a4266f2e2e612
blob + 7f9026a9b8d5c96a24479753a750d7e3d7ab7eec
--- include/got_worktree.h
+++ include/got_worktree.h
/*
* Get the current base commit ID of a worktree.
*/
-const struct got_object_id *got_worktree_get_base_commit_id(struct got_worktree *);
+struct got_object_id *got_worktree_get_base_commit_id(struct got_worktree *);
/*
* Set the base commit Id of a worktree.
got_worktree_cancel_cb, void *);
/* A callback function which is invoked to report a path's status. */
-typedef void (*got_worktree_status_cb)(void *, unsigned char, const char *);
+typedef const struct got_error *(*got_worktree_status_cb)(void *,
+ unsigned char, const char *, struct got_object_id *);
/*
* Report the status of paths in the work tree.
blob - c89351f48f0b6b7aad4de60bfc866f18b5f6fd63
blob + a3da580ba00997c724ca5eb3cd2126aab7442ebd
--- lib/diff.c
+++ lib/diff.c
}
const struct got_error *
+got_diff_blob_file(struct got_blob_object *blob1, FILE *f2, size_t size2,
+ const char *label2, int diff_context, FILE *outfile)
+{
+ struct got_diff_state ds;
+ struct got_diff_args args;
+ const struct got_error *err = NULL;
+ FILE *f1 = NULL;
+ char hex1[SHA1_DIGEST_STRING_LENGTH];
+ char *idstr1 = NULL;
+ size_t size1;
+ int res, flags = 0;
+
+ size1 = 0;
+ if (blob1) {
+ f1 = got_opentemp();
+ if (f1 == NULL)
+ return got_error_from_errno();
+ idstr1 = got_object_blob_id_str(blob1, hex1, sizeof(hex1));
+ err = got_object_blob_dump_to_file(&size1, NULL, f1, blob1);
+ if (err)
+ goto done;
+ } else {
+ flags |= D_EMPTY1;
+ idstr1 = "/dev/null";
+ }
+
+ if (f2 == NULL)
+ flags |= D_EMPTY2;
+
+ memset(&ds, 0, sizeof(ds));
+ /* XXX should stat buffers be passed in args instead of ds? */
+ ds.stb1.st_mode = S_IFREG;
+ if (blob1)
+ ds.stb1.st_size = size1;
+ ds.stb1.st_mtime = 0; /* XXX */
+
+ ds.stb2.st_mode = S_IFREG;
+ ds.stb2.st_size = size2;
+ ds.stb2.st_mtime = 0; /* XXX */
+
+ memset(&args, 0, sizeof(args));
+ args.diff_format = D_UNIFIED;
+ args.label[0] = label2;
+ args.label[1] = label2;
+ args.diff_context = diff_context;
+ flags |= D_PROTOTYPE;
+
+ fprintf(outfile, "blob - %s\n", idstr1);
+ fprintf(outfile, "file + %s\n", label2);
+ err = got_diffreg(&res, f1, f2, flags, &args, &ds, outfile, NULL);
+done:
+ if (f1)
+ fclose(f1);
+ return err;
+}
+
+const struct got_error *
got_diff_blob_lines_changed(struct got_diff_changes **changes,
struct got_blob_object *blob1, struct got_blob_object *blob2)
{
blob - 708cf625a91485cd69e6b44a4ed2699c28850ec7
blob + c0ccc0d1604c7cfb8c922ce2a76a686a2443fc8d
--- lib/worktree.c
+++ lib/worktree.c
return got_ref_dup(worktree->head_ref);
}
-const struct got_object_id *
+struct got_object_id *
got_worktree_get_base_commit_id(struct got_worktree *worktree)
{
return worktree->base_commit_id;
}
err = get_file_status(&status, ie, abspath, a->repo);
- if (err == NULL && status != GOT_STATUS_NO_CHANGE)
- (*a->status_cb)(a->status_arg, status, ie->path);
+ 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);
+ }
free(abspath);
return err;
}
status_old(void *arg, struct got_fileindex_entry *ie, const char *parent_path)
{
struct diff_dir_cb_arg *a = arg;
- (*a->status_cb)(a->status_arg, GOT_STATUS_MISSING, ie->path);
- return NULL;
+ struct got_object_id id;
+ memcpy(id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
+ return (*a->status_cb)(a->status_arg, GOT_STATUS_MISSING, ie->path,
+ &id);
}
static const struct got_error *
status_new(void *arg, struct dirent *de, const char *parent_path)
{
+ const struct got_error *err = NULL;
struct diff_dir_cb_arg *a = arg;
char *path = NULL;
path = de->d_name;
}
- (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED, path);
+ err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED, path,
+ NULL);
if (parent_path[0])
free(path);
- return NULL;
+ return err;
}
const struct got_error *