commit 44392932de0367a4f50fdeb8ecb541cda02a86f8 from: Stefan Sperling date: Sun Aug 25 22:13:01 2019 UTC make 'got log -p path' display patches for the specified path only commit - a4f89d488d527ac3e4234f22eca2ce92d5ab46a7 commit + 44392932de0367a4f50fdeb8ecb541cda02a86f8 blob - 977bfb4a54389e39ecc005b21511c2b6cd75e6ea blob + 3697535d7f7ebd36d8a374d195ebe42d1c658497 --- got/got.1 +++ got/got.1 @@ -324,6 +324,9 @@ The environment variable may be set to change this default value. .It Fl p Display the patch of modifications made in each commit. +If a +.Ar path +is specified, only show the patch of modifications at or within this path. .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 blob - c5f0c6c719d399e1d37f6808e6f8a453544be2bc blob + 178ad9f5321f4259fd91762efec539efe3a0683c --- got/got.c +++ got/got.c @@ -1317,54 +1317,144 @@ done: } static const struct got_error * -print_patch(struct got_commit_object *commit, struct got_object_id *id, - int diff_context, struct got_repository *repo) +diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2, + const char *path, int diff_context, struct got_repository *repo) { const struct got_error *err = NULL; - struct got_tree_object *tree1 = NULL, *tree2; - struct got_object_qid *qid; - char *id_str1 = NULL, *id_str2; - struct got_diff_blob_output_unidiff_arg arg; + struct got_blob_object *blob1 = NULL, *blob2 = NULL; - err = got_object_open_as_tree(&tree2, repo, - got_object_commit_get_tree_id(commit)); - if (err) - return err; + if (blob_id1) { + err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192); + if (err) + goto done; + } - qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit)); - if (qid != NULL) { - struct got_commit_object *pcommit; + err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192); + if (err) + goto done; - err = got_object_open_as_commit(&pcommit, repo, qid->id); - if (err) - return err; - - err = got_object_open_as_tree(&tree1, repo, - got_object_commit_get_tree_id(pcommit)); - got_object_commit_close(pcommit); - if (err) - return err; - - err = got_object_id_str(&id_str1, qid->id); + while (path[0] == '/') + path++; + err = got_diff_blob(blob1, blob2, path, path, diff_context, + stdout); +done: + if (blob1) + got_object_blob_close(blob1); + got_object_blob_close(blob2); + return err; +} + +static const struct got_error * +diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2, + const char *path, int diff_context, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_tree_object *tree1 = NULL, *tree2 = NULL; + struct got_diff_blob_output_unidiff_arg arg; + + if (tree_id1) { + err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) - return err; + goto done; } - err = got_object_id_str(&id_str2, id); + err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; - printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); arg.diff_context = diff_context; arg.outfile = stdout; - err = got_diff_tree(tree1, tree2, "", "", repo, + while (path[0] == '/') + path++; + err = got_diff_tree(tree1, tree2, path, path, repo, got_diff_blob_output_unidiff, &arg, 1); done: if (tree1) got_object_tree_close(tree1); got_object_tree_close(tree2); + return err; +} + +static const struct got_error * +print_patch(struct got_commit_object *commit, struct got_object_id *id, + const char *path, int diff_context, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_commit_object *pcommit = NULL; + char *id_str1 = NULL, *id_str2 = NULL; + struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL; + struct got_object_qid *qid; + + qid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit)); + if (qid != NULL) { + err = got_object_open_as_commit(&pcommit, repo, + qid->id); + if (err) + return err; + } + + if (path && path[0] != '\0') { + int obj_type; + err = got_object_id_by_path(&obj_id2, repo, id, path); + if (err) + goto done; + err = got_object_id_str(&id_str2, obj_id2); + if (err) { + free(obj_id2); + goto done; + } + if (pcommit) { + err = got_object_id_by_path(&obj_id1, repo, + qid->id, path); + if (err) { + free(obj_id2); + goto done; + } + err = got_object_id_str(&id_str1, obj_id1); + if (err) { + free(obj_id2); + goto done; + } + } + err = got_object_get_type(&obj_type, repo, obj_id2); + if (err) { + free(obj_id2); + goto done; + } + printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); + switch (obj_type) { + case GOT_OBJ_TYPE_BLOB: + err = diff_blobs(obj_id1, obj_id2, path, diff_context, + repo); + break; + case GOT_OBJ_TYPE_TREE: + err = diff_trees(obj_id1, obj_id2, path, diff_context, + repo); + break; + default: + err = got_error(GOT_ERR_OBJ_TYPE); + break; + } + free(obj_id1); + free(obj_id2); + } else { + obj_id2 = got_object_commit_get_tree_id(commit); + err = got_object_id_str(&id_str2, obj_id2); + if (err) + goto done; + obj_id1 = got_object_commit_get_tree_id(pcommit); + err = got_object_id_str(&id_str1, obj_id1); + if (err) + goto done; + printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); + err = diff_trees(obj_id1, obj_id2, "", diff_context, repo); + } + +done: free(id_str1); free(id_str2); + if (pcommit) + got_object_commit_close(pcommit); return err; } @@ -1390,8 +1480,8 @@ get_datestr(time_t *time, char *datebuf) static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, - struct got_repository *repo, int show_patch, int diff_context, - struct got_reflist_head *refs) + struct got_repository *repo, const char *path, int show_patch, + int diff_context, struct got_reflist_head *refs) { const struct got_error *err = NULL; char *id_str, *datestr, *logmsg0, *logmsg, *line; @@ -1490,7 +1580,7 @@ print_commit(struct got_commit_object *commit, struct free(logmsg0); if (show_patch) { - err = print_patch(commit, id, diff_context, repo); + err = print_patch(commit, id, path, diff_context, repo); if (err == 0) printf("\n"); } @@ -1544,8 +1634,8 @@ print_commits(struct got_object_id *root_id, struct go err = got_object_open_as_commit(&commit, repo, id); if (err) break; - err = print_commit(commit, id, repo, show_patch, diff_context, - refs); + err = print_commit(commit, id, repo, path, show_patch, + diff_context, refs); got_object_commit_close(commit); if (err || (limit && --limit == 0)) break; blob - 358a2e93309670de43d22afd7635bfd41fac137b blob + ce3cb343d8747812035937497cb86cab7192b220 --- regress/cmdline/import.sh +++ regress/cmdline/import.sh @@ -55,6 +55,8 @@ function test_import_basic { id_beta=`get_blob_id $testroot/repo "" beta` id_zeta=`get_blob_id $testroot/repo epsilon zeta` id_delta=`get_blob_id $testroot/repo gamma delta` + tree_id=`(cd $testroot/repo && got cat $head_commit | \ + grep ^tree | cut -d ' ' -f 2)` echo "-----------------------------------------------" \ > $testroot/stdout.expected @@ -63,7 +65,7 @@ function test_import_basic { echo " " >> $testroot/stdout.expected echo " init" >> $testroot/stdout.expected echo " " >> $testroot/stdout.expected - echo "diff /dev/null $head_commit" >> $testroot/stdout.expected + echo "diff /dev/null $tree_id" >> $testroot/stdout.expected echo "blob - /dev/null" >> $testroot/stdout.expected echo "blob + $id_alpha" >> $testroot/stdout.expected echo "--- /dev/null" >> $testroot/stdout.expected