зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/pack-peeled'
* jc/pack-peeled: Store peeled refs in packed-refs (take 2). Store peeled refs in packed-refs file.
This commit is contained in:
Коммит
d63afe9ebb
|
@ -1,5 +1,7 @@
|
|||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
||||
static const char builtin_pack_refs_usage[] =
|
||||
"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)
|
||||
{
|
||||
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 */
|
||||
if (!(flags & REF_ISSYMREF))
|
||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
if ((flags & REF_ISSYMREF))
|
||||
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\n",
|
||||
sha1_to_hex(o->sha1));
|
||||
}
|
||||
}
|
||||
|
||||
if (cb->prune && !do_not_prune(flags)) {
|
||||
int namelen = strlen(path) + 1;
|
||||
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
||||
|
@ -95,6 +111,10 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
|||
if (!cbdata.refs_file)
|
||||
die("unable to create ref-pack file structure (%s)",
|
||||
strerror(errno));
|
||||
|
||||
/* perhaps other traits later as well */
|
||||
fprintf(cbdata.refs_file, "# pack-refs with: peeled \n");
|
||||
|
||||
for_each_ref(handle_one_ref, &cbdata);
|
||||
fflush(cbdata.refs_file);
|
||||
fsync(fd);
|
||||
|
|
|
@ -13,6 +13,7 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
|||
{
|
||||
struct object *obj;
|
||||
const char *hex;
|
||||
unsigned char peeled[20];
|
||||
|
||||
if (tags_only || heads_only) {
|
||||
int match;
|
||||
|
@ -44,12 +45,15 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
|||
|
||||
match:
|
||||
found_match++;
|
||||
obj = parse_object(sha1);
|
||||
if (!obj) {
|
||||
if (quiet)
|
||||
return 0;
|
||||
die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
/* This changes the semantics slightly that even under quiet we
|
||||
* detect and return error if the repository is corrupt and
|
||||
* ref points at a nonexistent object.
|
||||
*/
|
||||
if (!has_sha1_file(sha1))
|
||||
die("git-show-ref: bad ref %s (%s)", refname,
|
||||
sha1_to_hex(sha1));
|
||||
|
||||
if (quiet)
|
||||
return 0;
|
||||
|
||||
|
@ -58,10 +62,26 @@ match:
|
|||
printf("%s\n", hex);
|
||||
else
|
||||
printf("%s %s\n", hex, refname);
|
||||
if (deref_tags && obj->type == OBJ_TAG) {
|
||||
obj = deref_tag(obj, refname, 0);
|
||||
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
|
||||
if (!deref_tags)
|
||||
return 0;
|
||||
|
||||
if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
|
||||
if (!is_null_sha1(peeled)) {
|
||||
hex = find_unique_abbrev(peeled, abbrev);
|
||||
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;
|
||||
}
|
||||
|
|
106
refs.c
106
refs.c
|
@ -1,12 +1,18 @@
|
|||
#include "refs.h"
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* ISSYMREF=01 and ISPACKED=02 are public interfaces */
|
||||
#define REF_KNOWS_PEELED 04
|
||||
|
||||
struct ref_list {
|
||||
struct ref_list *next;
|
||||
unsigned char flag; /* ISSYMREF? ISPACKED? */
|
||||
unsigned char sha1[20];
|
||||
unsigned char peeled[20];
|
||||
char name[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
|
@ -34,11 +40,13 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
|
|||
if (line[len] != '\n')
|
||||
return NULL;
|
||||
line[len] = 0;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
|
||||
int flag, struct ref_list *list)
|
||||
int flag, struct ref_list *list,
|
||||
struct ref_list **new_entry)
|
||||
{
|
||||
int len;
|
||||
struct ref_list **p = &list, *entry;
|
||||
|
@ -50,8 +58,11 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
|
|||
break;
|
||||
|
||||
/* Same as existing entry? */
|
||||
if (!cmp)
|
||||
if (!cmp) {
|
||||
if (new_entry)
|
||||
*new_entry = entry;
|
||||
return list;
|
||||
}
|
||||
p = &entry->next;
|
||||
}
|
||||
|
||||
|
@ -59,10 +70,13 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
|
|||
len = strlen(name) + 1;
|
||||
entry = xmalloc(sizeof(struct ref_list) + len);
|
||||
hashcpy(entry->sha1, sha1);
|
||||
hashclr(entry->peeled);
|
||||
memcpy(entry->name, name, len);
|
||||
entry->flag = flag;
|
||||
entry->next = *p;
|
||||
*p = entry;
|
||||
if (new_entry)
|
||||
*new_entry = entry;
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -98,25 +112,50 @@ static void invalidate_cached_refs(void)
|
|||
ca->did_loose = ca->did_packed = 0;
|
||||
}
|
||||
|
||||
static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
|
||||
{
|
||||
struct ref_list *list = NULL;
|
||||
struct ref_list *last = NULL;
|
||||
char refline[PATH_MAX];
|
||||
int flag = REF_ISPACKED;
|
||||
|
||||
while (fgets(refline, sizeof(refline), f)) {
|
||||
unsigned char sha1[20];
|
||||
const char *name;
|
||||
static const char header[] = "# pack-refs with:";
|
||||
|
||||
if (!strncmp(refline, header, sizeof(header)-1)) {
|
||||
const char *traits = refline + sizeof(header) - 1;
|
||||
if (strstr(traits, " peeled "))
|
||||
flag |= REF_KNOWS_PEELED;
|
||||
/* perhaps other traits later as well */
|
||||
continue;
|
||||
}
|
||||
|
||||
name = parse_ref_line(refline, sha1);
|
||||
if (name) {
|
||||
list = add_ref(name, sha1, flag, list, &last);
|
||||
continue;
|
||||
}
|
||||
if (last &&
|
||||
refline[0] == '^' &&
|
||||
strlen(refline) == 42 &&
|
||||
refline[41] == '\n' &&
|
||||
!get_sha1_hex(refline + 1, sha1))
|
||||
hashcpy(last->peeled, sha1);
|
||||
}
|
||||
cached_refs->packed = list;
|
||||
}
|
||||
|
||||
static struct ref_list *get_packed_refs(void)
|
||||
{
|
||||
if (!cached_refs.did_packed) {
|
||||
struct ref_list *refs = NULL;
|
||||
FILE *f = fopen(git_path("packed-refs"), "r");
|
||||
cached_refs.packed = NULL;
|
||||
if (f) {
|
||||
struct ref_list *list = NULL;
|
||||
char refline[PATH_MAX];
|
||||
while (fgets(refline, sizeof(refline), f)) {
|
||||
unsigned char sha1[20];
|
||||
const char *name = parse_ref_line(refline, sha1);
|
||||
if (!name)
|
||||
continue;
|
||||
list = add_ref(name, sha1, REF_ISPACKED, list);
|
||||
}
|
||||
read_packed_refs(f, &cached_refs);
|
||||
fclose(f);
|
||||
refs = list;
|
||||
}
|
||||
cached_refs.packed = refs;
|
||||
cached_refs.did_packed = 1;
|
||||
}
|
||||
return cached_refs.packed;
|
||||
|
@ -159,7 +198,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
|
|||
error("%s points nowhere!", ref);
|
||||
continue;
|
||||
}
|
||||
list = add_ref(ref, sha1, flag, list);
|
||||
list = add_ref(ref, sha1, flag, list, NULL);
|
||||
}
|
||||
free(ref);
|
||||
closedir(dir);
|
||||
|
@ -336,6 +375,43 @@ 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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
while (list) {
|
||||
if (!strcmp(list->name, ref)) {
|
||||
if (list->flag & REF_KNOWS_PEELED) {
|
||||
hashcpy(sha1, list->peeled);
|
||||
return 0;
|
||||
}
|
||||
/* older pack-refs did not leave peeled ones */
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* fallback - callers should not call this for unpacked refs */
|
||||
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,
|
||||
void *cb_data)
|
||||
{
|
||||
|
|
7
refs.h
7
refs.h
|
@ -10,12 +10,13 @@ struct ref_lock {
|
|||
int force_write;
|
||||
};
|
||||
|
||||
#define REF_ISSYMREF 01
|
||||
#define REF_ISPACKED 02
|
||||
|
||||
/*
|
||||
* Calls the specified function for each ref file until it returns nonzero,
|
||||
* and returns the value
|
||||
*/
|
||||
#define REF_ISSYMREF 01
|
||||
#define REF_ISPACKED 02
|
||||
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 for_each_ref(each_ref_fn, void *);
|
||||
|
@ -23,6 +24,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_remote_ref(each_ref_fn, void *);
|
||||
|
||||
extern int peel_ref(const char *, unsigned char *);
|
||||
|
||||
/** Reads the refs file specified into sha1 **/
|
||||
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче