summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2015-08-03 18:01:17 (GMT)
committerJunio C Hamano <gitster@pobox.com>2015-08-03 18:01:17 (GMT)
commitbe9cb560e31c76c00760dadb151b5e3059970586 (patch)
tree434003cf022bccf7f1a1dfecfb77305214defe32
parent5f02274e4c4506b923b510a24da7991656f4db14 (diff)
parent1c03c4d34771db20b78231359caa6fda28e2d9fe (diff)
downloadgit-be9cb560e31c76c00760dadb151b5e3059970586.zip
git-be9cb560e31c76c00760dadb151b5e3059970586.tar.gz
git-be9cb560e31c76c00760dadb151b5e3059970586.tar.bz2
Merge branch 'mh/init-delete-refs-api'
Clean up refs API and make "git clone" less intimate with the implementation detail. * mh/init-delete-refs-api: delete_ref(): use the usual convention for old_sha1 cmd_update_ref(): make logic more straightforward update_ref(): don't read old reference value before delete check_branch_commit(): make first parameter const refs.h: add some parameter names to function declarations refs: move the remaining ref module declarations to refs.h initial_ref_transaction_commit(): check for ref D/F conflicts initial_ref_transaction_commit(): check for duplicate refs refs: remove some functions from the module's public interface initial_ref_transaction_commit(): function for initial ref creation repack_without_refs(): make function private prune_refs(): use delete_refs() prune_remote(): use delete_refs() delete_refs(): bail early if the packed-refs file cannot be rewritten delete_refs(): make error message more generic delete_refs(): new function for the refs API delete_ref(): handle special case more explicitly remove_branches(): remove temporary delete_ref(): move declaration to refs.h
-rw-r--r--archive.c1
-rw-r--r--builtin/blame.c1
-rw-r--r--builtin/branch.c5
-rw-r--r--builtin/clone.c18
-rw-r--r--builtin/fast-export.c1
-rw-r--r--builtin/fetch.c25
-rw-r--r--builtin/fmt-merge-msg.c1
-rw-r--r--builtin/init-db.c1
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/remote.c33
-rw-r--r--builtin/update-ref.c21
-rw-r--r--cache.h68
-rw-r--r--fast-import.c6
-rw-r--r--refs.c182
-rw-r--r--refs.h211
-rw-r--r--remote-testsvn.c1
16 files changed, 371 insertions, 205 deletions
diff --git a/archive.c b/archive.c
index d37c41d..936a594 100644
--- a/archive.c
+++ b/archive.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "refs.h"
#include "commit.h"
#include "tree-walk.h"
#include "attr.h"
diff --git a/builtin/blame.c b/builtin/blame.c
index a22ac17..272a222 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -6,6 +6,7 @@
*/
#include "cache.h"
+#include "refs.h"
#include "builtin.h"
#include "blob.h"
#include "commit.h"
diff --git a/builtin/branch.c b/builtin/branch.c
index b42e5b6..58aa84f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -160,7 +160,7 @@ static int branch_merged(int kind, const char *name,
}
static int check_branch_commit(const char *branchname, const char *refname,
- unsigned char *sha1, struct commit *head_rev,
+ const unsigned char *sha1, struct commit *head_rev,
int kinds, int force)
{
struct commit *rev = lookup_commit_reference(sha1);
@@ -253,7 +253,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
continue;
}
- if (delete_ref(name, sha1, REF_NODEREF)) {
+ if (delete_ref(name, is_null_sha1(sha1) ? NULL : sha1,
+ REF_NODEREF)) {
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
diff --git a/builtin/clone.c b/builtin/clone.c
index a72ff7e..303a3a7 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -484,16 +484,26 @@ static void write_remote_refs(const struct ref *local_refs)
{
const struct ref *r;
- lock_packed_refs(LOCK_DIE_ON_ERROR);
+ struct ref_transaction *t;
+ struct strbuf err = STRBUF_INIT;
+
+ t = ref_transaction_begin(&err);
+ if (!t)
+ die("%s", err.buf);
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
- add_packed_ref(r->peer_ref->name, r->old_sha1);
+ if (ref_transaction_create(t, r->peer_ref->name, r->old_sha1,
+ 0, NULL, &err))
+ die("%s", err.buf);
}
- if (commit_packed_refs())
- die_errno("unable to overwrite old ref-pack file");
+ if (initial_ref_transaction_commit(t, &err))
+ die("%s", err.buf);
+
+ strbuf_release(&err);
+ ref_transaction_free(t);
}
static void write_followtags(const struct ref *refs, const char *msg)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b8182c2..d23f3be 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -5,6 +5,7 @@
*/
#include "builtin.h"
#include "cache.h"
+#include "refs.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8d5b2db..34b6f5e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -790,20 +790,29 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
if (4 < i && !strncmp(".git", url + i - 3, 4))
url_len = i - 3;
- for (ref = stale_refs; ref; ref = ref->next) {
- if (!dry_run)
- result |= delete_ref(ref->name, NULL, 0);
- if (verbosity >= 0 && !shown_url) {
- fprintf(stderr, _("From %.*s\n"), url_len, url);
- shown_url = 1;
- }
- if (verbosity >= 0) {
+ if (!dry_run) {
+ struct string_list refnames = STRING_LIST_INIT_NODUP;
+
+ for (ref = stale_refs; ref; ref = ref->next)
+ string_list_append(&refnames, ref->name);
+
+ result = delete_refs(&refnames);
+ string_list_clear(&refnames, 0);
+ }
+
+ if (verbosity >= 0) {
+ for (ref = stale_refs; ref; ref = ref->next) {
+ if (!shown_url) {
+ fprintf(stderr, _("From %.*s\n"), url_len, url);
+ shown_url = 1;
+ }
fprintf(stderr, " x %-*s %-*s -> %s\n",
TRANSPORT_SUMMARY(_("[deleted]")),
REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
+
free(url);
free_refs(stale_refs);
return result;
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 05f4c26..4ba7f28 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "cache.h"
+#include "refs.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 4335738..49df78d 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -4,6 +4,7 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
+#include "refs.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
diff --git a/builtin/log.c b/builtin/log.c
index 8781049..93025d0 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -5,6 +5,7 @@
* 2006 Junio Hamano
*/
#include "cache.h"
+#include "refs.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
diff --git a/builtin/remote.c b/builtin/remote.c
index f4a6ec9..cc3c741 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -746,26 +746,6 @@ static int mv(int argc, const char **argv)
return 0;
}
-static int remove_branches(struct string_list *branches)
-{
- struct strbuf err = STRBUF_INIT;
- int i, result = 0;
-
- if (repack_without_refs(branches, &err))
- result |= error("%s", err.buf);
- strbuf_release(&err);
-
- for (i = 0; i < branches->nr; i++) {
- struct string_list_item *item = branches->items + i;
- const char *refname = item->string;
-
- if (delete_ref(refname, NULL, 0))
- result |= error(_("Could not remove branch %s"), refname);
- }
-
- return result;
-}
-
static int rm(int argc, const char **argv)
{
struct option options[] = {
@@ -822,7 +802,7 @@ static int rm(int argc, const char **argv)
strbuf_release(&buf);
if (!result)
- result = remove_branches(&branches);
+ result = delete_refs(&branches);
string_list_clear(&branches, 0);
if (skipped.nr) {
@@ -1334,19 +1314,12 @@ static int prune_remote(const char *remote, int dry_run)
string_list_append(&refs_to_prune, item->util);
string_list_sort(&refs_to_prune);
- if (!dry_run) {
- struct strbuf err = STRBUF_INIT;
- if (repack_without_refs(&refs_to_prune, &err))
- result |= error("%s", err.buf);
- strbuf_release(&err);
- }
+ if (!dry_run)
+ result |= delete_refs(&refs_to_prune);
for_each_string_list_item(item, &states.stale) {
const char *refname = item->util;
- if (!dry_run)
- result |= delete_ref(refname, NULL, 0);
-
if (dry_run)
printf_ln(_(" * [would prune] %s"),
abbrev_ref(refname, "refs/remotes/"));
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 3d79a46..6763cf1 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -408,14 +408,27 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
die("%s: not a valid SHA1", value);
}
- hashclr(oldsha1); /* all-zero hash in case oldval is the empty string */
- if (oldval && *oldval && get_sha1(oldval, oldsha1))
- die("%s: not a valid old SHA1", oldval);
+ if (oldval) {
+ if (!*oldval)
+ /*
+ * The empty string implies that the reference
+ * must not already exist:
+ */
+ hashclr(oldsha1);
+ else if (get_sha1(oldval, oldsha1))
+ die("%s: not a valid old SHA1", oldval);
+ }
if (no_deref)
flags = REF_NODEREF;
if (delete)
- return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
+ /*
+ * For purposes of backwards compatibility, we treat
+ * NULL_SHA1 as "don't care" here:
+ */
+ return delete_ref(refname,
+ (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
+ flags);
else
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
flags, UPDATE_REFS_DIE_ON_ERR);
diff --git a/cache.h b/cache.h
index dcc9d3f..6997b2c 100644
--- a/cache.h
+++ b/cache.h
@@ -596,8 +596,6 @@ extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
extern void set_alternate_index_output(const char *);
-extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
-
/* Environment bits from configuration mechanism */
extern int trust_executable_bit;
extern int trust_ctime;
@@ -1032,76 +1030,10 @@ extern int get_oid_hex(const char *hex, struct object_id *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
-extern int read_ref_full(const char *refname, int resolve_flags,
- unsigned char *sha1, int *flags);
-extern int read_ref(const char *refname, unsigned char *sha1);
-/*
- * Resolve a reference, recursively following symbolic refererences.
- *
- * Store the referred-to object's name in sha1 and return the name of
- * the non-symbolic reference that ultimately pointed at it. The
- * return value, if not NULL, is a pointer into either a static buffer
- * or the input ref.
- *
- * If the reference cannot be resolved to an object, the behavior
- * depends on the RESOLVE_REF_READING flag:
- *
- * - If RESOLVE_REF_READING is set, return NULL.
- *
- * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
- * the last reference name in the chain, which will either be a non-symbolic
- * reference or an undefined reference. If this is a prelude to
- * "writing" to the ref, the return value is the name of the ref
- * that will actually be created or changed.
- *
- * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
- * level of symbolic reference. The value stored in sha1 for a symbolic
- * reference will always be null_sha1 in this case, and the return
- * value is the reference that the symref refers to directly.
- *
- * If flags is non-NULL, set the value that it points to the
- * combination of REF_ISPACKED (if the reference was found among the
- * packed references), REF_ISSYMREF (if the initial reference was a
- * symbolic reference), REF_BAD_NAME (if the reference name is ill
- * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
- * (if the ref is malformed or has a bad name). See refs.h for more detail
- * on each flag.
- *
- * If ref is not a properly-formatted, normalized reference, return
- * NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
- * give up and return NULL.
- *
- * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
- * name is invalid according to git-check-ref-format(1). If the name
- * is bad then the value stored in sha1 will be null_sha1 and the two
- * flags REF_ISBROKEN and REF_BAD_NAME will be set.
- *
- * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
- * directory and do not consist of all caps and underscores cannot be
- * resolved. The function returns NULL for such ref names.
- * Caps and underscores refers to the special refs, such as HEAD,
- * FETCH_HEAD and friends, that all live outside of the refs/ directory.
- */
-#define RESOLVE_REF_READING 0x01
-#define RESOLVE_REF_NO_RECURSE 0x02
-#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
-extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
-extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
-
-extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
-extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
extern int interpret_branch_name(const char *str, int len, struct strbuf *);
extern int get_sha1_mb(const char *str, unsigned char *sha1);
-/*
- * Return true iff abbrev_name is a possible abbreviation for
- * full_name according to the rules defined by ref_rev_parse_rules in
- * refs.c.
- */
-extern int refname_match(const char *abbrev_name, const char *full_name);
-
-extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
diff --git a/fast-import.c b/fast-import.c
index 6378726..d7ed065 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1692,13 +1692,13 @@ static int update_branch(struct branch *b)
unsigned char old_sha1[20];
struct strbuf err = STRBUF_INIT;
- if (read_ref(b->name, old_sha1))
- hashclr(old_sha1);
if (is_null_sha1(b->sha1)) {
if (b->delete)
- delete_ref(b->name, old_sha1, 0);
+ delete_ref(b->name, NULL, 0);
return 0;
}
+ if (read_ref(b->name, old_sha1))
+ hashclr(old_sha1);
if (!force_update && !is_null_sha1(old_sha1)) {
struct commit *old_cmit, *new_cmit;
diff --git a/refs.c b/refs.c
index 227cb50..fb568d7 100644
--- a/refs.c
+++ b/refs.c
@@ -1314,7 +1314,13 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
return get_packed_ref_dir(get_packed_ref_cache(refs));
}
-void add_packed_ref(const char *refname, const unsigned char *sha1)
+/*
+ * Add a reference to the in-memory packed reference cache. This may
+ * only be called while the packed-refs file is locked (see
+ * lock_packed_refs()). To actually write the packed-refs file, call
+ * commit_packed_refs().
+ */
+static void add_packed_ref(const char *refname, const unsigned char *sha1)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
@@ -1741,9 +1747,11 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
return ret;
}
-char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
+char *resolve_refdup(const char *refname, int resolve_flags,
+ unsigned char *sha1, int *flags)
{
- return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
+ return xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,
+ sha1, flags));
}
/* The argument to filter_refs */
@@ -2531,8 +2539,12 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
return 0;
}
-/* This should return a meaningful errno on failure */
-int lock_packed_refs(int flags)
+/*
+ * Lock the packed-refs file for writing. Flags is passed to
+ * hold_lock_file_for_update(). Return 0 on success. On errors, set
+ * errno appropriately and return a nonzero value.
+ */
+static int lock_packed_refs(int flags)
{
static int timeout_configured = 0;
static int timeout_value = 1000;
@@ -2562,10 +2574,12 @@ int lock_packed_refs(int flags)
}
/*
- * Commit the packed refs changes.
- * On error we must make sure that errno contains a meaningful value.
+ * Write the current version of the packed refs cache from memory to
+ * disk. The packed-refs file must already be locked for writing (see
+ * lock_packed_refs()). Return zero on success. On errors, set errno
+ * and return a nonzero value
*/
-int commit_packed_refs(void)
+static int commit_packed_refs(void)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
@@ -2594,7 +2608,12 @@ int commit_packed_refs(void)
return error;
}
-void rollback_packed_refs(void)
+/*
+ * Rollback the lockfile for the packed-refs file, and discard the
+ * in-memory packed reference cache. (The packed-refs file will be
+ * read anew if it is needed again after this function is called.)
+ */
+static void rollback_packed_refs(void)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
@@ -2752,7 +2771,14 @@ int pack_refs(unsigned int flags)
return 0;
}
-int repack_without_refs(struct string_list *refnames, struct strbuf *err)
+/*
+ * Rewrite the packed-refs file, omitting any refs listed in
+ * 'refnames'. On error, leave packed-refs unchanged, write an error
+ * message to 'err', and return a nonzero value.
+ *
+ * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
+ */
+static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
{
struct ref_dir *packed;
struct string_list_item *refname;
@@ -2817,15 +2843,15 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
return 0;
}
-int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
+int delete_ref(const char *refname, const unsigned char *old_sha1,
+ unsigned int flags)
{
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_delete(transaction, refname,
- (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL,
+ ref_transaction_delete(transaction, refname, old_sha1,
flags, NULL, &err) ||
ref_transaction_commit(transaction, &err)) {
error("%s", err.buf);
@@ -2838,6 +2864,44 @@ int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flag
return 0;
}
+int delete_refs(struct string_list *refnames)
+{
+ struct strbuf err = STRBUF_INIT;
+ int i, result = 0;
+
+ if (!refnames->nr)
+ return 0;
+
+ result = repack_without_refs(refnames, &err);
+ if (result) {
+ /*
+ * If we failed to rewrite the packed-refs file, then
+ * it is unsafe to try to remove loose refs, because
+ * doing so might expose an obsolete packed value for
+ * a reference that might even point at an object that
+ * has been garbage collected.
+ */
+ if (refnames->nr == 1)
+ error(_("could not delete reference %s: %s"),
+ refnames->items[0].string, err.buf);
+ else
+ error(_("could not delete references: %s"), err.buf);
+
+ goto out;
+ }
+
+ for (i = 0; i < refnames->nr; i++) {
+ const char *refname = refnames->items[i].string;
+
+ if (delete_ref(refname, NULL, 0))
+ result |= error(_("could not remove reference %s"), refname);
+ }
+
+out:
+ strbuf_release(&err);
+ return result;
+}
+
/*
* People using contrib's git-new-workdir have .git/logs/refs ->
* /some/other/path/.git/logs/refs, and that may live on another device.
@@ -4039,6 +4103,98 @@ cleanup:
return ret;
}
+static int ref_present(const char *refname,
+ const struct object_id *oid, int flags, void *cb_data)
+{
+ struct string_list *affected_refnames = cb_data;
+
+ return string_list_has_string(affected_refnames, refname);
+}
+
+int initial_ref_transaction_commit(struct ref_transaction *transaction,
+ struct strbuf *err)
+{
+ struct ref_dir *loose_refs = get_loose_refs(&ref_cache);
+ struct ref_dir *packed_refs = get_packed_refs(&ref_cache);
+ int ret = 0, i;
+ int n = transaction->nr;
+ struct ref_update **updates = transaction->updates;
+ struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
+
+ assert(err);
+
+ if (transaction->state != REF_TRANSACTION_OPEN)
+ die("BUG: commit called for transaction that is not open");
+
+ /* Fail if a refname appears more than once in the transaction: */
+ for (i = 0; i < n; i++)
+ string_list_append(&affected_refnames, updates[i]->refname);
+ string_list_sort(&affected_refnames);
+ if (ref_update_reject_duplicates(&affected_refnames, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * It's really undefined to call this function in an active
+ * repository or when there are existing references: we are
+ * only locking and changing packed-refs, so (1) any
+ * simultaneous processes might try to change a reference at
+ * the same time we do, and (2) any existing loose versions of
+ * the references that we are setting would have precedence
+ * over our values. But some remote helpers create the remote
+ * "HEAD" and "master" branches before calling this function,
+ * so here we really only check that none of the references
+ * that we are creating already exists.
+ */
+ if (for_each_rawref(ref_present, &affected_refnames))
+ die("BUG: initial ref transaction called with existing refs");
+
+ for (i = 0; i < n; i++) {
+ struct ref_update *update = updates[i];
+
+ if ((update->flags & REF_HAVE_OLD) &&
+ !is_null_sha1(update->old_sha1))
+ die("BUG: initial ref transaction with old_sha1 set");
+ if (verify_refname_available(update->refname,
+ &affected_refnames, NULL,
+ loose_refs, err) ||
+ verify_refname_available(update->refname,
+ &affected_refnames, NULL,
+ packed_refs, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
+ goto cleanup;
+ }
+ }
+
+ if (lock_packed_refs(0)) {
+ strbuf_addf(err, "unable to lock packed-refs file: %s",
+ strerror(errno));
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+
+ for (i = 0; i < n; i++) {
+ struct ref_update *update = updates[i];
+
+ if ((update->flags & REF_HAVE_NEW) &&
+ !is_null_sha1(update->new_sha1))
+ add_packed_ref(update->refname, update->new_sha1);
+ }
+
+ if (commit_packed_refs()) {
+ strbuf_addf(err, "unable to commit packed-refs file: %s",
+ strerror(errno));
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
+
+cleanup:
+ transaction->state = REF_TRANSACTION_CLOSED;
+ string_list_clear(&affected_refnames, 0);
+ return ret;
+}
+
char *shorten_unambiguous_ref(const char *refname, int strict)
{
int i;
diff --git a/refs.h b/refs.h
index 8c3d433..e82fca5 100644
--- a/refs.h
+++ b/refs.h
@@ -2,6 +2,98 @@
#define REFS_H
/*
+ * Resolve a reference, recursively following symbolic refererences.
+ *
+ * Store the referred-to object's name in sha1 and return the name of
+ * the non-symbolic reference that ultimately pointed at it. The
+ * return value, if not NULL, is a pointer into either a static buffer
+ * or the input ref.
+ *
+ * If the reference cannot be resolved to an object, the behavior
+ * depends on the RESOLVE_REF_READING flag:
+ *
+ * - If RESOLVE_REF_READING is set, return NULL.
+ *
+ * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
+ * the last reference name in the chain, which will either be a non-symbolic
+ * reference or an undefined reference. If this is a prelude to
+ * "writing" to the ref, the return value is the name of the ref
+ * that will actually be created or changed.
+ *
+ * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
+ * level of symbolic reference. The value stored in sha1 for a symbolic
+ * reference will always be null_sha1 in this case, and the return
+ * value is the reference that the symref refers to directly.
+ *
+ * If flags is non-NULL, set the value that it points to the
+ * combination of REF_ISPACKED (if the reference was found among the
+ * packed references), REF_ISSYMREF (if the initial reference was a
+ * symbolic reference), REF_BAD_NAME (if the reference name is ill
+ * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
+ * (if the ref is malformed or has a bad name). See refs.h for more detail
+ * on each flag.
+ *
+ * If ref is not a properly-formatted, normalized reference, return
+ * NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
+ * give up and return NULL.
+ *
+ * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
+ * name is invalid according to git-check-ref-format(1). If the name
+ * is bad then the value stored in sha1 will be null_sha1 and the two
+ * flags REF_ISBROKEN and REF_BAD_NAME will be set.
+ *
+ * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
+ * directory and do not consist of all caps and underscores cannot be
+ * resolved. The function returns NULL for such ref names.
+ * Caps and underscores refers to the special refs, such as HEAD,
+ * FETCH_HEAD and friends, that all live outside of the refs/ directory.
+ */
+#define RESOLVE_REF_READING 0x01
+#define RESOLVE_REF_NO_RECURSE 0x02
+#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
+
+extern const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
+ unsigned char *sha1, int *flags);
+
+extern char *resolve_refdup(const char *refname, int resolve_flags,
+ unsigned char *sha1, int *flags);
+
+extern int read_ref_full(const char *refname, int resolve_flags,
+ unsigned char *sha1, int *flags);
+extern int read_ref(const char *refname, unsigned char *sha1);
+
+extern int ref_exists(const char *refname);
+
+extern int is_branch(const char *refname);
+
+/*
+ * If refname is a non-symbolic reference that refers to a tag object,
+ * and the tag can be (recursively) dereferenced to a non-tag object,
+ * store the SHA1 of the referred-to object to sha1 and return 0. If
+ * any of these conditions are not met, return a non-zero value.
+ * Symbolic references are considered unpeelable, even if they
+ * ultimately resolve to a peelable tag.
+ */
+extern int peel_ref(const char *refname, unsigned char *sha1);
+
+/**
+ * Resolve refname in the nested "gitlink" repository that is located
+ * at path. If the resolution is successful, return 0 and set sha1 to
+ * the name of the object; otherwise, return a non-zero value.
+ */
+extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1);
+
+/*
+ * Return true iff abbrev_name is a possible abbreviation for
+ * full_name according to the rules defined by ref_rev_parse_rules in
+ * refs.c.
+ */
+extern int refname_match(const char *abbrev_name, const char *full_name);
+
+extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
+extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
+
+/*
* A ref_transaction represents a collection of ref updates
* that should succeed or fail together.
*
@@ -78,15 +170,15 @@ typedef int each_ref_fn(const char *refname,
* modifies the reference also returns a nonzero value to immediately
* stop the iteration.
*/
-extern int head_ref(each_ref_fn, void *);
-extern int for_each_ref(each_ref_fn, void *);
-extern int for_each_ref_in(const char *, each_ref_fn, void *);
-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 for_each_replace_ref(each_ref_fn, void *);
-extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *);
-extern int for_each_glob_ref_in(each_ref_fn, const char *pattern, const char* prefix, void *);
+extern int head_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
+extern int for_each_tag_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_branch_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
+extern int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data);
extern int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
@@ -99,48 +191,18 @@ extern int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn,
extern int head_ref_namespaced(each_ref_fn fn, void *cb_data);
extern int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
+/* can be used to learn about broken ref and symref */
+extern int for_each_rawref(each_ref_fn fn, void *cb_data);
+
static inline const char *has_glob_specials(const char *pattern)
{
return strpbrk(pattern, "?*[");
}
-/* can be used to learn about broken ref and symref */
-extern int for_each_rawref(each_ref_fn, void *);
-
extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames);
/*
- * Lock the packed-refs file for writing. Flags is passed to
- * hold_lock_file_for_update(). Return 0 on success.
- * Errno is set to something meaningful on error.
- */
-extern int lock_packed_refs(int flags);
-
-/*
- * Add a reference to the in-memory packed reference cache. This may
- * only be called while the packed-refs file is locked (see
- * lock_packed_refs()). To actually write the packed-refs file, call
- * commit_packed_refs().
- */
-extern void add_packed_ref(const char *refname, const unsigned char *sha1);
-
-/*
- * Write the current version of the packed refs cache from memory to
- * disk. The packed-refs file must already be locked for writing (see
- * lock_packed_refs()). Return zero on success.
- * Sets errno to something meaningful on error.
- */
-extern int commit_packed_refs(void);
-
-/*
- * Rollback the lockfile for the packed-refs file, and discard the
- * in-memory packed reference cache. (The packed-refs file will be
- * read anew if it is needed again after this function is called.)
- */
-extern void rollback_packed_refs(void);
-
-/*
* Flags for controlling behaviour of pack_refs()
* PACK_REFS_PRUNE: Prune loose refs after packing
* PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
@@ -155,31 +217,6 @@ extern void rollback_packed_refs(void);
int pack_refs(unsigned int flags);
/*
- * Rewrite the packed-refs file, omitting any refs listed in
- * 'refnames'. On error, packed-refs will be unchanged, the return
- * value is nonzero, and a message about the error is written to the
- * 'err' strbuf.
- *
- * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
- */
-extern int repack_without_refs(struct string_list *refnames,
- struct strbuf *err);
-
-extern int ref_exists(const char *);
-
-extern int is_branch(const char *refname);
-
-/*
- * If refname is a non-symbolic reference that refers to a tag object,
- * and the tag can be (recursively) dereferenced to a non-tag object,
- * store the SHA1 of the referred-to object to sha1 and return 0. If
- * any of these conditions are not met, return a non-zero value.
- * Symbolic references are considered unpeelable, even if they
- * ultimately resolve to a peelable tag.
- */
-extern int peel_ref(const char *refname, unsigned char *sha1);
-
-/*
* Flags controlling ref_transaction_update(), ref_transaction_create(), etc.
* REF_NODEREF: act on the ref directly, instead of dereferencing
* symbolic references.
@@ -202,6 +239,23 @@ extern int read_ref_at(const char *refname, unsigned int flags,
/** Check if a particular reflog exists */
extern int reflog_exists(const char *refname);
+/*
+ * Delete the specified reference. If old_sha1 is non-NULL, then
+ * verify that the current value of the reference is old_sha1 before
+ * deleting it. If old_sha1 is NULL, delete the reference if it
+ * exists, regardless of its old value. It is an error for old_sha1 to
+ * be NULL_SHA1. flags is passed through to ref_transaction_delete().
+ */
+extern int delete_ref(const char *refname, const unsigned char *old_sha1,
+ unsigned int flags);
+
+/*
+ * Delete the specified references. If there are any problems, emit
+ * errors but attempt to keep going (i.e., the deletes are not done in
+ * an all-or-nothing transaction).
+ */
+extern int delete_refs(struct string_list *refnames);
+
/** Delete a reflog */
extern int delete_reflog(const char *refname);
@@ -230,17 +284,13 @@ extern int for_each_reflog(each_ref_fn, void *);
extern int check_refname_format(const char *refname, int flags);
extern const char *prettify_refname(const char *refname);
+
extern char *shorten_unambiguous_ref(const char *refname, int strict);
/** rename ref, return 0 on success **/
extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
-/**
- * Resolve refname in the nested "gitlink" repository that is located
- * at path. If the resolution is successful, return 0 and set sha1 to
- * the name of the object; otherwise, return a non-zero value.
- */
-extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1);
+extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
enum action_on_err {
UPDATE_REFS_MSG_ON_ERR,
@@ -360,6 +410,20 @@ int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err);
/*
+ * Like ref_transaction_commit(), but optimized for creating
+ * references when originally initializing a repository (e.g., by "git
+ * clone"). It writes the new references directly to packed-refs
+ * without locking the individual references.
+ *
+ * It is a bug to call this function when there might be other
+ * processes accessing the repository or if there are existing
+ * references that might conflict with the ones being created. All
+ * old_sha1 values must either be absent or NULL_SHA1.
+ */
+int initial_ref_transaction_commit(struct ref_transaction *transaction,
+ struct strbuf *err);
+
+/*
* Free an existing transaction and all associated data.
*/
void ref_transaction_free(struct ref_transaction *transaction);
@@ -377,6 +441,7 @@ int update_ref(const char *msg, const char *refname,
unsigned int flags, enum action_on_err onerr);
extern int parse_hide_refs_config(const char *var, const char *value, const char *);
+
extern int ref_is_hidden(const char *);
enum expire_reflog_flags {
diff --git a/remote-testsvn.c b/remote-testsvn.c
index 48bf6eb..f599c37 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "refs.h"
#include "remote.h"
#include "strbuf.h"
#include "url.h"