зеркало из https://github.com/microsoft/git.git
Store peeled refs in packed-refs file.
This would speed up "show-ref -d" in a repository with mostly packed tags. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Родитель
ef06b91804
Коммит
cf0adba788
|
@ -1,5 +1,7 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
static const char builtin_pack_refs_usage[] =
|
static const char builtin_pack_refs_usage[] =
|
||||||
"git-pack-refs [--all] [--prune]";
|
"git-pack-refs [--all] [--prune]";
|
||||||
|
@ -29,12 +31,26 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
|
||||||
int flags, void *cb_data)
|
int flags, void *cb_data)
|
||||||
{
|
{
|
||||||
struct pack_refs_cb_data *cb = cb_data;
|
struct pack_refs_cb_data *cb = cb_data;
|
||||||
|
int is_tag_ref;
|
||||||
|
|
||||||
if (!cb->all && strncmp(path, "refs/tags/", 10))
|
|
||||||
return 0;
|
|
||||||
/* Do not pack the symbolic refs */
|
/* Do not pack the symbolic refs */
|
||||||
if (!(flags & REF_ISSYMREF))
|
if ((flags & REF_ISSYMREF))
|
||||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
return 0;
|
||||||
|
is_tag_ref = !strncmp(path, "refs/tags/", 10);
|
||||||
|
if (!cb->all && !is_tag_ref)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||||
|
if (is_tag_ref) {
|
||||||
|
struct object *o = parse_object(sha1);
|
||||||
|
if (o->type == OBJ_TAG) {
|
||||||
|
o = deref_tag(o, path, 0);
|
||||||
|
if (o)
|
||||||
|
fprintf(cb->refs_file, "%s %s^{}\n",
|
||||||
|
sha1_to_hex(o->sha1), path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cb->prune && !do_not_prune(flags)) {
|
if (cb->prune && !do_not_prune(flags)) {
|
||||||
int namelen = strlen(path) + 1;
|
int namelen = strlen(path) + 1;
|
||||||
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
||||||
|
|
|
@ -13,6 +13,7 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
const char *hex;
|
const char *hex;
|
||||||
|
unsigned char peeled[20];
|
||||||
|
|
||||||
if (tags_only || heads_only) {
|
if (tags_only || heads_only) {
|
||||||
int match;
|
int match;
|
||||||
|
@ -44,12 +45,15 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
||||||
|
|
||||||
match:
|
match:
|
||||||
found_match++;
|
found_match++;
|
||||||
obj = parse_object(sha1);
|
|
||||||
if (!obj) {
|
/* This changes the semantics slightly that even under quiet we
|
||||||
if (quiet)
|
* detect and return error if the repository is corrupt and
|
||||||
return 0;
|
* ref points at a nonexistent object.
|
||||||
die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1));
|
*/
|
||||||
}
|
if (!has_sha1_file(sha1))
|
||||||
|
die("git-show-ref: bad ref %s (%s)", refname,
|
||||||
|
sha1_to_hex(sha1));
|
||||||
|
|
||||||
if (quiet)
|
if (quiet)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -58,11 +62,25 @@ match:
|
||||||
printf("%s\n", hex);
|
printf("%s\n", hex);
|
||||||
else
|
else
|
||||||
printf("%s %s\n", hex, refname);
|
printf("%s %s\n", hex, refname);
|
||||||
if (deref_tags && obj->type == OBJ_TAG) {
|
|
||||||
obj = deref_tag(obj, refname, 0);
|
if (!deref_tags)
|
||||||
hex = find_unique_abbrev(obj->sha1, abbrev);
|
return 0;
|
||||||
|
|
||||||
|
if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
|
||||||
|
hex = find_unique_abbrev(peeled, abbrev);
|
||||||
printf("%s %s^{}\n", hex, refname);
|
printf("%s %s^{}\n", hex, refname);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
obj = parse_object(sha1);
|
||||||
|
if (!obj)
|
||||||
|
die("git-show-ref: bad ref %s (%s)", refname,
|
||||||
|
sha1_to_hex(sha1));
|
||||||
|
if (obj->type == OBJ_TAG) {
|
||||||
|
obj = deref_tag(obj, refname, 0);
|
||||||
|
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||||
|
printf("%s %s^{}\n", hex, refname);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
73
refs.c
73
refs.c
|
@ -1,16 +1,18 @@
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
struct ref_list {
|
struct ref_list {
|
||||||
struct ref_list *next;
|
struct ref_list *next;
|
||||||
unsigned char flag; /* ISSYMREF? ISPACKED? */
|
unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
char name[FLEX_ARRAY];
|
char name[FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *parse_ref_line(char *line, unsigned char *sha1)
|
static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* 42: the answer to everything.
|
* 42: the answer to everything.
|
||||||
|
@ -21,6 +23,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
|
||||||
* +1 (newline at the end of the line)
|
* +1 (newline at the end of the line)
|
||||||
*/
|
*/
|
||||||
int len = strlen(line) - 42;
|
int len = strlen(line) - 42;
|
||||||
|
int peeled = 0;
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -29,11 +32,24 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
|
||||||
if (!isspace(line[40]))
|
if (!isspace(line[40]))
|
||||||
return NULL;
|
return NULL;
|
||||||
line += 41;
|
line += 41;
|
||||||
if (isspace(*line))
|
|
||||||
return NULL;
|
if (isspace(*line)) {
|
||||||
|
/* "SHA-1 SP SP refs/tags/tagname^{} LF"? */
|
||||||
|
line++;
|
||||||
|
len--;
|
||||||
|
peeled = 1;
|
||||||
|
}
|
||||||
if (line[len] != '\n')
|
if (line[len] != '\n')
|
||||||
return NULL;
|
return NULL;
|
||||||
line[len] = 0;
|
line[len] = 0;
|
||||||
|
|
||||||
|
if (peeled && (len < 3 || strcmp(line + len - 3, "^{}")))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!peeled)
|
||||||
|
*flag &= ~REF_ISPEELED;
|
||||||
|
else
|
||||||
|
*flag |= REF_ISPEELED;
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,10 +124,12 @@ static struct ref_list *get_packed_refs(void)
|
||||||
char refline[PATH_MAX];
|
char refline[PATH_MAX];
|
||||||
while (fgets(refline, sizeof(refline), f)) {
|
while (fgets(refline, sizeof(refline), f)) {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *name = parse_ref_line(refline, sha1);
|
int flag = REF_ISPACKED;
|
||||||
|
const char *name =
|
||||||
|
parse_ref_line(refline, sha1, &flag);
|
||||||
if (!name)
|
if (!name)
|
||||||
continue;
|
continue;
|
||||||
list = add_ref(name, sha1, REF_ISPACKED, list);
|
list = add_ref(name, sha1, flag, list);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
refs = list;
|
refs = list;
|
||||||
|
@ -207,7 +225,8 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
|
||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
struct ref_list *list = get_packed_refs();
|
struct ref_list *list = get_packed_refs();
|
||||||
while (list) {
|
while (list) {
|
||||||
if (!strcmp(ref, list->name)) {
|
if (!(list->flag & REF_ISPEELED) &&
|
||||||
|
!strcmp(ref, list->name)) {
|
||||||
hashcpy(sha1, list->sha1);
|
hashcpy(sha1, list->sha1);
|
||||||
if (flag)
|
if (flag)
|
||||||
*flag |= REF_ISPACKED;
|
*flag |= REF_ISPACKED;
|
||||||
|
@ -329,6 +348,8 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
|
||||||
return 0;
|
return 0;
|
||||||
if (is_null_sha1(entry->sha1))
|
if (is_null_sha1(entry->sha1))
|
||||||
return 0;
|
return 0;
|
||||||
|
if (entry->flag & REF_ISPEELED)
|
||||||
|
return 0;
|
||||||
if (!has_sha1_file(entry->sha1)) {
|
if (!has_sha1_file(entry->sha1)) {
|
||||||
error("%s does not point to a valid object!", entry->name);
|
error("%s does not point to a valid object!", entry->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -336,6 +357,44 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
|
||||||
return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
|
return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int peel_ref(const char *ref, unsigned char *sha1)
|
||||||
|
{
|
||||||
|
int flag;
|
||||||
|
unsigned char base[20];
|
||||||
|
struct object *o;
|
||||||
|
|
||||||
|
if (!resolve_ref(ref, base, 1, &flag))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((flag & REF_ISPACKED)) {
|
||||||
|
struct ref_list *list = get_packed_refs();
|
||||||
|
int len = strlen(ref);
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
if ((list->flag & REF_ISPEELED) &&
|
||||||
|
!strncmp(list->name, ref, len) &&
|
||||||
|
strlen(list->name) == len + 3 &&
|
||||||
|
!strcmp(list->name + len, "^{}")) {
|
||||||
|
hashcpy(sha1, list->sha1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
/* older pack-refs did not leave peeled ones in */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise ... */
|
||||||
|
o = parse_object(base);
|
||||||
|
if (o->type == OBJ_TAG) {
|
||||||
|
o = deref_tag(o, ref, 0);
|
||||||
|
if (o) {
|
||||||
|
hashcpy(sha1, o->sha1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
|
static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
{
|
{
|
||||||
|
|
4
refs.h
4
refs.h
|
@ -16,6 +16,8 @@ struct ref_lock {
|
||||||
*/
|
*/
|
||||||
#define REF_ISSYMREF 01
|
#define REF_ISSYMREF 01
|
||||||
#define REF_ISPACKED 02
|
#define REF_ISPACKED 02
|
||||||
|
#define REF_ISPEELED 04 /* internal use */
|
||||||
|
|
||||||
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
|
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
|
||||||
extern int head_ref(each_ref_fn, void *);
|
extern int head_ref(each_ref_fn, void *);
|
||||||
extern int for_each_ref(each_ref_fn, void *);
|
extern int for_each_ref(each_ref_fn, void *);
|
||||||
|
@ -23,6 +25,8 @@ extern int for_each_tag_ref(each_ref_fn, void *);
|
||||||
extern int for_each_branch_ref(each_ref_fn, void *);
|
extern int for_each_branch_ref(each_ref_fn, void *);
|
||||||
extern int for_each_remote_ref(each_ref_fn, void *);
|
extern int for_each_remote_ref(each_ref_fn, void *);
|
||||||
|
|
||||||
|
extern int peel_ref(const char *, unsigned char *);
|
||||||
|
|
||||||
/** Reads the refs file specified into sha1 **/
|
/** Reads the refs file specified into sha1 **/
|
||||||
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче