static void name_rev(struct commit *commit, const char *tip_name, int generation, int distance, int deref) { struct rev_name *name = (struct rev_name *)commit->util; struct commit_list *parents; int parent_number = 1; parse_commit(commit); if (commit->date < cutoff) return; if (deref) { tip_name = xstrfmt("%s^0", tip_name); if (generation) die("generation: %d, but deref?", generation); } if (name == NULL) { name = xmalloc(sizeof(rev_name)); commit->util = name; goto copy_data; } else if (name->distance > distance) { copy_data: name->tip_name = tip_name; name->generation = generation; name->distance = distance; } else return; for (parents = commit->parents; parents; parents = parents->next, parent_number++) { if (parent_number > 1) { int len = strlen(tip_name); char *new_name = xmalloc(len + 1 + decimal_length(generation) + /* ~<n> */ 1 + 2 + /* ^NN */ 1); if (len > 2 && !strcmp(tip_name + len - 2, "^0")) len -= 2; if (generation > 0) sprintf(new_name, "%.*s~%d^%d", len, tip_name, generation, parent_number); else sprintf(new_name, "%.*s^%d", len, tip_name, parent_number); name_rev(parents->item, new_name, 0, distance + MERGE_TRAVERSAL_WEIGHT, 0); } else { name_rev(parents->item, tip_name, generation + 1, distance + 1, 0); } } }
static void name_rev(struct commit *commit, const char *tip_name, int generation, int distance, int deref) { struct rev_name *name = (struct rev_name *)commit->util; struct commit_list *parents; int parent_number = 1; parse_commit(commit); if (commit->date < cutoff) return; if (deref) { tip_name = xstrfmt("%s^0", tip_name); if (generation) die("generation: %d, but deref?", generation); } if (name == NULL) { name = xmalloc(sizeof(rev_name)); commit->util = name; goto copy_data; } else if (name->distance > distance) { copy_data: name->tip_name = tip_name; name->generation = generation; name->distance = distance; } else return; for (parents = commit->parents; parents; parents = parents->next, parent_number++) { if (parent_number > 1) { size_t len; char *new_name; strip_suffix(tip_name, "^0", &len); if (generation > 0) new_name = xstrfmt("%.*s~%d^%d", (int)len, tip_name, generation, parent_number); else new_name = xstrfmt("%.*s^%d", (int)len, tip_name, parent_number); name_rev(parents->item, new_name, 0, distance + MERGE_TRAVERSAL_WEIGHT, 0); } else { name_rev(parents->item, tip_name, generation + 1, distance + 1, 0); } } }
static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data) { struct object *o = parse_object(sha1); struct name_ref_data *data = cb_data; int deref = 0; if (data->tags_only && prefixcmp(path, "refs/tags/")) return 0; if (data->ref_filter && fnmatch(data->ref_filter, path, 0)) return 0; while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o = parse_object(t->tagged->sha1); deref = 1; } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!prefixcmp(path, "refs/heads/")) path = path + 11; else if (data->tags_only && data->name_only && !prefixcmp(path, "refs/tags/")) path = path + 10; else if (!prefixcmp(path, "refs/")) path = path + 5; name_rev(commit, xstrdup(path), 0, 0, deref); } return 0; }
static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data) { struct object *o = parse_object(oid->hash); struct name_ref_data *data = cb_data; int can_abbreviate_output = data->tags_only && data->name_only; int deref = 0; if (data->tags_only && !starts_with(path, "refs/tags/")) return 0; if (data->ref_filter) { switch (subpath_matches(path, data->ref_filter)) { case -1: /* did not match */ return 0; case 0: /* matched fully */ break; default: /* matched subpath */ can_abbreviate_output = 1; break; } } add_to_tip_table(oid->hash, path, can_abbreviate_output); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o = parse_object(t->tagged->oid.hash); deref = 1; } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; path = name_ref_abbrev(path, can_abbreviate_output); name_rev(commit, xstrdup(path), 0, 0, deref); } return 0; }