Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
git
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
8b5157e
Documentation
arm
compat
contrib
gitweb
mozilla-sha1
perl
ppc
t
templates
xdiff
.gitignore
.mailmap
COPYING
GIT-VERSION-GEN
INSTALL
Makefile
README
alloc.c
archive-tar.c
archive-zip.c
archive.h
base85.c
blob.c
blob.h
builtin-add.c
builtin-annotate.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-check-ref-format.c
builtin-checkout-index.c
builtin-commit-tree.c
builtin-count-objects.c
builtin-describe.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-stages.c
builtin-diff-tree.c
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-mailsplit.c
builtin-merge-file.c
builtin-mv.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-pack-refs.c
builtin-prune-packed.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-repo-config.c
builtin-rerere.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-rm.c
builtin-runstatus.c
builtin-shortlog.c
builtin-show-branch.c
builtin-show-ref.c
builtin-stripspace.c
builtin-symbolic-ref.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-update-ref.c
builtin-upload-archive.c
builtin-verify-pack.c
builtin-write-tree.c
builtin.h
cache-tree.c
cache-tree.h
cache.h
check-builtins.sh
check-racy.c
color.c
color.h
combine-diff.c
commit.c
commit.h
config.c
config.mak.in
configure.ac
connect.c
convert-objects.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
delta.h
diff-delta.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
dump-cache-tree.c
entry.c
environment.c
exec_cmd.c
exec_cmd.h
fetch-pack.c
fetch.c
fetch.h
fsck-objects.c
generate-cmdlist.sh
git-add--interactive.perl
git-am.sh
git-applymbox.sh
git-applypatch.sh
git-archimport.perl
git-bisect.sh
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-fetch.sh
git-gc.sh
git-instaweb.sh
git-lost-found.sh
git-ls-remote.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-ours.sh
git-merge-resolve.sh
git-merge-stupid.sh
git-merge.sh
git-p4import.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase.sh
git-relink.perl
git-remote.perl
git-repack.sh
git-request-pull.sh
git-reset.sh
git-resolve.sh
git-revert.sh
git-send-email.perl
git-sh-setup.sh
git-svn.perl
git-svnimport.perl
git-tag.sh
git-verify-tag.sh
git.c
git.spec.in
gitk
grep.c
grep.h
hash-object.c
help.c
http-fetch.c
http-push.c
http.c
http.h
ident.c
imap-send.c
index-pack.c
interpolate.c
interpolate.h
list-objects.c
list-objects.h
local-fetch.c
lockfile.c
log-tree.c
log-tree.h
merge-base.c
merge-file.c
merge-index.c
merge-recursive.c
merge-tree.c
mktag.c
mktree.c
object-refs.c
object.c
object.h
pack-check.c
pack-redundant.c
pack.h
pager.c
patch-delta.c
patch-id.c
path-list.c
path-list.h
path.c
peek-remote.c
pkt-line.c
pkt-line.h
quote.c
quote.h
reachable.c
reachable.h
read-cache.c
receive-pack.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
revision.c
revision.h
rsh.c
rsh.h
run-command.c
run-command.h
send-pack.c
server-info.c
setup.c
sha1_file.c
sha1_name.c
shallow.c
shell.c
show-index.c
sideband.c
sideband.h
ssh-fetch.c
ssh-pull.c
ssh-push.c
ssh-upload.c
strbuf.c
strbuf.h
tag.c
tag.h
tar.h
test-date.c
test-delta.c
test-sha1.c
test-sha1.sh
trace.c
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unpack-file.c
unpack-trees.c
unpack-trees.h
update-server-info.c
upload-pack.c
usage.c
utf8.c
utf8.h
var.c
write_or_die.c
wt-status.c
wt-status.h
xdiff-interface.c
xdiff-interface.h
Breadcrumbs
git
/
sha1_name.c
Blame
Blame
Latest commit
History
History
605 lines (551 loc) · 13.2 KB
Breadcrumbs
git
/
sha1_name.c
Top
File metadata and controls
Code
Blame
605 lines (551 loc) · 13.2 KB
Raw
#include "cache.h" #include "tag.h" #include "commit.h" #include "tree.h" #include "blob.h" #include "tree-walk.h" #include "refs.h" static int find_short_object_filename(int len, const char *name, unsigned char *sha1) { struct alternate_object_database *alt; char hex[40]; int found = 0; static struct alternate_object_database *fakeent; if (!fakeent) { const char *objdir = get_object_directory(); int objdir_len = strlen(objdir); int entlen = objdir_len + 43; fakeent = xmalloc(sizeof(*fakeent) + entlen); memcpy(fakeent->base, objdir, objdir_len); fakeent->name = fakeent->base + objdir_len + 1; fakeent->name[-1] = '/'; } fakeent->next = alt_odb_list; sprintf(hex, "%.2s", name); for (alt = fakeent; alt && found < 2; alt = alt->next) { struct dirent *de; DIR *dir; sprintf(alt->name, "%.2s/", name); dir = opendir(alt->base); if (!dir) continue; while ((de = readdir(dir)) != NULL) { if (strlen(de->d_name) != 38) continue; if (memcmp(de->d_name, name + 2, len - 2)) continue; if (!found) { memcpy(hex + 2, de->d_name, 38); found++; } else if (memcmp(hex + 2, de->d_name, 38)) { found = 2; break; } } closedir(dir); } if (found == 1) return get_sha1_hex(hex, sha1) == 0; return found; } static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) { do { if (*a != *b) return 0; a++; b++; len -= 2; } while (len > 1); if (len) if ((*a ^ *b) & 0xf0) return 0; return 1; } static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) { struct packed_git *p; unsigned char found_sha1[20]; int found = 0; prepare_packed_git(); for (p = packed_git; p && found < 2; p = p->next) { unsigned num = num_packed_objects(p); unsigned first = 0, last = num; while (first < last) { unsigned mid = (first + last) / 2; unsigned char now[20]; int cmp; nth_packed_object_sha1(p, mid, now); cmp = hashcmp(match, now); if (!cmp) { first = mid; break; } if (cmp > 0) { first = mid+1; continue; } last = mid; } if (first < num) { unsigned char now[20], next[20]; nth_packed_object_sha1(p, first, now); if (match_sha(len, match, now)) { if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) { /* unique within this pack */ if (!found) { hashcpy(found_sha1, now); found++; } else if (hashcmp(found_sha1, now)) { found = 2; break; } } else { /* not even unique within this pack */ found = 2; break; } } } } if (found == 1) hashcpy(sha1, found_sha1); return found; } #define SHORT_NAME_NOT_FOUND (-1) #define SHORT_NAME_AMBIGUOUS (-2) static int find_unique_short_object(int len, char *canonical, unsigned char *res, unsigned char *sha1) { int has_unpacked, has_packed; unsigned char unpacked_sha1[20], packed_sha1[20]; has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1); has_packed = find_short_packed_object(len, res, packed_sha1); if (!has_unpacked && !has_packed) return SHORT_NAME_NOT_FOUND; if (1 < has_unpacked || 1 < has_packed) return SHORT_NAME_AMBIGUOUS; if (has_unpacked != has_packed) { hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1)); return 0; } /* Both have unique ones -- do they match? */ if (hashcmp(packed_sha1, unpacked_sha1)) return SHORT_NAME_AMBIGUOUS; hashcpy(sha1, packed_sha1); return 0; } static int get_short_sha1(const char *name, int len, unsigned char *sha1, int quietly) { int i, status; char canonical[40]; unsigned char res[20]; if (len < MINIMUM_ABBREV || len > 40) return -1; hashclr(res); memset(canonical, 'x', 40); for (i = 0; i < len ;i++) { unsigned char c = name[i]; unsigned char val; if (c >= '0' && c <= '9') val = c - '0'; else if (c >= 'a' && c <= 'f') val = c - 'a' + 10; else if (c >= 'A' && c <='F') { val = c - 'A' + 10; c -= 'A' - 'a'; } else return -1; canonical[i] = c; if (!(i & 1)) val <<= 4; res[i >> 1] |= val; } status = find_unique_short_object(i, canonical, res, sha1); if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) return error("short SHA1 %.*s is ambiguous.", len, canonical); return status; } const char *find_unique_abbrev(const unsigned char *sha1, int len) { int status, is_null; static char hex[41]; is_null = is_null_sha1(sha1); memcpy(hex, sha1_to_hex(sha1), 40); if (len == 40 || !len) return hex; while (len < 40) { unsigned char sha1_ret[20]; status = get_short_sha1(hex, len, sha1_ret, 1); if (!status || (is_null && status != SHORT_NAME_AMBIGUOUS)) { hex[len] = 0; return hex; } if (status != SHORT_NAME_AMBIGUOUS) return NULL; len++; } return NULL; } static int ambiguous_path(const char *path, int len) { int slash = 1; int cnt; for (cnt = 0; cnt < len; cnt++) { switch (*path++) { case '\0': break; case '/': if (slash) break; slash = 1; continue; case '.': continue; default: slash = 0; continue; } break; } return slash; } int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) { static const char *fmt[] = { "%.*s", "refs/%.*s", "refs/tags/%.*s", "refs/heads/%.*s", "refs/remotes/%.*s", "refs/remotes/%.*s/HEAD", NULL }; const char **p, *r; int refs_found = 0; *ref = NULL; for (p = fmt; *p; p++) { unsigned char sha1_from_ref[20]; unsigned char *this_result; this_result = refs_found ? sha1_from_ref : sha1; r = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; } } return refs_found; } static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { static const char *warning = "warning: refname '%.*s' is ambiguous.\n"; char *real_ref = NULL; int refs_found = 0; int at, reflog_len; if (len == 40 && !get_sha1_hex(str, sha1)) return 0; /* basic@{time or number} format to query ref-log */ reflog_len = at = 0; if (str[len-1] == '}') { for (at = 1; at < len - 1; at++) { if (str[at] == '@' && str[at+1] == '{') { reflog_len = (len-1) - (at+2); len = at; break; } } } /* Accept only unambiguous ref paths. */ if (ambiguous_path(str, len)) return -1; refs_found = dwim_ref(str, len, sha1, &real_ref); if (!refs_found) return -1; if (warn_ambiguous_refs && refs_found > 1) fprintf(stderr, warning, len, str); if (reflog_len) { /* Is it asking for N-th entry, or approxidate? */ int nth, i; unsigned long at_time; unsigned long co_time; int co_tz, co_cnt; for (i = nth = 0; 0 <= nth && i < reflog_len; i++) { char ch = str[at+2+i]; if ('0' <= ch && ch <= '9') nth = nth * 10 + ch - '0'; else nth = -1; } if (0 <= nth) at_time = 0; else at_time = approxidate(str + at + 2); if (read_ref_at(real_ref, at_time, nth, sha1, NULL, &co_time, &co_tz, &co_cnt)) { if (at_time) fprintf(stderr, "warning: Log for '%.*s' only goes " "back to %s.\n", len, str, show_rfc2822_date(co_time, co_tz)); else fprintf(stderr, "warning: Log for '%.*s' only has " "%d entries.\n", len, str, co_cnt); } } free(real_ref); return 0; } static int get_sha1_1(const char *name, int len, unsigned char *sha1); static int get_parent(const char *name, int len, unsigned char *result, int idx) { unsigned char sha1[20]; int ret = get_sha1_1(name, len, sha1); struct commit *commit; struct commit_list *p; if (ret) return ret; commit = lookup_commit_reference(sha1); if (!commit) return -1; if (parse_commit(commit)) return -1; if (!idx) { hashcpy(result, commit->object.sha1); return 0; } p = commit->parents; while (p) { if (!--idx) { hashcpy(result, p->item->object.sha1); return 0; } p = p->next; } return -1; } static int get_nth_ancestor(const char *name, int len, unsigned char *result, int generation) { unsigned char sha1[20]; int ret = get_sha1_1(name, len, sha1); if (ret) return ret; while (generation--) { struct commit *commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit) || !commit->parents) return -1; hashcpy(sha1, commit->parents->item->object.sha1); } hashcpy(result, sha1); return 0; } static int peel_onion(const char *name, int len, unsigned char *sha1) { unsigned char outer[20]; const char *sp; unsigned int expected_type = 0; struct object *o; /* * "ref^{type}" dereferences ref repeatedly until you cannot * dereference anymore, or you get an object of given type, * whichever comes first. "ref^{}" means just dereference * tags until you get a non-tag. "ref^0" is a shorthand for * "ref^{commit}". "commit^{tree}" could be used to find the * top-level tree of the given commit. */ if (len < 4 || name[len-1] != '}') return -1; for (sp = name + len - 1; name <= sp; sp--) { int ch = *sp; if (ch == '{' && name < sp && sp[-1] == '^') break; } if (sp <= name) return -1; sp++; /* beginning of type name, or closing brace for empty */ if (!strncmp(commit_type, sp, 6) && sp[6] == '}') expected_type = OBJ_COMMIT; else if (!strncmp(tree_type, sp, 4) && sp[4] == '}') expected_type = OBJ_TREE; else if (!strncmp(blob_type, sp, 4) && sp[4] == '}') expected_type = OBJ_BLOB; else if (sp[0] == '}') expected_type = OBJ_NONE; else return -1; if (get_sha1_1(name, sp - name - 2, outer)) return -1; o = parse_object(outer); if (!o) return -1; if (!expected_type) { o = deref_tag(o, name, sp - name - 2); if (!o || (!o->parsed && !parse_object(o->sha1))) return -1; hashcpy(sha1, o->sha1); } else { /* At this point, the syntax look correct, so * if we do not get the needed object, we should * barf. */ while (1) { if (!o || (!o->parsed && !parse_object(o->sha1))) return -1; if (o->type == expected_type) { hashcpy(sha1, o->sha1); return 0; } if (o->type == OBJ_TAG) o = ((struct tag*) o)->tagged; else if (o->type == OBJ_COMMIT) o = &(((struct commit *) o)->tree->object); else return error("%.*s: expected %s type, but the object dereferences to %s type", len, name, typename(expected_type), typename(o->type)); if (!o->parsed) parse_object(o->sha1); } } return 0; } static int get_describe_name(const char *name, int len, unsigned char *sha1) { const char *cp; for (cp = name + len - 1; name + 2 <= cp; cp--) { char ch = *cp; if (hexval(ch) & ~0377) { /* We must be looking at g in "SOMETHING-g" * for it to be describe output. */ if (ch == 'g' && cp[-1] == '-') { cp++; len -= cp - name; return get_short_sha1(cp, len, sha1, 1); } } } return -1; } static int get_sha1_1(const char *name, int len, unsigned char *sha1) { int ret, has_suffix; const char *cp; /* "name~3" is "name^^^", * "name~" and "name~0" are name -- not "name^0"! * "name^" is not "name^0"; it is "name^1". */ has_suffix = 0; for (cp = name + len - 1; name <= cp; cp--) { int ch = *cp; if ('0' <= ch && ch <= '9') continue; if (ch == '~' || ch == '^') has_suffix = ch; break; } if (has_suffix) { int num = 0; int len1 = cp - name; cp++; while (cp < name + len) num = num * 10 + *cp++ - '0'; if (has_suffix == '^') { if (!num && len1 == len - 1) num = 1; return get_parent(name, len1, sha1, num); } /* else if (has_suffix == '~') -- goes without saying */ return get_nth_ancestor(name, len1, sha1, num); } ret = peel_onion(name, len, sha1); if (!ret) return 0; ret = get_sha1_basic(name, len, sha1); if (!ret) return 0; /* It could be describe output that is "SOMETHING-gXXXX" */ ret = get_describe_name(name, len, sha1); if (!ret) return 0; return get_short_sha1(name, len, sha1, 0); } /* * This is like "get_sha1_basic()", except it allows "sha1 expressions", * notably "xyz^" for "parent of xyz" */ int get_sha1(const char *name, unsigned char *sha1) { int ret, bracket_depth; unsigned unused; int namelen = strlen(name); const char *cp; prepare_alt_odb(); ret = get_sha1_1(name, namelen, sha1); if (!ret) return ret; /* sha1:path --> object name of path in ent sha1 * :path -> object name of path in index * :[0-3]:path -> object name of path in index at stage */ if (name[0] == ':') { int stage = 0; struct cache_entry *ce; int pos; if (namelen < 3 || name[2] != ':' || name[1] < '0' || '3' < name[1]) cp = name + 1; else { stage = name[1] - '0'; cp = name + 3; } namelen = namelen - (cp - name); if (!active_cache) read_cache(); if (active_nr < 0) return -1; pos = cache_name_pos(cp, namelen); if (pos < 0) pos = -pos - 1; while (pos < active_nr) { ce = active_cache[pos]; if (ce_namelen(ce) != namelen || memcmp(ce->name, cp, namelen)) break; if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); return 0; } pos++; } return -1; } for (cp = name, bracket_depth = 0; *cp; cp++) { if (*cp == '{') bracket_depth++; else if (bracket_depth && *cp == '}') bracket_depth--; else if (!bracket_depth && *cp == ':') break; } if (*cp == ':') { unsigned char tree_sha1[20]; if (!get_sha1_1(name, cp-name, tree_sha1)) return get_tree_entry(tree_sha1, cp+1, sha1, &unused); } return ret; }
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
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
You can’t perform that action at this time.