#include "cache.h"
#include "refs.h"
+#include "object.h"
+#include "tag.h"
static const char builtin_pack_refs_usage[] =
"git-pack-refs [--all] [--prune]";
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);
{
struct object *obj;
const char *hex;
+ unsigned char peeled[20];
if (tags_only || heads_only) {
int match;
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;
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;
}
#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.
* +1 (newline at the end of the line)
*/
int len = strlen(line) - 42;
+ int peeled = 0;
if (len <= 0)
return NULL;
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;
}
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;
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;
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)
{
*/
#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 *);
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);