add support for tag objects to 'got diff'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
diff --git a/got/got.1 b/got/got.1
index d79284e..107ba1a 100644
--- a/got/got.1
+++ b/got/got.1
@@ -332,8 +332,9 @@ If a
.Ar path
is specified, only show changes within this path.
.Pp
-If two arguments are provided, treat each argument as a reference,
-or an object ID SHA1 hash, and display differences between these objects.
+If two arguments are provided, treat each argument as a reference, a tag
+name, or an object ID SHA1 hash, and display differences between the
+corresponding objects.
Both objects must be of the same type (blobs, trees, or commits).
An abbreviated hash argument will be expanded to a full SHA1 hash
automatically, provided the abbreviation is unique.
diff --git a/got/got.c b/got/got.c
index 6303aab..02fe06d 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1858,11 +1858,25 @@ match_object_id(struct got_object_id **id, char **label,
const char *id_str, int obj_type, struct got_repository *repo)
{
const struct got_error *err;
+ struct got_tag_object *tag;
struct got_reference *ref = NULL;
*id = NULL;
*label = NULL;
+ err = got_repo_object_match_tag(&tag, id_str, GOT_OBJ_TYPE_ANY, repo);
+ if (err == NULL) {
+ *id = got_object_id_dup(got_object_tag_get_object_id(tag));
+ if (*id == NULL)
+ err = got_error_from_errno("got_object_id_dup");
+ if (asprintf(label, "refs/tags/%s",
+ strdup(got_object_tag_get_name(tag))) == -1)
+ err = got_error_from_errno("asprintf");
+ got_object_tag_close(tag);
+ return err;
+ } else if (err->code != GOT_ERR_NO_OBJ)
+ return err;
+
err = got_repo_match_object_id_prefix(id, id_str, obj_type, repo);
if (err) {
if (err->code != GOT_ERR_BAD_OBJ_ID_STR)
diff --git a/include/got_object.h b/include/got_object.h
index 5e46d49..505fd64 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -221,6 +221,9 @@ const struct got_error *got_object_open_as_tag(struct got_tag_object **,
/* Dispose of a tag object. */
void got_object_tag_close(struct got_tag_object *);
+/* Get the name of a tag. */
+const char *got_object_tag_get_name(struct got_tag_object *);
+
/* Get type of the object a tag points to. */
int got_object_tag_get_object_type(struct got_tag_object *);
diff --git a/lib/object.c b/lib/object.c
index d247b09..42e0035 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -1356,6 +1356,12 @@ got_object_tag_open(struct got_tag_object **tag,
return open_tag(tag, repo, got_object_get_id(obj), 1);
}
+const char *
+got_object_tag_get_name(struct got_tag_object *tag)
+{
+ return tag->tag;
+}
+
int
got_object_tag_get_object_type(struct got_tag_object *tag)
{
diff --git a/lib/repository.c b/lib/repository.c
index 60e8e27..2937089 100644
--- a/lib/repository.c
+++ b/lib/repository.c
@@ -1147,7 +1147,8 @@ got_repo_object_match_tag(struct got_tag_object **tag, const char *name,
free(tag_id);
if (err)
break;
- if (got_object_tag_get_object_type(*tag) == obj_type)
+ if (obj_type == GOT_OBJ_TYPE_ANY ||
+ got_object_tag_get_object_type(*tag) == obj_type)
break;
got_object_tag_close(*tag);
*tag = NULL;
diff --git a/regress/cmdline/diff.sh b/regress/cmdline/diff.sh
index 9193624..e7cea61 100755
--- a/regress/cmdline/diff.sh
+++ b/regress/cmdline/diff.sh
@@ -136,5 +136,66 @@ function test_diff_shows_conflict {
test_done "$testroot" "$ret"
}
+function test_diff_tag {
+ local testroot=`test_init diff_tag`
+ local commit_id0=`git_show_head $testroot/repo`
+ local tag1=1.0.0
+ local tag2=2.0.0
+
+ echo "modified alpha" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "changed alpha"
+ local commit_id1=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git tag -m "test" $tag1)
+
+ echo "new file" > $testroot/repo/new
+ (cd $testroot/repo && git add new)
+ git_commit $testroot/repo -m "new file"
+ local commit_id2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git tag -m "test" $tag2)
+
+ echo "diff $commit_id0 refs/tags/$tag1" > $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id0 -i | grep 'alpha$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -i | grep 'alpha$' | cut -d' ' -f 1 \
+ >> $testroot/stdout.expected
+ echo '--- alpha' >> $testroot/stdout.expected
+ echo '+++ alpha' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-alpha' >> $testroot/stdout.expected
+ echo '+modified alpha' >> $testroot/stdout.expected
+
+ got diff -r $testroot/repo $commit_id0 $tag1 > $testroot/stdout
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "diff refs/tags/$tag1 refs/tags/$tag2" > $testroot/stdout.expected
+ echo "blob - /dev/null" >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -i -c $commit_id2 | grep 'new$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo '--- /dev/null' >> $testroot/stdout.expected
+ echo '+++ new' >> $testroot/stdout.expected
+ echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected
+ echo '+new file' >> $testroot/stdout.expected
+
+ got diff -r $testroot/repo $tag1 $tag2 > $testroot/stdout
+ 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_diff_basic
run_test test_diff_shows_conflict
+run_test test_diff_tag