#include "tag.h"
#include "dir.h"
-/* ISSYMREF=01 and ISPACKED=02 are public interfaces */
-#define REF_KNOWS_PEELED 04
-#define REF_BROKEN 010
+/* ISSYMREF=0x01, ISPACKED=0x02 and ISBROKEN=0x04 are public interfaces */
+#define REF_KNOWS_PEELED 0x10
struct ref_entry {
unsigned char flag; /* ISSYMREF? ISPACKED? */
}
static void add_ref(const char *name, const unsigned char *sha1,
- int flag, struct ref_array *refs,
+ int flag, int check_name, struct ref_array *refs,
struct ref_entry **new_entry)
{
int len;
entry = xmalloc(sizeof(struct ref_entry) + len);
hashcpy(entry->sha1, sha1);
hashclr(entry->peeled);
- if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+ if (check_name &&
+ check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
die("Reference has invalid format: '%s'", name);
memcpy(entry->name, name, len);
entry->flag = flag;
refs->did_loose = 0;
}
-static void clear_ref_cache(struct ref_cache *refs)
-{
- clear_packed_ref_cache(refs);
- clear_loose_ref_cache(refs);
-}
-
static struct ref_cache *create_ref_cache(const char *submodule)
{
int len;
void invalidate_ref_cache(const char *submodule)
{
- clear_ref_cache(get_ref_cache(submodule));
+ struct ref_cache *refs = get_ref_cache(submodule);
+ clear_packed_ref_cache(refs);
+ clear_loose_ref_cache(refs);
}
static void read_packed_refs(FILE *f, struct ref_array *array)
name = parse_ref_line(refline, sha1);
if (name) {
- add_ref(name, sha1, flag, array, &last);
+ add_ref(name, sha1, flag, 1, array, &last);
continue;
}
if (last &&
void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
{
- add_ref(name, sha1, flag, &extra_refs, NULL);
+ add_ref(name, sha1, flag, 0, &extra_refs, NULL);
}
void clear_extra_refs(void)
flag = 0;
if (resolve_gitlink_ref(submodule, ref, sha1) < 0) {
hashclr(sha1);
- flag |= REF_BROKEN;
- }
- } else
- if (!resolve_ref(ref, sha1, 1, &flag)) {
- hashclr(sha1);
- flag |= REF_BROKEN;
+ flag |= REF_ISBROKEN;
}
- add_ref(ref, sha1, flag, array, NULL);
+ } else if (!resolve_ref(ref, sha1, 1, &flag)) {
+ hashclr(sha1);
+ flag |= REF_ISBROKEN;
+ }
+ add_ref(ref, sha1, flag, 1, array, NULL);
}
free(ref);
closedir(dir);
#define MAXDEPTH 5
#define MAXREFLEN (1024)
+/*
+ * Called by resolve_gitlink_ref_recursive() after it failed to read
+ * from "name", which is "module/.git/<refname>". Find <refname> in
+ * the packed-refs file for the submodule.
+ */
static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result)
{
int retval = -1;
struct ref_entry *ref;
- struct ref_array *array = get_packed_refs(name);
+ struct ref_array *array;
+ /* being defensive: resolve_gitlink_ref() did this for us */
+ if (pathlen < 6 || memcmp(name + pathlen - 6, "/.git/", 6))
+ die("Oops");
+ name[pathlen - 6] = '\0'; /* make it path to the submodule */
+ array = get_packed_refs(name);
ref = search_ref_array(array, refname);
if (ref != NULL) {
memcpy(result, ref->sha1, 20);
ssize_t len;
char buffer[256];
static char ref_buffer[256];
- char path[PATH_MAX];
if (flag)
*flag = 0;
return NULL;
for (;;) {
+ char path[PATH_MAX];
struct stat st;
char *buf;
int fd;
*/
if (prefixcmp(buffer, "ref:"))
break;
+ if (flag)
+ *flag |= REF_ISSYMREF;
buf = buffer + 4;
while (isspace(*buf))
buf++;
if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
- warning("symbolic reference in %s is formatted incorrectly",
- path);
+ if (flag)
+ *flag |= REF_ISBROKEN;
return NULL;
}
ref = strcpy(ref_buffer, buf);
- if (flag)
- *flag |= REF_ISSYMREF;
}
/* Please note that FETCH_HEAD has a second line containing other data. */
if (get_sha1_hex(buffer, sha1) || (buffer[40] != '\0' && !isspace(buffer[40]))) {
- warning("reference in %s is formatted incorrectly", path);
+ if (flag)
+ *flag |= REF_ISBROKEN;
return NULL;
}
return ref;
return 0;
if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) {
- if (entry->flag & REF_BROKEN)
- return 0; /* ignore dangling symref */
+ if (entry->flag & REF_ISBROKEN)
+ return 0; /* ignore broken refs e.g. dangling symref */
if (!has_sha1_file(entry->sha1)) {
error("%s does not point to a valid object!", entry->name);
return 0;
return 1;
}
+/*
+ * *string and *len will only be substituted, and *string returned (for
+ * later free()ing) if the string passed in is a magic short-hand form
+ * to name a branch.
+ */
+static char *substitute_branch_name(const char **string, int *len)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int ret = interpret_branch_name(*string, &buf);
+
+ if (ret == *len) {
+ size_t size;
+ *string = strbuf_detach(&buf, &size);
+ *len = size;
+ return (char *)*string;
+ }
+
+ return NULL;
+}
+
+int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
+{
+ char *last_branch = substitute_branch_name(&str, &len);
+ const char **p, *r;
+ int refs_found = 0;
+
+ *ref = NULL;
+ for (p = ref_rev_parse_rules; *p; p++) {
+ char fullref[PATH_MAX];
+ unsigned char sha1_from_ref[20];
+ unsigned char *this_result;
+ int flag;
+
+ this_result = refs_found ? sha1_from_ref : sha1;
+ mksnpath(fullref, sizeof(fullref), *p, len, str);
+ r = resolve_ref(fullref, this_result, 1, &flag);
+ if (r) {
+ if (!refs_found++)
+ *ref = xstrdup(r);
+ if (!warn_ambiguous_refs)
+ break;
+ } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) {
+ warning("ignoring dangling symref %s.", fullref);
+ } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {
+ warning("ignoring broken ref %s.", fullref);
+ }
+ }
+ free(last_branch);
+ return refs_found;
+}
+
+int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
+{
+ char *last_branch = substitute_branch_name(&str, &len);
+ const char **p;
+ int logs_found = 0;
+
+ *log = NULL;
+ for (p = ref_rev_parse_rules; *p; p++) {
+ struct stat st;
+ unsigned char hash[20];
+ char path[PATH_MAX];
+ const char *ref, *it;
+
+ mksnpath(path, sizeof(path), *p, len, str);
+ ref = resolve_ref(path, hash, 1, NULL);
+ if (!ref)
+ continue;
+ if (!stat(git_path("logs/%s", path), &st) &&
+ S_ISREG(st.st_mode))
+ it = path;
+ else if (strcmp(ref, path) &&
+ !stat(git_path("logs/%s", ref), &st) &&
+ S_ISREG(st.st_mode))
+ it = ref;
+ else
+ continue;
+ if (!logs_found++) {
+ *log = xstrdup(it);
+ hashcpy(sha1, hash);
+ }
+ if (!warn_ambiguous_refs)
+ break;
+ }
+ free(last_branch);
+ return logs_found;
+}
+
static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int flags, int *type_p)
{
char *ref_file;
int rename_ref(const char *oldref, const char *newref, const char *logmsg)
{
- static const char renamed_ref[] = "RENAMED-REF";
unsigned char sha1[20], orig_sha1[20];
int flag = 0, logmoved = 0;
struct ref_lock *lock;
if (!is_refname_available(newref, oldref, get_loose_refs(NULL), 0))
return 1;
- lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);
- if (!lock)
- return error("unable to lock %s", renamed_ref);
- lock->force_write = 1;
- if (write_ref_sha1(lock, orig_sha1, logmsg))
- return error("unable to save current sha1 in %s", renamed_ref);
-
if (log && rename(git_path("logs/%s", oldref), git_path(TMP_RENAMED_LOG)))
return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
oldref, strerror(errno));