Skip to content

Commit 52fca06

Browse files
ebiedermgitster
authored andcommitted
object-names: support input of oids in any supported hash
Support short oids encoded in any algorithm, while ensuring enough of the oid is specified to disambiguate between all of the oids in the repository encoded in any algorithm. By default have the code continue to only accept oids specified in the storage hash algorithm of the repository, but when something is ambiguous display all of the possible oids from any accepted oid encoding. A new flag is added GET_OID_HASH_ANY that when supplied causes the code to accept oids specified in any hash algorithm, and to return the oids that were resolved. This implements the functionality that allows both SHA-1 and SHA-256 object names, from the "Object names on the command line" section of the hash function transition document. Care is taken in get_short_oid so that when the result is ambiguous the output remains the same if GIT_OID_HASH_ANY was not supplied. If GET_OID_HASH_ANY was supplied objects of any hash algorithm that match the prefix are displayed. This required updating repo_for_each_abbrev to give it a parameter so that it knows to look at all hash algorithms. Signed-off-by: "Eric W. Biederman" <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d50cbe4 commit 52fca06

File tree

4 files changed

+39
-13
lines changed

4 files changed

+39
-13
lines changed

builtin/rev-parse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
882882
continue;
883883
}
884884
if (skip_prefix(arg, "--disambiguate=", &arg)) {
885-
repo_for_each_abbrev(the_repository, arg,
885+
repo_for_each_abbrev(the_repository, arg, the_hash_algo,
886886
show_abbrev, NULL);
887887
continue;
888888
}

hash-ll.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct object_id {
145145
#define GET_OID_RECORD_PATH 0200
146146
#define GET_OID_ONLY_TO_DIE 04000
147147
#define GET_OID_REQUIRE_PATH 010000
148+
#define GET_OID_HASH_ANY 020000
148149

149150
#define GET_OID_DISAMBIGUATORS \
150151
(GET_OID_COMMIT | GET_OID_COMMITTISH | \

object-name.c

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "midx.h"
2626
#include "commit-reach.h"
2727
#include "date.h"
28+
#include "object-file-convert.h"
2829

2930
static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
3031

@@ -49,6 +50,7 @@ struct disambiguate_state {
4950

5051
static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
5152
{
53+
/* The hash algorithm of current has already been filtered */
5254
if (ds->always_call_fn) {
5355
ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
5456
return;
@@ -134,6 +136,8 @@ static void unique_in_midx(struct multi_pack_index *m,
134136
{
135137
uint32_t num, i, first = 0;
136138
const struct object_id *current = NULL;
139+
int len = ds->len > ds->repo->hash_algo->hexsz ?
140+
ds->repo->hash_algo->hexsz : ds->len;
137141
num = m->num_objects;
138142

139143
if (!num)
@@ -149,7 +153,7 @@ static void unique_in_midx(struct multi_pack_index *m,
149153
for (i = first; i < num && !ds->ambiguous; i++) {
150154
struct object_id oid;
151155
current = nth_midxed_object_oid(&oid, m, i);
152-
if (!match_hash(ds->len, ds->bin_pfx.hash, current->hash))
156+
if (!match_hash(len, ds->bin_pfx.hash, current->hash))
153157
break;
154158
update_candidates(ds, current);
155159
}
@@ -159,6 +163,8 @@ static void unique_in_pack(struct packed_git *p,
159163
struct disambiguate_state *ds)
160164
{
161165
uint32_t num, i, first = 0;
166+
int len = ds->len > ds->repo->hash_algo->hexsz ?
167+
ds->repo->hash_algo->hexsz : ds->len;
162168

163169
if (p->multi_pack_index)
164170
return;
@@ -177,7 +183,7 @@ static void unique_in_pack(struct packed_git *p,
177183
for (i = first; i < num && !ds->ambiguous; i++) {
178184
struct object_id oid;
179185
nth_packed_object_id(&oid, p, i);
180-
if (!match_hash(ds->len, ds->bin_pfx.hash, oid.hash))
186+
if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
181187
break;
182188
update_candidates(ds, &oid);
183189
}
@@ -188,6 +194,10 @@ static void find_short_packed_object(struct disambiguate_state *ds)
188194
struct multi_pack_index *m;
189195
struct packed_git *p;
190196

197+
/* Skip, unless oids from the storage hash algorithm are wanted */
198+
if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
199+
return;
200+
191201
for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
192202
m = m->next)
193203
unique_in_midx(m, ds);
@@ -326,11 +336,12 @@ int set_disambiguate_hint_config(const char *var, const char *value)
326336

327337
static int init_object_disambiguation(struct repository *r,
328338
const char *name, int len,
339+
const struct git_hash_algo *algo,
329340
struct disambiguate_state *ds)
330341
{
331342
int i;
332343

333-
if (len < MINIMUM_ABBREV || len > the_hash_algo->hexsz)
344+
if (len < MINIMUM_ABBREV || len > GIT_MAX_HEXSZ)
334345
return -1;
335346

336347
memset(ds, 0, sizeof(*ds));
@@ -357,6 +368,7 @@ static int init_object_disambiguation(struct repository *r,
357368
ds->len = len;
358369
ds->hex_pfx[len] = '\0';
359370
ds->repo = r;
371+
ds->bin_pfx.algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
360372
prepare_alt_odb(r);
361373
return 0;
362374
}
@@ -491,9 +503,10 @@ static int repo_collect_ambiguous(struct repository *r UNUSED,
491503
return collect_ambiguous(oid, data);
492504
}
493505

494-
static int sort_ambiguous(const void *a, const void *b, void *ctx)
506+
static int sort_ambiguous(const void *va, const void *vb, void *ctx)
495507
{
496508
struct repository *sort_ambiguous_repo = ctx;
509+
const struct object_id *a = va, *b = vb;
497510
int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
498511
int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
499512
int a_type_sort;
@@ -503,8 +516,12 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)
503516
* Sorts by hash within the same object type, just as
504517
* oid_array_for_each_unique() would do.
505518
*/
506-
if (a_type == b_type)
507-
return oidcmp(a, b);
519+
if (a_type == b_type) {
520+
if (a->algo == b->algo)
521+
return oidcmp(a, b);
522+
else
523+
return a->algo > b->algo ? 1 : -1;
524+
}
508525

509526
/*
510527
* Between object types show tags, then commits, and finally
@@ -533,8 +550,12 @@ static enum get_oid_result get_short_oid(struct repository *r,
533550
int status;
534551
struct disambiguate_state ds;
535552
int quietly = !!(flags & GET_OID_QUIETLY);
553+
const struct git_hash_algo *algo = r->hash_algo;
554+
555+
if (flags & GET_OID_HASH_ANY)
556+
algo = NULL;
536557

537-
if (init_object_disambiguation(r, name, len, &ds) < 0)
558+
if (init_object_disambiguation(r, name, len, algo, &ds) < 0)
538559
return -1;
539560

540561
if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
@@ -588,7 +609,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
588609
if (!ds.ambiguous)
589610
ds.fn = NULL;
590611

591-
repo_for_each_abbrev(r, ds.hex_pfx, collect_ambiguous, &collect);
612+
repo_for_each_abbrev(r, ds.hex_pfx, algo, collect_ambiguous, &collect);
592613
sort_ambiguous_oid_array(r, &collect);
593614

594615
if (oid_array_for_each(&collect, show_ambiguous_object, &out))
@@ -610,13 +631,14 @@ static enum get_oid_result get_short_oid(struct repository *r,
610631
}
611632

612633
int repo_for_each_abbrev(struct repository *r, const char *prefix,
634+
const struct git_hash_algo *algo,
613635
each_abbrev_fn fn, void *cb_data)
614636
{
615637
struct oid_array collect = OID_ARRAY_INIT;
616638
struct disambiguate_state ds;
617639
int ret;
618640

619-
if (init_object_disambiguation(r, prefix, strlen(prefix), &ds) < 0)
641+
if (init_object_disambiguation(r, prefix, strlen(prefix), algo, &ds) < 0)
620642
return -1;
621643

622644
ds.always_call_fn = 1;
@@ -787,10 +809,12 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
787809
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
788810
const struct object_id *oid, int len)
789811
{
812+
const struct git_hash_algo *algo =
813+
oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
790814
struct disambiguate_state ds;
791815
struct min_abbrev_data mad;
792816
struct object_id oid_ret;
793-
const unsigned hexsz = r->hash_algo->hexsz;
817+
const unsigned hexsz = algo->hexsz;
794818

795819
if (len < 0) {
796820
unsigned long count = repo_approximate_object_count(r);
@@ -826,7 +850,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
826850

827851
find_abbrev_len_packed(&mad);
828852

829-
if (init_object_disambiguation(r, hex, mad.cur_len, &ds) < 0)
853+
if (init_object_disambiguation(r, hex, mad.cur_len, algo, &ds) < 0)
830854
return -1;
831855

832856
ds.fn = repo_extend_abbrev_len;

object-name.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ enum get_oid_result get_oid_with_context(struct repository *repo, const char *st
6767

6868

6969
typedef int each_abbrev_fn(const struct object_id *oid, void *);
70-
int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
70+
int repo_for_each_abbrev(struct repository *r, const char *prefix,
71+
const struct git_hash_algo *algo, each_abbrev_fn, void *);
7172

7273
int set_disambiguate_hint_config(const char *var, const char *value);
7374

0 commit comments

Comments
 (0)