summaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/branch.c10
-rw-r--r--builtin/bundle.c2
-rw-r--r--builtin/cat-file.c7
-rw-r--r--builtin/check-ref-format.c2
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c16
-rw-r--r--builtin/fast-import.c23
-rw-r--r--builtin/fetch.c141
-rw-r--r--builtin/fsck.c20
-rw-r--r--builtin/gc.c12
-rw-r--r--builtin/index-pack.c127
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/multi-pack-index.c6
-rw-r--r--builtin/pack-objects.c11
-rw-r--r--builtin/pack-redundant.c2
-rw-r--r--builtin/range-diff.c12
-rw-r--r--builtin/remote.c82
-rw-r--r--builtin/repack.c4
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/show-index.c9
-rw-r--r--builtin/tag.c13
-rw-r--r--builtin/upload-pack.c5
-rw-r--r--builtin/worktree.c37
25 files changed, 418 insertions, 139 deletions
diff --git a/builtin/branch.c b/builtin/branch.c
index 3737a11cbf..6e7b0cfddb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -259,7 +259,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
char *target = NULL;
int flags = 0;
- strbuf_branchname(&bname, argv[i], allowed_interpret);
+ copy_branchname(&bname, argv[i], allowed_interpret);
free(name);
name = mkpathdup(fmt, bname.buf);
@@ -581,7 +581,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
int recovery = 0, oldref_usage = 0;
struct worktree **worktrees = get_worktrees();
- if (strbuf_check_branch_ref(&oldref, oldname)) {
+ if (check_branch_ref(&oldref, oldname)) {
/*
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
@@ -898,7 +898,7 @@ int cmd_branch(int argc,
die(_("cannot give description to detached HEAD"));
branch_name = head;
} else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch_name = buf.buf;
} else {
die(_("cannot edit description of more than one branch"));
@@ -941,7 +941,7 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to set new upstream"));
@@ -971,7 +971,7 @@ int cmd_branch(int argc,
if (!argc)
branch = branch_get(NULL);
else if (argc == 1) {
- strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
branch = branch_get(buf.buf);
} else
die(_("too many arguments to unset upstream"));
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 3f14754197..1e170e9278 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -222,7 +222,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix,
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
ret = !!unbundle(the_repository, &header, bundle_fd,
- &extra_index_pack_args, 0) ||
+ &extra_index_pack_args, NULL) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 825d7d83b2..b13561cf73 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -830,15 +830,16 @@ static int batch_objects(struct batch_options *opt)
cb.seen = &seen;
for_each_loose_object(batch_unordered_loose, &cb, 0);
- for_each_packed_object(batch_unordered_packed, &cb,
- FOR_EACH_OBJECT_PACK_ORDER);
+ for_each_packed_object(the_repository, batch_unordered_packed,
+ &cb, FOR_EACH_OBJECT_PACK_ORDER);
oidset_clear(&seen);
} else {
struct oid_array sa = OID_ARRAY_INIT;
for_each_loose_object(collect_loose_object, &sa, 0);
- for_each_packed_object(collect_packed_object, &sa, 0);
+ for_each_packed_object(the_repository, collect_packed_object,
+ &sa, 0);
oid_array_for_each_unique(&sa, batch_object_cb, &cb);
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index e86d8ef980..cef1ffe3ce 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -42,7 +42,7 @@ static int check_ref_format_branch(const char *arg)
int nongit;
setup_git_directory_gently(&nongit);
- if (strbuf_check_branch_ref(&sb, arg) ||
+ if (check_branch_ref(&sb, arg) ||
!skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
printf("%s\n", name);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 1f92e8297b..01ea9ff8b2 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -744,7 +744,7 @@ static void setup_branch_path(struct branch_info *branch)
&branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
- strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
+ copy_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
if (strcmp(buf.buf, branch->name)) {
free(branch->name);
branch->name = xstrdup(buf.buf);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 04d80887e0..1e89148ed7 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -67,7 +67,7 @@ static int count_loose(const struct object_id *oid, const char *path,
else {
loose_size += on_disk_bytes(st);
loose++;
- if (verbose && has_object_pack(oid))
+ if (verbose && has_object_pack(the_repository, oid))
packed_loose++;
}
return 0;
diff --git a/builtin/describe.c b/builtin/describe.c
index 9045e583b7..e2e73f3d75 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -368,6 +368,13 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit_name **slot;
seen_commits++;
+
+ if (match_cnt == max_candidates ||
+ match_cnt == hashmap_get_size(&names)) {
+ gave_up_on = c;
+ break;
+ }
+
slot = commit_names_peek(&commit_names, c);
n = slot ? *slot : NULL;
if (n) {
@@ -383,10 +390,6 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (n->prio == 2)
annotated_cnt++;
}
- else {
- gave_up_on = c;
- break;
- }
}
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match];
@@ -472,9 +475,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
if (gave_up_on) {
fprintf(stderr,
- _("more than %i tags found; listed %i most recent\n"
- "gave up search at %s\n"),
- max_candidates, max_candidates,
+ _("found %i tags; gave up search at %s\n"),
+ max_candidates,
oid_to_hex(&gave_up_on->object.oid));
}
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 1cc5911bb0..0f86392761 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -15,6 +15,7 @@
#include "delta.h"
#include "pack.h"
#include "path.h"
+#include "read-cache-ll.h"
#include "refs.h"
#include "csum-file.h"
#include "quote.h"
@@ -768,6 +769,7 @@ static void start_packfile(void)
p->pack_fd = pack_fd;
p->do_not_close = 1;
+ p->repo = the_repository;
pack_file = hashfd(pack_fd, p->pack_name);
pack_data = p;
@@ -808,7 +810,7 @@ static char *keep_pack(const char *curr_index_name)
struct strbuf name = STRBUF_INIT;
int keep_fd;
- odb_pack_name(&name, pack_data->hash, "keep");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "keep");
keep_fd = odb_pack_keep(name.buf);
if (keep_fd < 0)
die_errno("cannot create keep file");
@@ -816,11 +818,11 @@ static char *keep_pack(const char *curr_index_name)
if (close(keep_fd))
die_errno("failed to write keep file");
- odb_pack_name(&name, pack_data->hash, "pack");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack");
if (finalize_object_file(pack_data->pack_name, name.buf))
die("cannot store pack file");
- odb_pack_name(&name, pack_data->hash, "idx");
+ odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx");
if (finalize_object_file(curr_index_name, name.buf))
die("cannot store index file");
free((void *)curr_index_name);
@@ -834,7 +836,7 @@ static void unkeep_all_packs(void)
for (k = 0; k < pack_id; k++) {
struct packed_git *p = all_packs[k];
- odb_pack_name(&name, p->hash, "keep");
+ odb_pack_name(p->repo, &name, p->hash, "keep");
unlink_or_warn(name.buf);
}
strbuf_release(&name);
@@ -891,7 +893,7 @@ static void end_packfile(void)
idx_name = keep_pack(create_index());
/* Register the packfile with core git's machinery. */
- new_p = add_packed_git(idx_name, strlen(idx_name), 1);
+ new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1);
if (!new_p)
die("core git rejected index %s", idx_name);
all_packs[pack_id] = new_p;
@@ -1104,7 +1106,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
cycle_packfile();
- the_hash_algo->init_fn(&checkpoint.ctx);
+ the_hash_algo->unsafe_init_fn(&checkpoint.ctx);
hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
@@ -2427,6 +2429,9 @@ static void file_change_m(const char *p, struct branch *b)
tree_content_replace(&b->branch_tree, &oid, mode, NULL);
return;
}
+
+ if (!verify_path(path.buf, mode))
+ die("invalid path '%s'", path.buf);
tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL);
}
@@ -2464,6 +2469,8 @@ static void file_change_cr(const char *p, struct branch *b, int rename)
leaf.tree);
return;
}
+ if (!verify_path(dest.buf, leaf.versions[1].mode))
+ die("invalid path '%s'", dest.buf);
tree_content_set(&b->branch_tree, dest.buf,
&leaf.versions[1].oid,
leaf.versions[1].mode,
@@ -3554,7 +3561,7 @@ static void parse_argv(void)
int cmd_fast_import(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
unsigned int i;
@@ -3675,7 +3682,7 @@ int cmd_fast_import(int argc,
fprintf(stderr, " pools: %10lu KiB\n", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024));
fprintf(stderr, " objects: %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, "---------------------------------------------------------------------\n");
- pack_report();
+ pack_report(repo);
fprintf(stderr, "---------------------------------------------------------------------\n");
fprintf(stderr, "\n");
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b7457a7274..fe2b26c74a 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1577,6 +1577,135 @@ static int backfill_tags(struct display_state *display_state,
return retcode;
}
+static const char *strip_refshead(const char *name){
+ skip_prefix(name, "refs/heads/", &name);
+ return name;
+}
+
+static void set_head_advice_msg(const char *remote, const char *head_name)
+{
+ const char message_advice_set_head[] =
+ N_("Run 'git remote set-head %s %s' to follow the change, or set\n"
+ "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
+ "if you do not want to see this message. Specifically running\n"
+ "'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+ "will disable the warning until the remote changes HEAD to something else.");
+
+ advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head),
+ remote, head_name, remote, remote, head_name);
+}
+
+static void report_set_head(const char *remote, const char *head_name,
+ struct strbuf *buf_prev, int updateres) {
+ struct strbuf buf_prefix = STRBUF_INIT;
+ const char *prev_head = NULL;
+
+ strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+ skip_prefix(buf_prev->buf, buf_prefix.buf, &prev_head);
+
+ if (prev_head && strcmp(prev_head, head_name)) {
+ printf("'HEAD' at '%s' is '%s', but we have '%s' locally.\n",
+ remote, head_name, prev_head);
+ set_head_advice_msg(remote, head_name);
+ }
+ else if (updateres && buf_prev->len) {
+ printf("'HEAD' at '%s' is '%s', "
+ "but we have a detached HEAD pointing to '%s' locally.\n",
+ remote, head_name, buf_prev->buf);
+ set_head_advice_msg(remote, head_name);
+ }
+ strbuf_release(&buf_prefix);
+}
+
+static int set_head(const struct ref *remote_refs, int follow_remote_head,
+ const char *no_warn_branch)
+{
+ int result = 0, create_only, is_bare, was_detached;
+ struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+ b_local_head = STRBUF_INIT;
+ const char *remote = gtransport->remote->name;
+ char *head_name = NULL;
+ struct ref *ref, *matches;
+ struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
+ struct refspec_item refspec = {
+ .force = 0,
+ .pattern = 1,
+ .src = (char *) "refs/heads/*",
+ .dst = (char *) "refs/heads/*",
+ };
+ struct string_list heads = STRING_LIST_INIT_DUP;
+ struct ref_store *refs = get_main_ref_store(the_repository);
+
+ get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
+ matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
+ fetch_map, 1);
+ for (ref = matches; ref; ref = ref->next) {
+ string_list_append(&heads, strip_refshead(ref->name));
+ }
+
+ if (follow_remote_head == FOLLOW_REMOTE_NEVER)
+ goto cleanup;
+
+ if (!heads.nr)
+ result = 1;
+ else if (heads.nr > 1)
+ result = 1;
+ else
+ head_name = xstrdup(heads.items[0].string);
+
+ if (!head_name)
+ goto cleanup;
+ is_bare = is_bare_repository();
+ create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare;
+ if (is_bare) {
+ strbuf_addstr(&b_head, "HEAD");
+ strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
+ } else {
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
+ strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+ }
+ /* make sure it's valid */
+ if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
+ result = 1;
+ goto cleanup;
+ }
+ was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+ "fetch", &b_local_head, create_only);
+ if (was_detached == -1) {
+ result = 1;
+ goto cleanup;
+ }
+ if (verbosity >= 0 &&
+ follow_remote_head == FOLLOW_REMOTE_WARN &&
+ (!no_warn_branch || strcmp(no_warn_branch, head_name)))
+ report_set_head(remote, head_name, &b_local_head, was_detached);
+
+cleanup:
+ free(head_name);
+ free_refs(fetch_map);
+ free_refs(matches);
+ string_list_clear(&heads, 0);
+ strbuf_release(&b_head);
+ strbuf_release(&b_local_head);
+ strbuf_release(&b_remote_head);
+ return result;
+}
+
+static int uses_remote_tracking(struct transport *transport, struct refspec *rs)
+{
+ if (!remote_is_configured(transport->remote, 0))
+ return 0;
+
+ if (!rs->nr)
+ rs = &transport->remote->fetch;
+
+ for (int i = 0; i < rs->nr; i++)
+ if (rs->items[i].dst)
+ return 1;
+
+ return 0;
+}
+
static int do_fetch(struct transport *transport,
struct refspec *rs,
const struct fetch_config *config)
@@ -1646,6 +1775,11 @@ static int do_fetch(struct transport *transport,
"refs/tags/");
}
+ if (uses_remote_tracking(transport, rs)) {
+ must_list_refs = 1;
+ strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+ }
+
if (must_list_refs) {
trace2_region_enter("fetch", "remote_refs", the_repository);
remote_refs = transport_get_remote_refs(transport,
@@ -1790,6 +1924,13 @@ static int do_fetch(struct transport *transport,
"you need to specify exactly one branch with the --set-upstream option"));
}
}
+ if (set_head(remote_refs, transport->remote->follow_remote_head,
+ transport->remote->no_warn_branch))
+ ;
+ /*
+ * Way too many cases where this can go wrong
+ * so let's just fail silently for now.
+ */
cleanup:
if (retcode) {
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 7f4e2f0414..0196c54eb6 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -150,7 +150,7 @@ static int mark_object(struct object *obj, enum object_type type,
return 0;
obj->flags |= REACHABLE;
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
/*
* Further recursion does not need to be performed on this
* object since it is a promisor object (so it does not need to
@@ -270,9 +270,9 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!(obj->flags & HAS_OBJ)) {
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
return;
- if (has_object_pack(&obj->oid))
+ if (has_object_pack(the_repository, &obj->oid))
return; /* it is in pack - forget about it */
printf_ln(_("missing %s %s"),
printable_type(&obj->oid, obj->type),
@@ -391,7 +391,10 @@ static void check_connectivity(void)
* traversal.
*/
for_each_loose_object(mark_loose_unreachable_referents, NULL, 0);
- for_each_packed_object(mark_packed_unreachable_referents, NULL, 0);
+ for_each_packed_object(the_repository,
+ mark_packed_unreachable_referents,
+ NULL,
+ 0);
}
/* Look up all the requirements, warn about missing objects.. */
@@ -488,7 +491,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
refname, timestamp);
obj->flags |= USED;
mark_object_reachable(obj);
- } else if (!is_promisor_object(oid)) {
+ } else if (!is_promisor_object(the_repository, oid)) {
error(_("%s: invalid reflog entry %s"),
refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
@@ -531,7 +534,7 @@ static int fsck_handle_ref(const char *refname, const char *referent UNUSED, con
obj = parse_object(the_repository, oid);
if (!obj) {
- if (is_promisor_object(oid)) {
+ if (is_promisor_object(the_repository, oid)) {
/*
* Increment default_refs anyway, because this is a
* valid ref.
@@ -966,7 +969,8 @@ int cmd_fsck(int argc,
if (connectivity_only) {
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
- for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
+ for_each_packed_object(the_repository,
+ mark_packed_for_connectivity, NULL, 0);
} else {
prepare_alt_odb(the_repository);
for (odb = the_repository->objects->odb; odb; odb = odb->next)
@@ -1011,7 +1015,7 @@ int cmd_fsck(int argc,
&oid);
if (!obj || !(obj->flags & HAS_OBJ)) {
- if (is_promisor_object(&oid))
+ if (is_promisor_object(the_repository, &oid))
continue;
error(_("%s: object missing"), oid_to_hex(&oid));
errors_found |= ERROR_OBJECT;
diff --git a/builtin/gc.c b/builtin/gc.c
index a5879d6b6b..a9b1c36de2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -141,6 +141,11 @@ struct gc_config {
char *repack_filter_to;
unsigned long big_pack_threshold;
unsigned long max_delta_cache_size;
+ /*
+ * Remove this member from gc_config once repo_settings is passed
+ * through the callchain.
+ */
+ size_t delta_base_cache_limit;
};
#define GC_CONFIG_INIT { \
@@ -156,6 +161,7 @@ struct gc_config {
.prune_expire = xstrdup("2.weeks.ago"), \
.prune_worktrees_expire = xstrdup("3.months.ago"), \
.max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
+ .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \
}
static void gc_config_release(struct gc_config *cfg)
@@ -171,6 +177,7 @@ static void gc_config(struct gc_config *cfg)
{
const char *value;
char *owned = NULL;
+ unsigned long ulongval;
if (!git_config_get_value("gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
@@ -209,6 +216,9 @@ static void gc_config(struct gc_config *cfg)
git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+ if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval))
+ cfg->delta_base_cache_limit = ulongval;
+
if (!git_config_get_string("gc.repackfilter", &owned)) {
free(cfg->repack_filter);
cfg->repack_filter = owned;
@@ -419,7 +429,7 @@ static uint64_t estimate_repack_memory(struct gc_config *cfg,
* read_sha1_file() (either at delta calculation phase, or
* writing phase) also fills up the delta base cache
*/
- heap += delta_base_cache_limit;
+ heap += cfg->delta_base_cache_limit;
/* and of course pack-objects has its own delta cache */
heap += cfg->max_delta_cache_size;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 54c7faf6ee..0b62b2589f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -157,11 +157,11 @@ static int input_fd, output_fd;
static const char *curr_pack;
/*
- * local_links is guarded by read_mutex, and record_local_links is read-only in
- * a thread.
+ * outgoing_links is guarded by read_mutex, and record_outgoing_links is
+ * read-only in a thread.
*/
-static struct oidset local_links = OIDSET_INIT;
-static int record_local_links;
+static struct oidset outgoing_links = OIDSET_INIT;
+static int record_outgoing_links;
static struct thread_local_data *thread_data;
static int nr_dispatched;
@@ -814,18 +814,41 @@ static int check_collison(struct object_entry *entry)
return 0;
}
-static void record_if_local_object(const struct object_id *oid)
+static void record_outgoing_link(const struct object_id *oid)
{
- struct object_info info = OBJECT_INFO_INIT;
- if (oid_object_info_extended(the_repository, oid, &info, 0))
- /* Missing; assume it is a promisor object */
- return;
- if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
- return;
- oidset_insert(&local_links, oid);
+ oidset_insert(&outgoing_links, oid);
}
-static void do_record_local_links(struct object *obj)
+static void maybe_record_name_entry(const struct name_entry *entry)
+{
+ /*
+ * Checking only trees here results in a significantly faster packfile
+ * indexing, but the drawback is that if the packfile to be indexed
+ * references a local blob only directly (that is, never through a
+ * local tree), that local blob is in danger of being garbage
+ * collected. Such a situation may arise if we push local commits,
+ * including one with a change to a blob in the root tree, and then the
+ * server incorporates them into its main branch through a "rebase" or
+ * "squash" merge strategy, and then we fetch the new main branch from
+ * the server.
+ *
+ * This situation has not been observed yet - we have only noticed
+ * missing commits, not missing trees or blobs. (In fact, if it were
+ * believed that only missing commits are problematic, one could argue
+ * that we should also exclude trees during the outgoing link check;
+ * but it is safer to include them.)
+ *
+ * Due to the rarity of the situation (it has not been observed to
+ * happen in real life), and because the "penalty" in such a situation
+ * is merely to refetch the missing blob when it's needed (and this
+ * happens only once - when refetched, the blob goes into a promisor
+ * pack, so it won't be GC-ed, the tradeoff seems worth it.
+ */
+ if (S_ISDIR(entry->mode))
+ record_outgoing_link(&entry->oid);
+}
+
+static void do_record_outgoing_links(struct object *obj)
{
if (obj->type == OBJ_TREE) {
struct tree *tree = (struct tree *)obj;
@@ -839,16 +862,17 @@ static void do_record_local_links(struct object *obj)
*/
return;
while (tree_entry_gently(&desc, &entry))
- record_if_local_object(&entry.oid);
+ maybe_record_name_entry(&entry);
} else if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
struct commit_list *parents = commit->parents;
+ record_outgoing_link(get_commit_tree_oid(commit));
for (; parents; parents = parents->next)
- record_if_local_object(&parents->item->object.oid);
+ record_outgoing_link(&parents->item->object.oid);
} else if (obj->type == OBJ_TAG) {
struct tag *tag = (struct tag *) obj;
- record_if_local_object(get_tagged_oid(tag));
+ record_outgoing_link(get_tagged_oid(tag));
}
}
@@ -898,7 +922,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
free(has_data);
}
- if (strict || do_fsck_object || record_local_links) {
+ if (strict || do_fsck_object || record_outgoing_links) {
read_lock();
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(the_repository, oid);
@@ -930,8 +954,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("fsck error in packed object"));
if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
- if (record_local_links)
- do_record_local_links(obj);
+ if (record_outgoing_links)
+ do_record_outgoing_links(obj);
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
@@ -1293,7 +1317,7 @@ static void parse_pack_objects(unsigned char *hash)
* recursively checking if the resulting object is used as a base
* for some more deltas.
*/
-static void resolve_deltas(void)
+static void resolve_deltas(struct pack_idx_option *opts)
{
int i;
@@ -1309,10 +1333,9 @@ static void resolve_deltas(void)
nr_ref_deltas + nr_ofs_deltas);
nr_dispatched = 0;
- base_cache_limit = delta_base_cache_limit * nr_threads;
+ base_cache_limit = opts->delta_base_cache_limit * nr_threads;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
- work_lock();
for (i = 0; i < nr_threads; i++) {
int ret = pthread_create(&thread_data[i].thread, NULL,
threaded_second_pass, thread_data + i);
@@ -1320,7 +1343,6 @@ static void resolve_deltas(void)
die(_("unable to create thread: %s"),
strerror(ret));
}
- work_unlock();
for (i = 0; i < nr_threads; i++)
pthread_join(thread_data[i].thread, NULL);
cleanup_thread();
@@ -1534,7 +1556,7 @@ static void write_special_file(const char *suffix, const char *msg,
if (pack_name)
filename = derive_filename(pack_name, "pack", suffix, &name_buf);
else
- filename = odb_pack_name(&name_buf, hash, suffix);
+ filename = odb_pack_name(the_repository, &name_buf, hash, suffix);
fd = odb_pack_keep(filename);
if (fd < 0) {
@@ -1562,7 +1584,7 @@ static void rename_tmp_packfile(const char **final_name,
{
if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
- *final_name = odb_pack_name(name, hash, ext);
+ *final_name = odb_pack_name(the_repository, name, hash, ext);
if (finalize_object_file(curr_name, *final_name))
die(_("unable to rename temporary '*.%s' file to '%s'"),
ext, *final_name);
@@ -1607,7 +1629,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (do_fsck_object) {
struct packed_git *p;
- p = add_packed_git(final_index_name, strlen(final_index_name), 0);
+ p = add_packed_git(the_repository, final_index_name,
+ strlen(final_index_name), 0);
if (p)
install_packed_git(the_repository, p);
}
@@ -1658,6 +1681,10 @@ static int git_index_pack_config(const char *k, const char *v,
else
opts->flags &= ~WRITE_REV;
}
+ if (!strcmp(k, "core.deltabasecachelimit")) {
+ opts->delta_base_cache_limit = git_config_ulong(k, v, ctx->kvi);
+ return 0;
+ }
return git_default_config(k, v, ctx, cb);
}
@@ -1705,7 +1732,8 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
{
- struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1);
+ struct packed_git *p = add_packed_git(the_repository, pack_name,
+ strlen(pack_name), 1);
if (!p)
die(_("Cannot open existing pack file '%s'"), pack_name);
@@ -1781,28 +1809,43 @@ static void repack_local_links(void)
struct strbuf line = STRBUF_INIT;
struct oidset_iter iter;
struct object_id *oid;
- char *base_name;
+ char *base_name = NULL;
- if (!oidset_size(&local_links))
+ if (!oidset_size(&outgoing_links))
return;
- base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository));
+ oidset_iter_init(&outgoing_links, &iter);
+ while ((oid = oidset_iter_next(&iter))) {
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, oid, &info, 0))
+ /* Missing; assume it is a promisor object */
+ continue;
+ if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+ continue;
- strvec_push(&cmd.args, "pack-objects");
- strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort");
- strvec_push(&cmd.args, base_name);
- cmd.git_cmd = 1;
- cmd.in = -1;
- cmd.out = -1;
- if (start_command(&cmd))
- die(_("could not start pack-objects to repack local links"));
+ if (!cmd.args.nr) {
+ base_name = mkpathdup(
+ "%s/pack/pack",
+ repo_get_object_directory(the_repository));
+ strvec_push(&cmd.args, "pack-objects");
+ strvec_push(&cmd.args,
+ "--exclude-promisor-objects-best-effort");
+ strvec_push(&cmd.args, base_name);
+ cmd.git_cmd = 1;
+ cmd.in = -1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die(_("could not start pack-objects to repack local links"));
+ }
- oidset_iter_init(&local_links, &iter);
- while ((oid = oidset_iter_next(&iter))) {
if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
write_in_full(cmd.in, "\n", 1) < 0)
die(_("failed to feed local object to pack-objects"));
}
+
+ if (!cmd.args.nr)
+ return;
+
close(cmd.in);
out = xfdopen(cmd.out, "r");
@@ -1901,7 +1944,7 @@ int cmd_index_pack(int argc,
} else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
; /* nothing to do */
} else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
- record_local_links = 1;
+ record_outgoing_links = 1;
} else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
@@ -2037,7 +2080,7 @@ int cmd_index_pack(int argc,
parse_pack_objects(pack_hash);
if (report_end_of_input)
write_in_full(2, "\0", 1);
- resolve_deltas();
+ resolve_deltas(&opts);
conclude_pack(fix_thin_pack, curr_pack, pack_hash);
free(ofs_deltas);
free(ref_deltas);
diff --git a/builtin/log.c b/builtin/log.c
index cb41a035c6..75e1b34123 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -531,10 +531,14 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
* but we didn't actually show the commit.
*/
rev->max_count++;
- if (!rev->reflog_info) {
+ if (!rev->reflog_info && !rev->remerge_diff) {
/*
* We may show a given commit multiple times when
- * walking the reflogs.
+ * walking the reflogs. Therefore we still need it.
+ *
+ * Likewise, we potentially still need the parents
+ * of * already shown commits to determine merge
+ * bases when showing remerge diffs.
*/
free_commit_buffer(the_repository->parsed_objects,
commit);
diff --git a/builtin/merge.c b/builtin/merge.c
index a2712a0bab..5f67007bba 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -501,7 +501,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
char *found_ref = NULL;
int len, early;
- strbuf_branchname(&bname, remote, 0);
+ copy_branchname(&bname, remote, 0);
remote = bname.buf;
oidclr(&branch_head, the_repository->hash_algo);
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 85e40a4b6d..2a938466f5 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -120,7 +120,7 @@ static void read_packs_from_stdin(struct string_list *to)
static int cmd_multi_pack_index_write(int argc, const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
struct option *options;
static struct option builtin_multi_pack_index_write_options[] = {
@@ -165,7 +165,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
read_packs_from_stdin(&packs);
- ret = write_midx_file_only(opts.object_dir, &packs,
+ ret = write_midx_file_only(repo, opts.object_dir, &packs,
opts.preferred_pack,
opts.refs_snapshot, opts.flags);
@@ -176,7 +176,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
}
- ret = write_midx_file(opts.object_dir, opts.preferred_pack,
+ ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack,
opts.refs_snapshot, opts.flags);
free(opts.refs_snapshot);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a5d6f8db60..1c3b842651 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1517,7 +1517,7 @@ static int want_found_object(const struct object_id *oid, int exclude,
return 0;
if (ignore_packed_keep_in_core && p->pack_keep_in_core)
return 0;
- if (has_object_kept_pack(oid, flags))
+ if (has_object_kept_pack(p->repo, oid, flags))
return 0;
}
@@ -3615,7 +3615,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
{
- return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS);
+ return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS);
}
static int cruft_include_check(struct commit *commit, void *data)
@@ -3846,7 +3846,8 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
* Quietly ignore EXPECTED missing objects. This avoids problems with
* staging them now and getting an odd error later.
*/
- if (!has_object(the_repository, &obj->oid, 0) && is_promisor_object(&obj->oid))
+ if (!has_object(the_repository, &obj->oid, 0) &&
+ is_promisor_object(to_pack.repo, &obj->oid))
return;
show_object(obj, name, data);
@@ -3915,7 +3916,9 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
static void add_objects_in_unpacked_packs(void)
{
- if (for_each_packed_object(add_object_in_unpacked_pack, NULL,
+ if (for_each_packed_object(to_pack.repo,
+ add_object_in_unpacked_pack,
+ NULL,
FOR_EACH_OBJECT_PACK_ORDER |
FOR_EACH_OBJECT_LOCAL_ONLY |
FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 275333f543..e046575871 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -690,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
- odb_pack_name(&idx_name, pl->pack->hash, "idx"),
+ odb_pack_name(pl->pack->repo, &idx_name, pl->pack->hash, "idx"),
pl->pack->pack_name);
pl = pl->next;
}
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index 433c305fc5..32ddb6613f 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -22,6 +22,7 @@ int cmd_range_diff(int argc,
{
struct diff_options diffopt = { NULL };
struct strvec other_arg = STRVEC_INIT;
+ struct strvec diff_merges_arg = STRVEC_INIT;
struct range_diff_options range_diff_opts = {
.creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT,
.diffopt = &diffopt,
@@ -37,6 +38,10 @@ int cmd_range_diff(int argc,
OPT_PASSTHRU_ARGV(0, "notes", &other_arg,
N_("notes"), N_("passed to 'git log'"),
PARSE_OPT_OPTARG),
+ OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg,
+ N_("style"), N_("passed to 'git log'"), 0),
+ OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL,
+ N_("passed to 'git log'"), PARSE_OPT_NOARG),
OPT_BOOL(0, "left-only", &left_only,
N_("only emit output related to the first range")),
OPT_BOOL(0, "right-only", &right_only,
@@ -63,6 +68,12 @@ int cmd_range_diff(int argc,
if (!simple_color)
diffopt.use_color = 1;
+ /* If `--diff-merges` was specified, imply `--merges` */
+ if (diff_merges_arg.nr) {
+ range_diff_opts.include_merges = 1;
+ strvec_pushv(&other_arg, diff_merges_arg.v);
+ }
+
for (i = 0; i < argc; i++)
if (!strcmp(argv[i], "--")) {
dash_dash = i;
@@ -156,6 +167,7 @@ int cmd_range_diff(int argc,
res = show_range_diff(range1.buf, range2.buf, &range_diff_opts);
strvec_clear(&other_arg);
+ strvec_clear(&diff_merges_arg);
strbuf_release(&range1);
strbuf_release(&range2);
diff --git a/builtin/remote.c b/builtin/remote.c
index b2b13a7dd2..0435963286 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1405,12 +1405,42 @@ static int show(int argc, const char **argv, const char *prefix,
return result;
}
+static void report_set_head_auto(const char *remote, const char *head_name,
+ struct strbuf *b_local_head, int was_detached) {
+ struct strbuf buf_prefix = STRBUF_INIT;
+ const char *prev_head = NULL;
+
+ strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+ skip_prefix(b_local_head->buf, buf_prefix.buf, &prev_head);
+
+ if (prev_head && !strcmp(prev_head, head_name))
+ printf(_("'%s/HEAD' is unchanged and points to '%s'\n"),
+ remote, head_name);
+ else if (prev_head)
+ printf(_("'%s/HEAD' has changed from '%s' and now points to '%s'\n"),
+ remote, prev_head, head_name);
+ else if (!b_local_head->len)
+ printf(_("'%s/HEAD' is now created and points to '%s'\n"),
+ remote, head_name);
+ else if (was_detached && b_local_head->len)
+ printf(_("'%s/HEAD' was detached at '%s' and now points to '%s'\n"),
+ remote, b_local_head->buf, head_name);
+ else
+ printf(_("'%s/HEAD' used to point to '%s' "
+ "(which is not a remote branch), but now points to '%s'\n"),
+ remote, b_local_head->buf, head_name);
+ strbuf_release(&buf_prefix);
+}
+
static int set_head(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, opt_a = 0, opt_d = 0, result = 0;
- struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
+ int i, opt_a = 0, opt_d = 0, result = 0, was_detached;
+ struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+ b_local_head = STRBUF_INIT;
char *head_name = NULL;
+ struct ref_store *refs = get_main_ref_store(the_repository);
+ struct remote *remote;
struct option options[] = {
OPT_BOOL('a', "auto", &opt_a,
@@ -1421,8 +1451,10 @@ static int set_head(int argc, const char **argv, const char *prefix,
};
argc = parse_options(argc, argv, prefix, options,
builtin_remote_sethead_usage, 0);
- if (argc)
- strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
+ if (argc) {
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
+ remote = remote_get(argv[0]);
+ }
if (!opt_a && !opt_d && argc == 2) {
head_name = xstrdup(argv[1]);
@@ -1441,25 +1473,39 @@ static int set_head(int argc, const char **argv, const char *prefix,
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF))
- result |= error(_("Could not delete %s"), buf.buf);
+ if (refs_delete_ref(refs, NULL, b_head.buf, NULL, REF_NO_DEREF))
+ result |= error(_("Could not delete %s"), b_head.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
- if (head_name) {
- strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
- /* make sure it's valid */
- if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
- result |= error(_("Not a valid ref: %s"), buf2.buf);
- else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
- result |= error(_("Could not setup %s"), buf.buf);
- else if (opt_a)
- printf("%s/HEAD set to %s\n", argv[0], head_name);
- free(head_name);
+ if (!head_name)
+ goto cleanup;
+ strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name);
+ if (!refs_ref_exists(refs, b_remote_head.buf)) {
+ result |= error(_("Not a valid ref: %s"), b_remote_head.buf);
+ goto cleanup;
+ }
+ was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+ "remote set-head", &b_local_head, 0);
+ if (was_detached == -1) {
+ result |= error(_("Could not set up %s"), b_head.buf);
+ goto cleanup;
+ }
+ if (opt_a)
+ report_set_head_auto(argv[0], head_name, &b_local_head, was_detached);
+ if (remote->follow_remote_head == FOLLOW_REMOTE_ALWAYS) {
+ struct strbuf config_name = STRBUF_INIT;
+ strbuf_addf(&config_name,
+ "remote.%s.followremotehead", remote->name);
+ git_config_set(config_name.buf, "warn");
+ strbuf_release(&config_name);
}
- strbuf_release(&buf);
- strbuf_release(&buf2);
+cleanup:
+ free(head_name);
+ strbuf_release(&b_head);
+ strbuf_release(&b_remote_head);
+ strbuf_release(&b_local_head);
return result;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index fd2ef166de..0c6dad7df4 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -406,7 +406,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
* {type -> existing pack order} ordering when computing deltas instead
* of a {type -> size} ordering, which may produce better deltas.
*/
- for_each_packed_object(write_oid, &cmd,
+ for_each_packed_object(the_repository, write_oid, &cmd,
FOR_EACH_OBJECT_PROMISOR_ONLY);
if (cmd.in == -1) {
@@ -1571,7 +1571,7 @@ int cmd_repack(int argc,
unsigned flags = 0;
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
flags |= MIDX_WRITE_INCREMENTAL;
- write_midx_file(repo_get_object_directory(the_repository),
+ write_midx_file(the_repository, repo_get_object_directory(the_repository),
NULL, NULL, flags);
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 9b41d0b62a..3196da7b2d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -123,7 +123,7 @@ static inline void finish_object__ma(struct object *obj)
return;
case MA_ALLOW_PROMISOR:
- if (is_promisor_object(&obj->oid))
+ if (is_promisor_object(the_repository, &obj->oid))
return;
die("unexpected missing %s object '%s'",
type_name(obj->type), oid_to_hex(&obj->oid));
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 3152d3c74b..756d632b51 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -40,6 +40,15 @@ int cmd_show_index(int argc,
repo_set_hash_algo(the_repository, hash_algo);
}
+ /*
+ * Fallback to SHA1 if we are running outside of a repository.
+ *
+ * TODO: Figure out and implement a way to detect the hash algorithm in use by the
+ * the index file passed in and use that instead.
+ */
+ if (!the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
hashsz = the_hash_algo->rawsz;
if (fread(top_index, 2 * 4, 1, stdin) != 1)
diff --git a/builtin/tag.c b/builtin/tag.c
index 9d4dfe8ab0..c4bd145831 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -450,17 +450,6 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
-{
- if (name[0] == '-')
- return -1;
-
- strbuf_reset(sb);
- strbuf_addf(sb, "refs/tags/%s", name);
-
- return check_refname_format(sb->buf, 0);
-}
-
int cmd_tag(int argc,
const char **argv,
const char *prefix,
@@ -653,7 +642,7 @@ int cmd_tag(int argc,
if (repo_get_oid(the_repository, object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
- if (strbuf_check_tag_ref(&ref, tag))
+ if (check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 3b6c83fbce..dd63d6eadf 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -39,6 +39,7 @@ int cmd_upload_pack(int argc,
N_("interrupt transfer after <n> seconds of inactivity")),
OPT_END()
};
+ unsigned enter_repo_flags = ENTER_REPO_ANY_OWNER_OK;
packet_trace_identity("upload-pack");
disable_replace_refs();
@@ -54,7 +55,9 @@ int cmd_upload_pack(int argc,
dir = argv[0];
- if (!enter_repo(dir, strict))
+ if (strict)
+ enter_repo_flags |= ENTER_REPO_STRICT;
+ if (!enter_repo(dir, enter_repo_flags))
die("'%s' does not appear to be a git repository", dir);
switch (determine_protocol_version_server()) {
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7dd46e7fc9..c043d4d523 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -122,12 +122,14 @@ struct add_opts {
int quiet;
int checkout;
int orphan;
+ int relative_paths;
const char *keep_locked;
};
static int show_only;
static int verbose;
static int guess_remote;
+static int use_relative_paths;
static timestamp_t expire;
static int git_worktree_config(const char *var, const char *value,
@@ -136,6 +138,9 @@ static int git_worktree_config(const char *var, const char *value,
if (!strcmp(var, "worktree.guessremote")) {
guess_remote = git_config_bool(var, value);
return 0;
+ } else if (!strcmp(var, "worktree.userelativepaths")) {
+ use_relative_paths = git_config_bool(var, value);
+ return 0;
}
return git_default_config(var, value, ctx, cb);
@@ -417,8 +422,7 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
- struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
const char *name;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
@@ -436,7 +440,7 @@ static int add_worktree(const char *path, const char *refname,
worktrees = NULL;
/* is 'refname' a branch or commit? */
- if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
+ if (!opts->detach && !check_branch_ref(&symref, refname) &&
refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) {
is_branch = 1;
if (!opts->force)
@@ -494,10 +498,7 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- strbuf_realpath(&sb_path_realpath, path, 1);
- strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
- write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
- write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
+ write_worktree_linking_files(sb_git, sb, opts->relative_paths);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -581,12 +582,9 @@ done:
strvec_clear(&child_env);
strbuf_release(&sb);
- strbuf_release(&sb_tmp);
strbuf_release(&symref);
strbuf_release(&sb_repo);
- strbuf_release(&sb_repo_realpath);
strbuf_release(&sb_git);
- strbuf_release(&sb_path_realpath);
strbuf_release(&sb_name);
free_worktree(wt);
return ret;
@@ -609,7 +607,7 @@ static void print_preparing_worktree_line(int detach,
fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
} else {
struct strbuf s = STRBUF_INIT;
- if (!detach && !strbuf_check_branch_ref(&s, branch) &&
+ if (!detach && !check_branch_ref(&s, branch) &&
refs_ref_exists(get_main_ref_store(the_repository), s.buf))
fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
branch);
@@ -750,7 +748,7 @@ static char *dwim_branch(const char *path, char **new_branch)
char *branchname = xstrndup(s, n);
struct strbuf ref = STRBUF_INIT;
- branch_exists = !strbuf_check_branch_ref(&ref, branchname) &&
+ branch_exists = !check_branch_ref(&ref, branchname) &&
refs_ref_exists(get_main_ref_store(the_repository),
ref.buf);
strbuf_release(&ref);
@@ -800,12 +798,15 @@ static int add(int ac, const char **av, const char *prefix,
PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
OPT_BOOL(0, "guess-remote", &guess_remote,
N_("try to match the new branch name with a remote-tracking branch")),
+ OPT_BOOL(0, "relative-paths", &opts.relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int ret;
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
+ opts.relative_paths = use_relative_paths;
ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
@@ -844,7 +845,7 @@ static int add(int ac, const char **av, const char *prefix,
new_branch = new_branch_force;
if (!opts.force &&
- !strbuf_check_branch_ref(&symref, new_branch) &&
+ !check_branch_ref(&symref, new_branch) &&
refs_ref_exists(get_main_ref_store(the_repository), symref.buf))
die_if_checked_out(symref.buf, 0);
strbuf_release(&symref);
@@ -1197,6 +1198,8 @@ static int move_worktree(int ac, const char **av, const char *prefix,
OPT__FORCE(&force,
N_("force move even if worktree is dirty or locked"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
struct worktree **worktrees, *wt;
@@ -1249,7 +1252,7 @@ static int move_worktree(int ac, const char **av, const char *prefix,
if (rename(wt->path, dst.buf) == -1)
die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
- update_worktree_location(wt, dst.buf);
+ update_worktree_location(wt, dst.buf, use_relative_paths);
strbuf_release(&dst);
free_worktrees(worktrees);
@@ -1392,6 +1395,8 @@ static int repair(int ac, const char **av, const char *prefix,
const char **p;
const char *self[] = { ".", NULL };
struct option options[] = {
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int rc = 0;
@@ -1399,8 +1404,8 @@ static int repair(int ac, const char **av, const char *prefix,
ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0);
p = ac > 0 ? av : self;
for (; *p; p++)
- repair_worktree_at_path(*p, report_repair, &rc);
- repair_worktrees(report_repair, &rc);
+ repair_worktree_at_path(*p, report_repair, &rc, use_relative_paths);
+ repair_worktrees(report_repair, &rc, use_relative_paths);
return rc;
}