diff: include oid length in deltas Now that `git_diff_delta` data can be produced by reading patch file data, which may have an abbreviated oid, allow consumers to know that the id is abbreviated.
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
diff --git a/include/git2/diff.h b/include/git2/diff.h
index f3bb337..065a786 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -264,10 +264,15 @@ typedef enum {
* link, a submodule commit id, or even a tree (although that only if you
* are tracking type changes or ignored/untracked directories).
*
- * The `oid` is the `git_oid` of the item. If the entry represents an
+ * The `id` is the `git_oid` of the item. If the entry represents an
* absent side of a diff (e.g. the `old_file` of a `GIT_DELTA_ADDED` delta),
* then the oid will be zeroes.
*
+ * The `id_abbrev` represents the known length of the `id` field, when
+ * converted to a hex string. It is generally `GIT_OID_HEXSZ`, unless this
+ * delta was created from reading a patch file, in which case it may be
+ * abbreviated to something reasonable, like 7 characters.
+ *
* `path` is the NUL-terminated path to the entry relative to the working
* directory of the repository.
*
@@ -280,6 +285,7 @@ typedef enum {
*/
typedef struct {
git_oid id;
+ int id_abbrev;
const char *path;
git_off_t size;
uint32_t flags;
diff --git a/src/diff.c b/src/diff.c
index 26c0b89..9c27511 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -151,11 +151,13 @@ static int diff_delta__from_one(
delta->old_file.size = entry->file_size;
delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS;
git_oid_cpy(&delta->old_file.id, &entry->id);
+ delta->old_file.id_abbrev = GIT_OID_HEXSZ;
} else /* ADDED, IGNORED, UNTRACKED */ {
delta->new_file.mode = entry->mode;
delta->new_file.size = entry->file_size;
delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS;
git_oid_cpy(&delta->new_file.id, &entry->id);
+ delta->new_file.id_abbrev = GIT_OID_HEXSZ;
}
delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
@@ -208,12 +210,14 @@ static int diff_delta__from_two(
delta->old_file.size = old_entry->file_size;
delta->old_file.mode = old_mode;
git_oid_cpy(&delta->old_file.id, old_id);
+ delta->old_file.id_abbrev = GIT_OID_HEXSZ;
delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID |
GIT_DIFF_FLAG_EXISTS;
}
if (!git_index_entry_is_conflict(new_entry)) {
git_oid_cpy(&delta->new_file.id, new_id);
+ delta->new_file.id_abbrev = GIT_OID_HEXSZ;
delta->new_file.size = new_entry->file_size;
delta->new_file.mode = new_mode;
delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS;
diff --git a/src/diff_file.c b/src/diff_file.c
index ecc34cf..8b945a5 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -149,12 +149,14 @@ int git_diff_file_content__init_from_src(
if (src->blob) {
fc->file->size = git_blob_rawsize(src->blob);
git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
+ fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = (size_t)fc->file->size;
fc->map.data = (char *)git_blob_rawcontent(src->blob);
} else {
fc->file->size = src->buflen;
git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB);
+ fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = src->buflen;
fc->map.data = (char *)src->buf;
diff --git a/src/diff_print.c b/src/diff_print.c
index 09bf77a..7c9af24 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -208,6 +208,7 @@ static int diff_print_one_raw(
{
diff_print_info *pi = data;
git_buf *out = pi->buf;
+ int id_abbrev;
char code = git_diff_status_char(delta->status);
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
@@ -218,6 +219,16 @@ static int diff_print_one_raw(
git_buf_clear(out);
+ id_abbrev = delta->old_file.mode ? delta->old_file.id_abbrev :
+ delta->new_file.id_abbrev;
+
+ if (pi->oid_strlen - 1 > id_abbrev) {
+ giterr_set(GITERR_PATCH,
+ "The patch input contains %d id characters (cannot print %d)",
+ id_abbrev, pi->oid_strlen);
+ return -1;
+ }
+
git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.id);
git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id);
@@ -252,6 +263,22 @@ static int diff_print_oid_range(
{
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
+ if (delta->old_file.mode &&
+ oid_strlen - 1 > delta->old_file.id_abbrev) {
+ giterr_set(GITERR_PATCH,
+ "The patch input contains %d id characters (cannot print %d)",
+ delta->old_file.id_abbrev, oid_strlen);
+ return -1;
+ }
+
+ if ((delta->new_file.mode &&
+ oid_strlen - 1 > delta->new_file.id_abbrev)) {
+ giterr_set(GITERR_PATCH,
+ "The patch input contains %d id characters (cannot print %d)",
+ delta->new_file.id_abbrev, oid_strlen);
+ return -1;
+ }
+
git_oid_tostr(start_oid, oid_strlen, &delta->old_file.id);
git_oid_tostr(end_oid, oid_strlen, &delta->new_file.id);
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 11e2693..323f8dc 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -197,15 +197,11 @@ static int parse_header_oid(
static int parse_header_git_index(
git_patch_parsed *patch, patch_parse_ctx *ctx)
{
- /*
- * TODO: we read the prefix provided in the diff into the delta's id
- * field, but do not mark is at an abbreviated id.
- */
- size_t oid_len, nid_len;
-
- if (parse_header_oid(&patch->base.delta->old_file.id, &oid_len, ctx) < 0 ||
+ if (parse_header_oid(&patch->base.delta->old_file.id,
+ &patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
parse_advance_expected(ctx, "..", 2) < 0 ||
- parse_header_oid(&patch->base.delta->new_file.id, &nid_len, ctx) < 0)
+ parse_header_oid(&patch->base.delta->new_file.id,
+ &patch->base.delta->new_file.id_abbrev, ctx) < 0)
return -1;
if (ctx->line_len > 0 && ctx->line[0] == ' ') {