summaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--refs.c36
-rw-r--r--refs.h8
-rw-r--r--refs/files-backend.c49
-rw-r--r--refs/packed-backend.c16
-rw-r--r--refs/packed-backend.h2
-rw-r--r--refs/ref-cache.c2
-rw-r--r--refs/ref-cache.h3
-rw-r--r--refs/refs-internal.h4
8 files changed, 97 insertions, 23 deletions
diff --git a/refs.c b/refs.c
index 9a318c8456..f9936355cd 100644
--- a/refs.c
+++ b/refs.c
@@ -217,6 +217,7 @@ char *resolve_refdup(const char *refname, int resolve_flags,
/* The argument to filter_refs */
struct ref_filter {
const char *pattern;
+ const char *prefix;
each_ref_fn *fn;
void *cb_data;
};
@@ -296,6 +297,8 @@ static int filter_refs(const char *refname, const struct object_id *oid,
if (wildmatch(filter->pattern, refname, 0))
return 0;
+ if (filter->prefix)
+ skip_prefix(refname, filter->prefix, &refname);
return filter->fn(refname, oid, flags, filter->cb_data);
}
@@ -458,6 +461,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
}
filter.pattern = real_pattern.buf;
+ filter.prefix = prefix;
filter.fn = fn;
filter.cb_data = cb_data;
ret = for_each_ref(filter_refs, &filter);
@@ -624,6 +628,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
static int is_per_worktree_ref(const char *refname)
{
return !strcmp(refname, "HEAD") ||
+ starts_with(refname, "refs/worktree/") ||
starts_with(refname, "refs/bisect/") ||
starts_with(refname, "refs/rewritten/");
}
@@ -640,13 +645,34 @@ static int is_pseudoref_syntax(const char *refname)
return 1;
}
+static int is_main_pseudoref_syntax(const char *refname)
+{
+ return skip_prefix(refname, "main-worktree/", &refname) &&
+ *refname &&
+ is_pseudoref_syntax(refname);
+}
+
+static int is_other_pseudoref_syntax(const char *refname)
+{
+ if (!skip_prefix(refname, "worktrees/", &refname))
+ return 0;
+ refname = strchr(refname, '/');
+ if (!refname || !refname[1])
+ return 0;
+ return is_pseudoref_syntax(refname + 1);
+}
+
enum ref_type ref_type(const char *refname)
{
if (is_per_worktree_ref(refname))
return REF_TYPE_PER_WORKTREE;
if (is_pseudoref_syntax(refname))
return REF_TYPE_PSEUDOREF;
- return REF_TYPE_NORMAL;
+ if (is_main_pseudoref_syntax(refname))
+ return REF_TYPE_MAIN_PSEUDOREF;
+ if (is_other_pseudoref_syntax(refname))
+ return REF_TYPE_OTHER_PSEUDOREF;
+ return REF_TYPE_NORMAL;
}
long get_files_ref_lock_timeout_ms(void)
@@ -702,7 +728,7 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
pseudoref);
rollback_lock_file(&lock);
goto done;
- } else if (oidcmp(&actual_old_oid, old_oid)) {
+ } else if (!oideq(&actual_old_oid, old_oid)) {
strbuf_addf(err, _("unexpected object ID when writing '%s'"),
pseudoref);
rollback_lock_file(&lock);
@@ -744,7 +770,7 @@ static int delete_pseudoref(const char *pseudoref, const struct object_id *old_o
}
if (read_ref(pseudoref, &actual_old_oid))
die(_("could not read ref '%s'"), pseudoref);
- if (oidcmp(&actual_old_oid, old_oid)) {
+ if (!oideq(&actual_old_oid, old_oid)) {
error(_("unexpected object ID when deleting '%s'"),
pseudoref);
rollback_lock_file(&lock);
@@ -875,13 +901,13 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
*/
if (!is_null_oid(&cb->ooid)) {
oidcpy(cb->oid, noid);
- if (oidcmp(&cb->ooid, noid))
+ if (!oideq(&cb->ooid, noid))
warning(_("log for ref %s has gap after %s"),
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
}
else if (cb->date == cb->at_time)
oidcpy(cb->oid, noid);
- else if (oidcmp(noid, cb->oid))
+ else if (!oideq(noid, cb->oid))
warning(_("log for ref %s unexpectedly ended on %s"),
cb->refname, show_date(cb->date, cb->tz,
DATE_MODE(RFC2822)));
diff --git a/refs.h b/refs.h
index 6cc0397679..308fa1f03b 100644
--- a/refs.h
+++ b/refs.h
@@ -714,9 +714,11 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
int ref_is_hidden(const char *, const char *);
enum ref_type {
- REF_TYPE_PER_WORKTREE,
- REF_TYPE_PSEUDOREF,
- REF_TYPE_NORMAL,
+ REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */
+ REF_TYPE_PSEUDOREF, /* refs outside refs/ in current worktree */
+ REF_TYPE_MAIN_PSEUDOREF, /* pseudo refs from the main worktree */
+ REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees */
+ REF_TYPE_NORMAL, /* normal/shared refs inside refs/ */
};
enum ref_type ref_type(const char *refname);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 1f1a98e4cb..dd8abe9185 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -10,6 +10,7 @@
#include "../object.h"
#include "../dir.h"
#include "../chdir-notify.h"
+#include "worktree.h"
/*
* This backend uses the following flags in `ref_update::flags` for
@@ -149,6 +150,25 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
+static void files_reflog_path_other_worktrees(struct files_ref_store *refs,
+ struct strbuf *sb,
+ const char *refname)
+{
+ const char *real_ref;
+ const char *worktree_name;
+ int length;
+
+ if (parse_worktree_ref(refname, &worktree_name, &length, &real_ref))
+ BUG("refname %s is not a other-worktree ref", refname);
+
+ if (worktree_name)
+ strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
+ length, worktree_name, real_ref);
+ else
+ strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir,
+ real_ref);
+}
+
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@@ -158,6 +178,10 @@ static void files_reflog_path(struct files_ref_store *refs,
case REF_TYPE_PSEUDOREF:
strbuf_addf(sb, "%s/logs/%s", refs->gitdir, refname);
break;
+ case REF_TYPE_OTHER_PSEUDOREF:
+ case REF_TYPE_MAIN_PSEUDOREF:
+ files_reflog_path_other_worktrees(refs, sb, refname);
+ break;
case REF_TYPE_NORMAL:
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
break;
@@ -176,6 +200,11 @@ static void files_ref_path(struct files_ref_store *refs,
case REF_TYPE_PSEUDOREF:
strbuf_addf(sb, "%s/%s", refs->gitdir, refname);
break;
+ case REF_TYPE_MAIN_PSEUDOREF:
+ if (!skip_prefix(refname, "main-worktree/", &refname))
+ BUG("ref %s is not a main pseudoref", refname);
+ /* fallthrough */
+ case REF_TYPE_OTHER_PSEUDOREF:
case REF_TYPE_NORMAL:
strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
break;
@@ -269,9 +298,9 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
closedir(d);
/*
- * Manually add refs/bisect, which, being per-worktree, might
- * not appear in the directory listing for refs/ in the main
- * repo.
+ * Manually add refs/bisect and refs/worktree, which, being
+ * per-worktree, might not appear in the directory listing for
+ * refs/ in the main repo.
*/
if (!strcmp(dirname, "refs/")) {
int pos = search_ref_dir(dir, "refs/bisect/", 12);
@@ -281,6 +310,14 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
dir->cache, "refs/bisect/", 12, 1);
add_entry_to_dir(dir, child_entry);
}
+
+ pos = search_ref_dir(dir, "refs/worktree/", 11);
+
+ if (pos < 0) {
+ struct ref_entry *child_entry = create_dir_entry(
+ dir->cache, "refs/worktree/", 11, 1);
+ add_entry_to_dir(dir, child_entry);
+ }
}
}
@@ -841,7 +878,7 @@ static int verify_lock(struct ref_store *ref_store, struct ref_lock *lock,
return 0;
}
}
- if (old_oid && oidcmp(&lock->old_oid, old_oid)) {
+ if (old_oid && !oideq(&lock->old_oid, old_oid)) {
strbuf_addf(err, "ref '%s' is at %s but expected %s",
lock->ref_name,
oid_to_hex(&lock->old_oid),
@@ -2307,7 +2344,7 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
struct strbuf *err)
{
if (!(update->flags & REF_HAVE_OLD) ||
- !oidcmp(oid, &update->old_oid))
+ oideq(oid, &update->old_oid))
return 0;
if (is_null_oid(&update->old_oid))
@@ -2443,7 +2480,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
!(update->flags & REF_DELETING) &&
!(update->flags & REF_LOG_ONLY)) {
if (!(update->type & REF_ISSYMREF) &&
- !oidcmp(&lock->old_oid, &update->new_oid)) {
+ oideq(&lock->old_oid, &update->new_oid)) {
/*
* The reference already has the desired
* value, so we don't need to write it.
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index d447a731da..c01c7f5901 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -274,8 +274,8 @@ struct snapshot_record {
static int cmp_packed_ref_records(const void *v1, const void *v2)
{
const struct snapshot_record *e1 = v1, *e2 = v2;
- const char *r1 = e1->start + GIT_SHA1_HEXSZ + 1;
- const char *r2 = e2->start + GIT_SHA1_HEXSZ + 1;
+ const char *r1 = e1->start + the_hash_algo->hexsz + 1;
+ const char *r2 = e2->start + the_hash_algo->hexsz + 1;
while (1) {
if (*r1 == '\n')
@@ -297,7 +297,7 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)
*/
static int cmp_record_to_refname(const char *rec, const char *refname)
{
- const char *r1 = rec + GIT_SHA1_HEXSZ + 1;
+ const char *r1 = rec + the_hash_algo->hexsz + 1;
const char *r2 = refname;
while (1) {
@@ -344,7 +344,7 @@ static void sort_snapshot(struct snapshot *snapshot)
if (!eol)
/* The safety check should prevent this. */
BUG("unterminated line found in packed-refs");
- if (eol - pos < GIT_SHA1_HEXSZ + 2)
+ if (eol - pos < the_hash_algo->hexsz + 2)
die_invalid_line(snapshot->refs->path,
pos, eof - pos);
eol++;
@@ -456,7 +456,7 @@ static void verify_buffer_safe(struct snapshot *snapshot)
return;
last_line = find_start_of_record(start, eof - 1);
- if (*(eof - 1) != '\n' || eof - last_line < GIT_SHA1_HEXSZ + 2)
+ if (*(eof - 1) != '\n' || eof - last_line < the_hash_algo->hexsz + 2)
die_invalid_line(snapshot->refs->path,
last_line, eof - last_line);
}
@@ -796,7 +796,7 @@ static int next_record(struct packed_ref_iterator *iter)
iter->base.flags = REF_ISPACKED;
- if (iter->eof - p < GIT_SHA1_HEXSZ + 2 ||
+ if (iter->eof - p < the_hash_algo->hexsz + 2 ||
parse_oid_hex(p, &iter->oid, &p) ||
!isspace(*p++))
die_invalid_line(iter->snapshot->refs->path,
@@ -826,7 +826,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->pos < iter->eof && *iter->pos == '^') {
p = iter->pos + 1;
- if (iter->eof - p < GIT_SHA1_HEXSZ + 1 ||
+ if (iter->eof - p < the_hash_algo->hexsz + 1 ||
parse_oid_hex(p, &iter->peeled, &p) ||
*p++ != '\n')
die_invalid_line(iter->snapshot->refs->path,
@@ -1160,7 +1160,7 @@ static int write_with_updates(struct packed_ref_store *refs,
"reference already exists",
update->refname);
goto error;
- } else if (oidcmp(&update->old_oid, iter->oid)) {
+ } else if (!oideq(&update->old_oid, iter->oid)) {
strbuf_addf(err, "cannot update ref '%s': "
"is at %s but expected %s",
update->refname,
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 640245d3b9..a01a0aff9c 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -1,6 +1,8 @@
#ifndef REFS_PACKED_BACKEND_H
#define REFS_PACKED_BACKEND_H
+struct ref_transaction;
+
/*
* Support for storing references in a `packed-refs` file.
*
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 9b110c8494..b7052f72e2 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -272,7 +272,7 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2
/* This is impossible by construction */
die("Reference directory conflict: %s", ref1->name);
- if (oidcmp(&ref1->u.value.oid, &ref2->u.value.oid))
+ if (!oideq(&ref1->u.value.oid, &ref2->u.value.oid))
die("Duplicated ref, and SHA1s don't match: %s", ref1->name);
warning("Duplicated ref: %s", ref1->name);
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index eda65e73ed..3bfb89d2b3 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,7 +1,10 @@
#ifndef REFS_REF_CACHE_H
#define REFS_REF_CACHE_H
+#include "cache.h"
+
struct ref_dir;
+struct ref_store;
/*
* If this ref_cache is filled lazily, this function is used to load
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index b425ae40b1..f2d8c0123a 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -1,8 +1,12 @@
#ifndef REFS_REFS_INTERNAL_H
#define REFS_REFS_INTERNAL_H
+#include "cache.h"
+#include "refs.h"
#include "iterator.h"
+struct ref_transaction;
+
/*
* Data structures and functions for the internal use of the refs
* module. Code outside of the refs module should use only the public