Code

setup: document prefix
[git.git] / refs.c
diff --git a/refs.c b/refs.c
index 9c12f5ea8c92452d892f5b7ce70757e2114d338f..d3db15a76cc46f6f6a31d4448816c09e6c48e543 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -289,6 +289,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
 }
 
 struct warn_if_dangling_data {
+       FILE *fp;
        const char *refname;
        const char *msg_fmt;
 };
@@ -307,13 +308,13 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
        if (!resolves_to || strcmp(resolves_to, d->refname))
                return 0;
 
-       printf(d->msg_fmt, refname);
+       fprintf(d->fp, d->msg_fmt, refname);
        return 0;
 }
 
-void warn_dangling_symref(const char *msg_fmt, const char *refname)
+void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
 {
-       struct warn_if_dangling_data data = { refname, msg_fmt };
+       struct warn_if_dangling_data data = { fp, refname, msg_fmt };
        for_each_rawref(warn_if_dangling_symref, &data);
 }
 
@@ -521,6 +522,13 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
        return ref;
 }
 
+/* The argument to filter_refs */
+struct ref_filter {
+       const char *pattern;
+       each_ref_fn *fn;
+       void *cb_data;
+};
+
 int read_ref(const char *ref, unsigned char *sha1)
 {
        if (resolve_ref(ref, sha1, 1, NULL))
@@ -547,6 +555,15 @@ 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);
 }
 
+static int filter_refs(const char *ref, const unsigned char *sha, int flags,
+       void *data)
+{
+       struct ref_filter *filter = (struct ref_filter *)data;
+       if (fnmatch(filter->pattern, ref, 0))
+               return 0;
+       return filter->fn(ref, sha, flags, filter->cb_data);
+}
+
 int peel_ref(const char *ref, unsigned char *sha1)
 {
        int flag;
@@ -671,6 +688,46 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data)
        return for_each_ref_in("refs/remotes/", fn, cb_data);
 }
 
+int for_each_replace_ref(each_ref_fn fn, void *cb_data)
+{
+       return do_for_each_ref("refs/replace/", fn, 13, 0, cb_data);
+}
+
+int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
+       const char *prefix, void *cb_data)
+{
+       struct strbuf real_pattern = STRBUF_INIT;
+       struct ref_filter filter;
+       int ret;
+
+       if (!prefix && prefixcmp(pattern, "refs/"))
+               strbuf_addstr(&real_pattern, "refs/");
+       else if (prefix)
+               strbuf_addstr(&real_pattern, prefix);
+       strbuf_addstr(&real_pattern, pattern);
+
+       if (!has_glob_specials(pattern)) {
+               /* Append implied '/' '*' if not present. */
+               if (real_pattern.buf[real_pattern.len - 1] != '/')
+                       strbuf_addch(&real_pattern, '/');
+               /* No need to check for '*', there is none. */
+               strbuf_addch(&real_pattern, '*');
+       }
+
+       filter.pattern = real_pattern.buf;
+       filter.fn = fn;
+       filter.cb_data = cb_data;
+       ret = for_each_ref(filter_refs, &filter);
+
+       strbuf_release(&real_pattern);
+       return ret;
+}
+
+int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
+{
+       return for_each_glob_ref_in(fn, pattern, NULL, cb_data);
+}
+
 int for_each_rawref(each_ref_fn fn, void *cb_data)
 {
        return do_for_each_ref("refs/", fn, 0,
@@ -686,12 +743,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
  * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
  * - it ends with a "/".
  * - it ends with ".lock"
+ * - it contains a "\" (backslash)
  */
 
 static inline int bad_ref_char(int ch)
 {
        if (((unsigned) ch) <= ' ' ||
-           ch == '~' || ch == '^' || ch == ':')
+           ch == '~' || ch == '^' || ch == ':' || ch == '\\')
                return 1;
        /* 2.13 Pattern Matching Notation */
        if (ch == '?' || ch == '[') /* Unsupported */
@@ -754,9 +812,8 @@ int check_ref_format(const char *ref)
        }
 }
 
-const char *prettify_ref(const struct ref *ref)
+const char *prettify_refname(const char *name)
 {
-       const char *name = ref->name;
        return name + (
                !prefixcmp(name, "refs/heads/") ? 11 :
                !prefixcmp(name, "refs/tags/") ? 10 :
@@ -824,7 +881,7 @@ static int remove_empty_directories(const char *file)
        strbuf_init(&path, 20);
        strbuf_addstr(&path, file);
 
-       result = remove_dir_recursively(&path, 1);
+       result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
 
        strbuf_release(&path);
 
@@ -970,8 +1027,10 @@ static int repack_without_ref(const char *refname)
        if (!found)
                return 0;
        fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
-       if (fd < 0)
+       if (fd < 0) {
+               unable_to_lock_error(git_path("packed-refs"), errno);
                return error("cannot delete '%s' from packed refs", refname);
+       }
 
        for (list = packed_ref_list; list; list = list->next) {
                char line[PATH_MAX + 100];
@@ -1217,6 +1276,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
        if (log_all_ref_updates &&
            (!prefixcmp(ref_name, "refs/heads/") ||
             !prefixcmp(ref_name, "refs/remotes/") ||
+            !prefixcmp(ref_name, "refs/notes/") ||
             !strcmp(ref_name, "HEAD"))) {
                if (safe_create_leading_directories(log_file) < 0)
                        return error("unable to create directory for %s",
@@ -1422,7 +1482,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
        logfile = git_path("logs/%s", ref);
        logfd = open(logfile, O_RDONLY, 0);
        if (logfd < 0)
-               die("Unable to read log %s: %s", logfile, strerror(errno));
+               die_errno("Unable to read log '%s'", logfile);
        fstat(logfd, &st);
        if (!st.st_size)
                die("Log %s is empty.", logfile);
@@ -1516,7 +1576,7 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
 {
        const char *logfile;
        FILE *logfp;
-       char buf[1024];
+       struct strbuf sb = STRBUF_INIT;
        int ret = 0;
 
        logfile = git_path("logs/%s", ref);
@@ -1529,24 +1589,24 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
                if (fstat(fileno(logfp), &statbuf) ||
                    statbuf.st_size < ofs ||
                    fseek(logfp, -ofs, SEEK_END) ||
-                   fgets(buf, sizeof(buf), logfp)) {
+                   strbuf_getwholeline(&sb, logfp, '\n')) {
                        fclose(logfp);
+                       strbuf_release(&sb);
                        return -1;
                }
        }
 
-       while (fgets(buf, sizeof(buf), logfp)) {
+       while (!strbuf_getwholeline(&sb, logfp, '\n')) {
                unsigned char osha1[20], nsha1[20];
                char *email_end, *message;
                unsigned long timestamp;
-               int len, tz;
+               int tz;
 
                /* old SP new SP name <email> SP time TAB msg LF */
-               len = strlen(buf);
-               if (len < 83 || buf[len-1] != '\n' ||
-                   get_sha1_hex(buf, osha1) || buf[40] != ' ' ||
-                   get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ' ||
-                   !(email_end = strchr(buf + 82, '>')) ||
+               if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' ||
+                   get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' ||
+                   get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' ||
+                   !(email_end = strchr(sb.buf + 82, '>')) ||
                    email_end[1] != ' ' ||
                    !(timestamp = strtoul(email_end + 2, &message, 10)) ||
                    !message || message[0] != ' ' ||
@@ -1560,11 +1620,13 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
                        message += 6;
                else
                        message += 7;
-               ret = fn(osha1, nsha1, buf+82, timestamp, tz, message, cb_data);
+               ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message,
+                        cb_data);
                if (ret)
                        break;
        }
        fclose(logfp);
+       strbuf_release(&sb);
        return ret;
 }