Merge branch 'jc/pack-peeled' into next

* jc/pack-peeled:
  Store peeled refs in packed-refs file.
  do_for_each_ref: perform the same sanity check for leftovers.
  git-fetch: follow lightweit tags as well.
  Documentation: Correct alternates documentation, document http-alternates
This commit is contained in:
Junio C Hamano
2006-11-19 18:46:44 -08:00
7 changed files with 169 additions and 44 deletions

View File

@@ -52,9 +52,20 @@ objects/info/packs::
by default.
objects/info/alternates::
This file records absolute filesystem paths of alternate
object stores that this object store borrows objects
from, one pathname per line.
This file records paths to alternate object stores that
this object store borrows objects from, one pathname per
line. Note that not only native Git tools use it locally,
but the HTTP fetcher also tries to use it remotely; this
will usually work if you have relative paths (relative
to the object database, not to the repository!) in your
alternates file, but it will not work if you use absolute
paths unless the absolute path in filesystem and web URL
is the same. See also 'objects/info/http-alternates'.
objects/info/http-alternates::
This file records URLs to alternate object stores that
this object store borrows objects from, to be used when
the repository is fetched over HTTP.
refs::
References are stored in subdirectories of this

View File

@@ -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 %s^{}\n",
sha1_to_hex(o->sha1), path);
}
}
if (cb->prune && !do_not_prune(flags)) {
int namelen = strlen(path) + 1;
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);

View File

@@ -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,11 +62,25 @@ 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);
if (!deref_tags)
return 0;
if ((flag & REF_ISPACKED) && !peel_ref(refname, 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;
}

View File

@@ -432,10 +432,11 @@ case "$no_tags$tags" in
# using local tracking branch.
taglist=$(IFS=" " &&
git-ls-remote $upload_pack --tags "$remote" |
sed -ne 's|^\([0-9a-f]*\)[ ]\(refs/tags/.*\)^{}$|\1 \2|p' |
sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \
-e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' |
while read sha1 name
do
git-show-ref --verify --quiet -- $name && continue
git-show-ref --verify --quiet -- "$name" && continue
git-check-ref-format "$name" || {
echo >&2 "warning: tag ${name} ignored"
continue

111
refs.c
View File

@@ -1,16 +1,18 @@
#include "refs.h"
#include "cache.h"
#include "object.h"
#include "tag.h"
#include <errno.h>
struct ref_list {
struct ref_list *next;
unsigned char flag; /* ISSYMREF? ISPACKED? */
unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */
unsigned char sha1[20];
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.
@@ -21,6 +23,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
* +1 (newline at the end of the line)
*/
int len = strlen(line) - 42;
int peeled = 0;
if (len <= 0)
return NULL;
@@ -29,11 +32,24 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
if (!isspace(line[40]))
return NULL;
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')
return NULL;
line[len] = 0;
if (peeled && (len < 3 || strcmp(line + len - 3, "^{}")))
return NULL;
if (!peeled)
*flag &= ~REF_ISPEELED;
else
*flag |= REF_ISPEELED;
return line;
}
@@ -108,10 +124,12 @@ static struct ref_list *get_packed_refs(void)
char refline[PATH_MAX];
while (fgets(refline, sizeof(refline), f)) {
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)
continue;
list = add_ref(name, sha1, REF_ISPACKED, list);
list = add_ref(name, sha1, flag, list);
}
fclose(f);
refs = list;
@@ -207,7 +225,8 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
if (lstat(path, &st) < 0) {
struct ref_list *list = get_packed_refs();
while (list) {
if (!strcmp(ref, list->name)) {
if (!(list->flag & REF_ISPEELED) &&
!strcmp(ref, list->name)) {
hashcpy(sha1, list->sha1);
if (flag)
*flag |= REF_ISPACKED;
@@ -322,6 +341,60 @@ int read_ref(const char *ref, unsigned char *sha1)
return -1;
}
static int do_one_ref(const char *base, each_ref_fn fn, int trim,
void *cb_data, struct ref_list *entry)
{
if (strncmp(base, entry->name, trim))
return 0;
if (is_null_sha1(entry->sha1))
return 0;
if (entry->flag & REF_ISPEELED)
return 0;
if (!has_sha1_file(entry->sha1)) {
error("%s does not point to a valid object!", entry->name);
return 0;
}
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,
void *cb_data)
{
@@ -343,29 +416,15 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
entry = packed;
packed = packed->next;
}
if (strncmp(base, entry->name, trim))
continue;
if (is_null_sha1(entry->sha1))
continue;
if (!has_sha1_file(entry->sha1)) {
error("%s does not point to a valid object!", entry->name);
continue;
}
retval = fn(entry->name + trim, entry->sha1,
entry->flag, cb_data);
retval = do_one_ref(base, fn, trim, cb_data, entry);
if (retval)
return retval;
}
packed = packed ? packed : loose;
while (packed) {
if (!strncmp(base, packed->name, trim)) {
retval = fn(packed->name + trim, packed->sha1,
packed->flag, cb_data);
if (retval)
return retval;
}
packed = packed->next;
for (packed = packed ? packed : loose; packed; packed = packed->next) {
retval = do_one_ref(base, fn, trim, cb_data, packed);
if (retval)
return retval;
}
return 0;
}

4
refs.h
View File

@@ -16,6 +16,8 @@ struct ref_lock {
*/
#define REF_ISSYMREF 01
#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);
extern int head_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_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);

View File

@@ -66,4 +66,20 @@ test_expect_success "fetch test for-merge" '
cut -f -2 .git/FETCH_HEAD >actual &&
diff expected actual'
test_expect_success 'fetch following tags' '
cd "$D" &&
git tag -a -m 'annotated' anno HEAD &&
git tag light HEAD &&
mkdir four &&
cd four &&
git init-db &&
git fetch .. :track &&
git show-ref --verify refs/tags/anno &&
git show-ref --verify refs/tags/light
'
test_done