aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/blame.c2
-rw-r--r--builtin/branch.c53
-rw-r--r--builtin/check-mailmap.c2
-rw-r--r--builtin/checkout.c3
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-files.c5
-rw-r--r--builtin/diff.c9
-rw-r--r--builtin/fetch.c224
-rw-r--r--builtin/for-each-ref.c2
-rw-r--r--builtin/fsck.c20
-rw-r--r--builtin/gc.c18
-rw-r--r--builtin/grep.c5
-rw-r--r--builtin/log.c24
-rw-r--r--builtin/ls-files.c81
-rw-r--r--builtin/merge.c3
-rw-r--r--builtin/mktag.c235
-rw-r--r--builtin/name-rev.c10
-rw-r--r--builtin/pack-objects.c47
-rw-r--r--builtin/pack-redundant.c13
-rw-r--r--builtin/repack.c8
-rw-r--r--builtin/shortlog.c16
-rw-r--r--builtin/show-ref.c2
-rw-r--r--builtin/sparse-checkout.c5
-rw-r--r--builtin/tag.c46
-rw-r--r--builtin/worktree.c110
26 files changed, 490 insertions, 457 deletions
diff --git a/builtin/blame.c b/builtin/blame.c
index 2c1c02c455..b66e938022 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1151,7 +1151,7 @@ parse_done:
sb.xdl_opts = xdl_opts;
sb.no_whole_file_rename = no_whole_file_rename;
- read_mailmap(&mailmap, NULL);
+ read_mailmap(&mailmap);
sb.found_guilty_entry = &found_guilty_entry;
sb.found_guilty_entry_data = π
diff --git a/builtin/branch.c b/builtin/branch.c
index 9b68591add..bcc00bcf18 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -202,6 +202,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
int remote_branch = 0;
struct strbuf bname = STRBUF_INIT;
unsigned allowed_interpret;
+ struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+ int branch_name_pos;
switch (kinds) {
case FILTER_REFS_REMOTES:
@@ -219,6 +222,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
default:
die(_("cannot use -a with -d"));
}
+ branch_name_pos = strcspn(fmt, "%");
if (!force) {
head_rev = lookup_commit_reference(the_repository, &head_oid);
@@ -265,30 +269,35 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
goto next;
}
- if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
- REF_NO_DEREF)) {
- error(remote_branch
- ? _("Error deleting remote-tracking branch '%s'")
- : _("Error deleting branch '%s'"),
- bname.buf);
- ret = 1;
- goto next;
- }
- if (!quiet) {
- printf(remote_branch
- ? _("Deleted remote-tracking branch %s (was %s).\n")
- : _("Deleted branch %s (was %s).\n"),
- bname.buf,
- (flags & REF_ISBROKEN) ? "broken"
- : (flags & REF_ISSYMREF) ? target
- : find_unique_abbrev(&oid, DEFAULT_ABBREV));
- }
- delete_branch_config(bname.buf);
+ item = string_list_append(&refs_to_delete, name);
+ item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
+ : (flags & REF_ISSYMREF) ? target
+ : find_unique_abbrev(&oid, DEFAULT_ABBREV));
next:
free(target);
}
+ if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ ret = 1;
+
+ for_each_string_list_item(item, &refs_to_delete) {
+ char *describe_ref = item->util;
+ char *name = item->string;
+ if (!ref_exists(name)) {
+ char *refname = name + branch_name_pos;
+ if (!quiet)
+ printf(remote_branch
+ ? _("Deleted remote-tracking branch %s (was %s).\n")
+ : _("Deleted branch %s (was %s).\n"),
+ name + branch_name_pos, describe_ref);
+
+ delete_branch_config(refname);
+ }
+ free(describe_ref);
+ }
+ string_list_clear(&refs_to_delete, 0);
+
free(name);
strbuf_release(&bname);
@@ -726,7 +735,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
print_current_branch_name();
return 0;
} else if (list) {
- /* git branch --local also shows HEAD when it is detached */
+ /* git branch --list also shows HEAD when it is detached */
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
filter.kind |= FILTER_REFS_DETACHED_HEAD;
filter.name_patterns = argv;
@@ -739,7 +748,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
*/
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+ ref_sorting_set_sort_flags_all(
+ sorting, REF_SORTING_DETACHED_HEAD_FIRST, 1);
print_ref_list(&filter, sorting, &format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index cdce144f3b..7dc47e4793 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -47,7 +47,7 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
if (argc == 0 && !use_stdin)
die(_("no contacts specified"));
- read_mailmap(&mailmap, NULL);
+ read_mailmap(&mailmap);
for (i = 0; i < argc; ++i)
check_mailmap(&mailmap, argv[i]);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index c9ba23c279..2d6550bc3c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -821,9 +821,6 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
}
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
-
if (!cache_tree_fully_valid(active_cache_tree))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
diff --git a/builtin/commit.c b/builtin/commit.c
index 505fe60956..739110c5a7 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1039,7 +1039,7 @@ static const char *find_author_by_nickname(const char *name)
av[++ac] = NULL;
setup_revisions(ac, av, &revs, NULL);
revs.mailmap = &mailmap;
- read_mailmap(revs.mailmap, NULL);
+ read_mailmap(revs.mailmap);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
diff --git a/builtin/describe.c b/builtin/describe.c
index 7668591d57..40482d8e9f 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -194,7 +194,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
}
/* Is it annotated? */
- if (!peel_ref(path, &peeled)) {
+ if (!peel_iterated_oid(oid, &peeled)) {
is_annotated = !oideq(oid, &peeled);
} else {
oidcpy(&peeled, oid);
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 1e352dd8f7..4742a4559b 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
#include "diff.h"
+#include "diff-merges.h"
#include "commit.h"
#include "revision.h"
#include "builtin.h"
@@ -69,9 +70,9 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
* was not asked to. "diff-files -c -p" should not densify
* (the user should ask with "diff-files --cc" explicitly).
*/
- if (rev.max_count == -1 && !rev.combine_merges &&
+ if (rev.max_count == -1 &&
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
- rev.combine_merges = rev.dense_combined_merges = 1;
+ diff_merges_set_dense_combined_if_unset(&rev);
if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
diff --git a/builtin/diff.c b/builtin/diff.c
index 780c33877f..5cfe1717e8 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -13,6 +13,7 @@
#include "blob.h"
#include "tag.h"
#include "diff.h"
+#include "diff-merges.h"
#include "diffcore.h"
#include "revision.h"
#include "log-tree.h"
@@ -216,8 +217,8 @@ static int builtin_diff_combined(struct rev_info *revs,
if (argc > 1)
usage(builtin_diff_usage);
- if (!revs->dense_combined_merges && !revs->combine_merges)
- revs->dense_combined_merges = revs->combine_merges = 1;
+ diff_merges_set_dense_combined_if_unset(revs);
+
for (i = 1; i < ents; i++)
oid_array_append(&parents, &ent[i].item->oid);
diff_tree_combined(&ent[0].item->oid, &parents, revs);
@@ -265,9 +266,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
* dense one, --cc can be explicitly asked for, or just rely
* on the default).
*/
- if (revs->max_count == -1 && !revs->combine_merges &&
+ if (revs->max_count == -1 &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
- revs->combine_merges = revs->dense_combined_merges = 1;
+ diff_merges_set_dense_combined_if_unset(revs);
setup_work_tree();
if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index ecf8537605..91f3d20696 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -63,6 +63,7 @@ static int enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
static int max_jobs = -1, submodule_fetch_jobs_config = -1;
static int fetch_parallel_config = 1;
+static int atomic_fetch;
static enum transport_family family;
static const char *depth;
static const char *deepen_since;
@@ -144,6 +145,8 @@ static struct option builtin_fetch_options[] = {
N_("set upstream for git pull/fetch")),
OPT_BOOL('a', "append", &append,
N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_BOOL(0, "atomic", &atomic_fetch,
+ N_("use atomic transaction to update references")),
OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
N_("path to upload pack on remote end")),
OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
@@ -583,13 +586,14 @@ static struct ref *get_ref_map(struct remote *remote,
static int s_update_ref(const char *action,
struct ref *ref,
+ struct ref_transaction *transaction,
int check_old)
{
char *msg;
char *rla = getenv("GIT_REFLOG_ACTION");
- struct ref_transaction *transaction;
+ struct ref_transaction *our_transaction = NULL;
struct strbuf err = STRBUF_INIT;
- int ret, df_conflict = 0;
+ int ret;
if (dry_run)
return 0;
@@ -597,31 +601,47 @@ static int s_update_ref(const char *action,
rla = default_rla.buf;
msg = xstrfmt("%s: %s", rla, action);
- transaction = ref_transaction_begin(&err);
- if (!transaction ||
- ref_transaction_update(transaction, ref->name,
- &ref->new_oid,
- check_old ? &ref->old_oid : NULL,
- 0, msg, &err))
- goto fail;
+ /*
+ * If no transaction was passed to us, we manage the transaction
+ * ourselves. Otherwise, we trust the caller to handle the transaction
+ * lifecycle.
+ */
+ if (!transaction) {
+ transaction = our_transaction = ref_transaction_begin(&err);
+ if (!transaction) {
+ ret = STORE_REF_ERROR_OTHER;
+ goto out;
+ }
+ }
- ret = ref_transaction_commit(transaction, &err);
+ ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
+ check_old ? &ref->old_oid : NULL,
+ 0, msg, &err);
if (ret) {
- df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
- goto fail;
+ ret = STORE_REF_ERROR_OTHER;
+ goto out;
}
- ref_transaction_free(transaction);
- strbuf_release(&err);
- free(msg);
- return 0;
-fail:
- ref_transaction_free(transaction);
- error("%s", err.buf);
+ if (our_transaction) {
+ switch (ref_transaction_commit(our_transaction, &err)) {
+ case 0:
+ break;
+ case TRANSACTION_NAME_CONFLICT:
+ ret = STORE_REF_ERROR_DF_CONFLICT;
+ goto out;
+ default:
+ ret = STORE_REF_ERROR_OTHER;
+ goto out;
+ }
+ }
+
+out:
+ ref_transaction_free(our_transaction);
+ if (ret)
+ error("%s", err.buf);
strbuf_release(&err);
free(msg);
- return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
- : STORE_REF_ERROR_OTHER;
+ return ret;
}
static int refcol_width = 10;
@@ -759,6 +779,7 @@ static void format_display(struct strbuf *display, char code,
}
static int update_local_ref(struct ref *ref,
+ struct ref_transaction *transaction,
const char *remote,
const struct ref *remote_ref,
struct strbuf *display,
@@ -799,7 +820,7 @@ static int update_local_ref(struct ref *ref,
starts_with(ref->name, "refs/tags/")) {
if (force || ref->force) {
int r;
- r = s_update_ref("updating tag", ref, 0);
+ r = s_update_ref("updating tag", ref, transaction, 0);
format_display(display, r ? '!' : 't', _("[tag update]"),
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -836,7 +857,7 @@ static int update_local_ref(struct ref *ref,
what = _("[new ref]");
}
- r = s_update_ref(msg, ref, 0);
+ r = s_update_ref(msg, ref, transaction, 0);
format_display(display, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -858,7 +879,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "..");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
- r = s_update_ref("fast-forward", ref, 1);
+ r = s_update_ref("fast-forward", ref, transaction, 1);
format_display(display, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
remote, pretty_ref, summary_width);
@@ -870,7 +891,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
strbuf_addstr(&quickref, "...");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
- r = s_update_ref("forced-update", ref, 1);
+ r = s_update_ref("forced-update", ref, transaction, 1);
format_display(display, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
remote, pretty_ref, summary_width);
@@ -897,6 +918,89 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
return 0;
}
+struct fetch_head {
+ FILE *fp;
+ struct strbuf buf;
+};
+
+static int open_fetch_head(struct fetch_head *fetch_head)
+{
+ const char *filename = git_path_fetch_head(the_repository);
+
+ if (write_fetch_head) {
+ fetch_head->fp = fopen(filename, "a");
+ if (!fetch_head->fp)
+ return error_errno(_("cannot open %s"), filename);
+ strbuf_init(&fetch_head->buf, 0);
+ } else {
+ fetch_head->fp = NULL;
+ }
+
+ return 0;
+}
+
+static void append_fetch_head(struct fetch_head *fetch_head,
+ const struct object_id *old_oid,
+ enum fetch_head_status fetch_head_status,
+ const char *note,
+ const char *url, size_t url_len)
+{
+ char old_oid_hex[GIT_MAX_HEXSZ + 1];
+ const char *merge_status_marker;
+ size_t i;
+
+ if (!fetch_head->fp)
+ return;
+
+ switch (fetch_head_status) {
+ case FETCH_HEAD_NOT_FOR_MERGE:
+ merge_status_marker = "not-for-merge";
+ break;
+ case FETCH_HEAD_MERGE:
+ merge_status_marker = "";
+ break;
+ default:
+ /* do not write anything to FETCH_HEAD */
+ return;
+ }
+
+ strbuf_addf(&fetch_head->buf, "%s\t%s\t%s",
+ oid_to_hex_r(old_oid_hex, old_oid), merge_status_marker, note);
+ for (i = 0; i < url_len; ++i)
+ if ('\n' == url[i])
+ strbuf_addstr(&fetch_head->buf, "\\n");
+ else
+ strbuf_addch(&fetch_head->buf, url[i]);
+ strbuf_addch(&fetch_head->buf, '\n');
+
+ /*
+ * When using an atomic fetch, we do not want to update FETCH_HEAD if
+ * any of the reference updates fails. We thus have to write all
+ * updates to a buffer first and only commit it as soon as all
+ * references have been successfully updated.
+ */
+ if (!atomic_fetch) {
+ strbuf_write(&fetch_head->buf, fetch_head->fp);
+ strbuf_reset(&fetch_head->buf);
+ }
+}
+
+static void commit_fetch_head(struct fetch_head *fetch_head)
+{
+ if (!fetch_head->fp || !atomic_fetch)
+ return;
+ strbuf_write(&fetch_head->buf, fetch_head->fp);
+}
+
+static void close_fetch_head(struct fetch_head *fetch_head)
+{
+ if (!fetch_head->fp)
+ return;
+
+ fclose(fetch_head->fp);
+ strbuf_release(&fetch_head->buf);
+}
+
static const char warn_show_forced_updates[] =
N_("Fetch normally indicates which branches had a forced update,\n"
"but that check has been disabled. To re-enable, use '--show-forced-updates'\n"
@@ -909,22 +1013,20 @@ N_("It took %.2f seconds to check forced updates. You can use\n"
static int store_updated_refs(const char *raw_url, const char *remote_name,
int connectivity_checked, struct ref *ref_map)
{
- FILE *fp;
+ struct fetch_head fetch_head;
struct commit *commit;
int url_len, i, rc = 0;
- struct strbuf note = STRBUF_INIT;
+ struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
+ struct ref_transaction *transaction = NULL;
const char *what, *kind;
struct ref *rm;
char *url;
- const char *filename = (!write_fetch_head
- ? "/dev/null"
- : git_path_fetch_head(the_repository));
int want_status;
int summary_width = transport_summary_width(ref_map);
- fp = fopen(filename, "a");
- if (!fp)
- return error_errno(_("cannot open %s"), filename);
+ rc = open_fetch_head(&fetch_head);
+ if (rc)
+ return -1;
if (raw_url)
url = transport_anonymize_url(raw_url);
@@ -941,6 +1043,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
+ if (atomic_fetch) {
+ transaction = ref_transaction_begin(&err);
+ if (!transaction) {
+ error("%s", err.buf);
+ goto abort;
+ }
+ }
+
prepare_format_display(ref_map);
/*
@@ -953,7 +1063,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
want_status++) {
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
- const char *merge_status_marker = "";
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
if (want_status == FETCH_HEAD_MERGE)
@@ -1011,31 +1120,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_addf(&note, "%s ", kind);
strbuf_addf(&note, "'%s' of ", what);
}
- switch (rm->fetch_head_status) {
- case FETCH_HEAD_NOT_FOR_MERGE:
- merge_status_marker = "not-for-merge";
- /* fall-through */
- case FETCH_HEAD_MERGE:
- fprintf(fp, "%s\t%s\t%s",
- oid_to_hex(&rm->old_oid),
- merge_status_marker,
- note.buf);
- for (i = 0; i < url_len; ++i)
- if ('\n' == url[i])
- fputs("\\n", fp);
- else
- fputc(url[i], fp);
- fputc('\n', fp);
- break;
- default:
- /* do not write anything to FETCH_HEAD */
- break;
- }
+
+ append_fetch_head(&fetch_head, &rm->old_oid,
+ rm->fetch_head_status,
+ note.buf, url, url_len);
strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, what, rm, &note,
- summary_width);
+ rc |= update_local_ref(ref, transaction, what,
+ rm, &note, summary_width);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1060,6 +1153,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
+ if (!rc && transaction) {
+ rc = ref_transaction_commit(transaction, &err);
+ if (rc) {
+ error("%s", err.buf);
+ goto abort;
+ }
+ }
+
+ if (!rc)
+ commit_fetch_head(&fetch_head);
+
if (rc & STORE_REF_ERROR_DF_CONFLICT)
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
@@ -1076,8 +1180,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
+ strbuf_release(&err);
+ ref_transaction_free(transaction);
free(url);
- fclose(fp);
+ close_fetch_head(&fetch_head);
return rc;
}
@@ -1887,6 +1993,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
die(_("--filter can only be used with the remote "
"configured in extensions.partialclone"));
+ if (atomic_fetch)
+ die(_("--atomic can only be used when fetching "
+ "from one remote"));
+
if (stdin_refspecs)
die(_("--stdin can only be used when fetching "
"from one remote"));
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 9d1ecda2b8..cb9c81a046 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
filter.name_patterns = argv;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index fbf26cafcf..821e7798c7 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -73,25 +73,7 @@ static const char *printable_type(const struct object_id *oid,
static int fsck_config(const char *var, const char *value, void *cb)
{
- if (strcmp(var, "fsck.skiplist") == 0) {
- const char *path;
- struct strbuf sb = STRBUF_INIT;
-
- if (git_config_pathname(&path, var, value))
- return 1;
- strbuf_addf(&sb, "skiplist=%s", path);
- free((char *)path);
- fsck_set_msg_types(&fsck_obj_options, sb.buf);
- strbuf_release(&sb);
- return 0;
- }
-
- if (skip_prefix(var, "fsck.", &var)) {
- fsck_set_msg_type(&fsck_obj_options, var, value);
- return 0;
- }
-
- return git_default_config(var, value, cb);
+ return fsck_config_internal(var, value, cb, &fsck_obj_options);
}
static int objerror(struct object *obj, const char *err)
diff --git a/builtin/gc.c b/builtin/gc.c
index b315b2ad58..4c40594d66 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -92,7 +92,7 @@ static void process_log_file(void)
*/
int saved_errno = errno;
fprintf(stderr, _("Failed to fstat %s: %s"),
- get_tempfile_path(log_lock.tempfile),
+ get_lock_file_path(&log_lock),
strerror(saved_errno));
fflush(stderr);
commit_lock_file(&log_lock);
@@ -301,7 +301,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
/* and then obj_hash[], underestimated in fact */
heap += sizeof(struct object *) * nr_objects;
/* revindex is used also */
- heap += sizeof(struct revindex_entry) * nr_objects;
+ heap += (sizeof(off_t) + sizeof(uint32_t)) * nr_objects;
/*
* read_sha1_file() (either at delta calculation phase, or
* writing phase) also fills up the delta base cache
@@ -769,7 +769,7 @@ static int dfs_on_ref(const char *refname,
struct commit_list *stack = NULL;
struct commit *commit;
- if (!peel_ref(refname, &peeled))
+ if (!peel_iterated_oid(oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
return 0;
@@ -897,6 +897,12 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
struct string_list_item *item;
struct string_list remotes = STRING_LIST_INIT_DUP;
+ git_config_set_multivar_gently("log.excludedecoration",
+ "refs/prefetch/",
+ "refs/prefetch/",
+ CONFIG_FLAGS_FIXED_VALUE |
+ CONFIG_FLAGS_MULTI_REPLACE);
+
if (for_each_remote(append_remote, &remotes)) {
error(_("failed to fill remotes"));
result = 1;
@@ -1953,11 +1959,11 @@ static int update_background_schedule(int enable)
return error(_("another process is scheduling background maintenance"));
if (!strcmp(scheduler, "launchctl"))
- result = launchctl_update_schedule(enable, lk.tempfile->fd, cmd);
+ result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else if (!strcmp(scheduler, "schtasks"))
- result = schtasks_update_schedule(enable, lk.tempfile->fd, cmd);
+ result = schtasks_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else if (!strcmp(scheduler, "crontab"))
- result = crontab_update_schedule(enable, lk.tempfile->fd, cmd);
+ result = crontab_update_schedule(enable, get_lock_file_fd(&lk), cmd);
else
die("unknown background scheduler: %s", scheduler);
diff --git a/builtin/grep.c b/builtin/grep.c
index ca259af441..55d06c9513 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -216,8 +216,6 @@ static void start_threads(struct grep_opt *opt)
int err;
struct grep_opt *o = grep_opt_dup(opt);
o->output = strbuf_out;
- if (i)
- o->debug = 0;
compile_grep_patterns(o);
err = pthread_create(&threads[i], NULL, run, o);
@@ -936,9 +934,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("indicate hit with exit status without output")),
OPT_BOOL(0, "all-match", &opt.all_match,
N_("show only matches from files that match all patterns")),
- OPT_SET_INT_F(0, "debug", &opt.debug,
- N_("show parse tree for grep expression"),
- 1, PARSE_OPT_HIDDEN),
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
N_("pager"), N_("show matching files in the pager"),
diff --git a/builtin/log.c b/builtin/log.c
index f23ccdbec3..d0cbaaf68a 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -12,6 +12,7 @@
#include "color.h"
#include "commit.h"
#include "diff.h"
+#include "diff-merges.h"
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
@@ -230,7 +231,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
if (mailmap) {
rev->mailmap = xcalloc(1, sizeof(struct string_list));
- read_mailmap(rev->mailmap, NULL);
+ read_mailmap(rev->mailmap);
}
if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
@@ -607,15 +608,10 @@ static int show_tree_object(const struct object_id *oid,
static void show_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
- if (rev->ignore_merges < 0) {
- /* There was no "-m" variant on the command line */
- rev->ignore_merges = 0;
- if (!rev->first_parent_only && !rev->combine_merges) {
- /* No "--first-parent", "-c", or "--cc" */
- rev->combine_merges = 1;
- rev->dense_combined_merges = 1;
- }
- }
+ if (rev->first_parent_only)
+ diff_merges_default_to_first_parent(rev);
+ else
+ diff_merges_default_to_dense_combined(rev);
if (!rev->diffopt.output_format)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
}
@@ -736,12 +732,8 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
rev->prune_data.nr == 1)
rev->diffopt.flags.follow_renames = 1;
- /* Turn --cc/-c into -p --cc/-c when -p was not given */
- if (!rev->diffopt.output_format && rev->combine_merges)
- rev->diffopt.output_format = DIFF_FORMAT_PATCH;
-
- if (rev->first_parent_only && rev->ignore_merges < 0)
- rev->ignore_merges = 0;
+ if (rev->first_parent_only)
+ diff_merges_default_to_first_parent(rev);
}
int cmd_log(int argc, const char **argv, const char *prefix)
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c8eae899b8..f6f9e483b2 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -35,6 +35,7 @@ static int line_terminator = '\n';
static int debug_mode;
static int show_eol;
static int recurse_submodules;
+static int skipping_duplicates;
static const char *prefix;
static int max_prefix_len;
@@ -312,45 +313,59 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
if (show_killed)
show_killed_files(repo->index, dir);
}
- if (show_cached || show_stage) {
- for (i = 0; i < repo->index->cache_nr; i++) {
- const struct cache_entry *ce = repo->index->cache[i];
- construct_fullname(&fullname, repo, ce);
+ if (!(show_cached || show_stage || show_deleted || show_modified))
+ return;
+ for (i = 0; i < repo->index->cache_nr; i++) {
+ const struct cache_entry *ce = repo->index->cache[i];
+ struct stat st;
+ int stat_err;
- if ((dir->flags & DIR_SHOW_IGNORED) &&
- !ce_excluded(dir, repo->index, fullname.buf, ce))
- continue;
- if (show_unmerged && !ce_stage(ce))
- continue;
- if (ce->ce_flags & CE_UPDATE)
- continue;
+ construct_fullname(&fullname, repo, ce);
+
+ if ((dir->flags & DIR_SHOW_IGNORED) &&
+ !ce_excluded(dir, repo->index, fullname.buf, ce))
+ continue;
+ if (ce->ce_flags & CE_UPDATE)
+ continue;
+ if ((show_cached || show_stage) &&
+ (!show_unmerged || ce_stage(ce))) {
show_ce(repo, dir, ce, fullname.buf,
ce_stage(ce) ? tag_unmerged :
(ce_skip_worktree(ce) ? tag_skip_worktree :
tag_cached));
+ if (skipping_duplicates)
+ goto skip_to_next_name;
}
- }
- if (show_deleted || show_modified) {
- for (i = 0; i < repo->index->cache_nr; i++) {
- const struct cache_entry *ce = repo->index->cache[i];
- struct stat st;
- int err;
- construct_fullname(&fullname, repo, ce);
-
- if ((dir->flags & DIR_SHOW_IGNORED) &&
- !ce_excluded(dir, repo->index, fullname.buf, ce))
- continue;
- if (ce->ce_flags & CE_UPDATE)
- continue;
- if (ce_skip_worktree(ce))
- continue;
- err = lstat(fullname.buf, &st);
- if (show_deleted && err)
- show_ce(repo, dir, ce, fullname.buf, tag_removed);
- if (show_modified && ie_modified(repo->index, ce, &st, 0))
- show_ce(repo, dir, ce, fullname.buf, tag_modified);
+ if (!(show_deleted || show_modified))
+ continue;
+ if (ce_skip_worktree(ce))
+ continue;
+ stat_err = lstat(fullname.buf, &st);
+ if (stat_err && (errno != ENOENT && errno != ENOTDIR))
+ error_errno("cannot lstat '%s'", fullname.buf);
+ if (stat_err && show_deleted) {
+ show_ce(repo, dir, ce, fullname.buf, tag_removed);
+ if (skipping_duplicates)
+ goto skip_to_next_name;
+ }
+ if (show_modified &&
+ (stat_err || ie_modified(repo->index, ce, &st, 0))) {
+ show_ce(repo, dir, ce, fullname.buf, tag_modified);
+ if (skipping_duplicates)
+ goto skip_to_next_name;
+ }
+ continue;
+
+skip_to_next_name:
+ {
+ int j;
+ struct cache_entry **cache = repo->index->cache;
+ for (j = i + 1; j < repo->index->cache_nr; j++)
+ if (strcmp(ce->name, cache[j]->name))
+ break;
+ i = j - 1; /* compensate for the for loop */
}
}
@@ -578,6 +593,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
N_("pretend that paths removed since <tree-ish> are still present")),
OPT__ABBREV(&abbrev),
OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
+ OPT_BOOL(0, "deduplicate", &skipping_duplicates,
+ N_("suppress duplicate entries")),
OPT_END()
};
@@ -617,6 +634,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
* you also show the stage information.
*/
show_stage = 1;
+ if (show_tag || show_stage)
+ skipping_duplicates = 0;
if (dir.exclude_per_dir)
exc_given = 1;
diff --git a/builtin/merge.c b/builtin/merge.c
index 1cff730715..eb00b273e6 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
#include "lockfile.h"
#include "run-command.h"
#include "diff.h"
+#include "diff-merges.h"
#include "refs.h"
#include "refspec.h"
#include "commit.h"
@@ -409,7 +410,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
printf(_("Squash commit -- not updating HEAD\n"));
repo_init_revisions(the_repository, &rev, NULL);
- rev.ignore_merges = 1;
+ diff_merges_suppress(&rev);
rev.commit_format = CMIT_FMT_MEDIUM;
commit->object.flags |= UNINTERESTING;
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 4982d3a93e..41a399a69e 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,179 +1,110 @@
#include "builtin.h"
+#include "parse-options.h"
#include "tag.h"
#include "replace-object.h"
#include "object-store.h"
+#include "fsck.h"
+#include "config.h"
-/*
- * A signature file has a very simple fixed format: four lines
- * of "object <sha1>" + "type <typename>" + "tag <tagname>" +
- * "tagger <committer>", followed by a blank line, a free-form tag
- * message and a signature block that git itself doesn't care about,
- * but that can be verified with gpg or similar.
- *
- * The first four lines are guaranteed to be at least 83 bytes:
- * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
- * shortest possible type-line, "tag .\n" at 6 bytes is the shortest
- * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is
- * the shortest possible tagger-line.
- */
-
-/*
- * We refuse to tag something we can't verify. Just because.
- */
-static int verify_object(const struct object_id *oid, const char *expected_type)
+static char const * const builtin_mktag_usage[] = {
+ N_("git mktag"),
+ NULL
+};
+static int option_strict = 1;
+
+static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
+
+static int mktag_config(const char *var, const char *value, void *cb)
{
- int ret = -1;
- enum object_type type;
- unsigned long size;
- void *buffer = read_object_file(oid, &type, &size);
- const struct object_id *repl = lookup_replace_object(the_repository, oid);
-
- if (buffer) {
- if (type == type_from_string(expected_type)) {
- ret = check_object_signature(the_repository, repl,
- buffer, size,
- expected_type);
+ return fsck_config_internal(var, value, cb, &fsck_options);
+}
+
+static int mktag_fsck_error_func(struct fsck_options *o,
+ const struct object_id *oid,
+ enum object_type object_type,
+ int msg_type, const char *message)
+{
+ switch (msg_type) {
+ case FSCK_WARN:
+ if (!option_strict) {
+ fprintf_ln(stderr, _("warning: tag input does not pass fsck: %s"), message);
+ return 0;
+
}
- free(buffer);
+ /* fallthrough */
+ case FSCK_ERROR:
+ /*
+ * We treat both warnings and errors as errors, things
+ * like missing "tagger" lines are "only" warnings
+ * under fsck, we've always considered them an error.
+ */
+ fprintf_ln(stderr, _("error: tag input does not pass fsck: %s"), message);
+ return 1;
+ default:
+ BUG(_("%d (FSCK_IGNORE?) should never trigger this callback"),
+ msg_type);
}
- return ret;
}
-static int verify_tag(char *buffer, unsigned long size)
+static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
{
- int typelen;
- char type[20];
- struct object_id oid;
- const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p;
- size_t len;
-
- if (size < 84)
- return error("wanna fool me ? you obviously got the size wrong !");
-
- buffer[size] = 0;
-
- /* Verify object line */
- object = buffer;
- if (memcmp(object, "object ", 7))
- return error("char%d: does not start with \"object \"", 0);
-
- if (parse_oid_hex(object + 7, &oid, &p))
- return error("char%d: could not get SHA1 hash", 7);
-
- /* Verify type line */
- type_line = p + 1;
- if (memcmp(type_line - 1, "\ntype ", 6))
- return error("char%d: could not find \"\\ntype \"", 47);
-
- /* Verify tag-line */
- tag_line = strchr(type_line, '\n');
- if (!tag_line)
- return error("char%"PRIuMAX": could not find next \"\\n\"",
- (uintmax_t) (type_line - buffer));
- tag_line++;
- if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n')
- return error("char%"PRIuMAX": no \"tag \" found",
- (uintmax_t) (tag_line - buffer));
-
- /* Get the actual type */
- typelen = tag_line - type_line - strlen("type \n");
- if (typelen >= sizeof(type))
- return error("char%"PRIuMAX": type too long",
- (uintmax_t) (type_line+5 - buffer));
-
- memcpy(type, type_line+5, typelen);
- type[typelen] = 0;
-
- /* Verify that the object matches */
- if (verify_object(&oid, type))
- return error("char%d: could not verify object %s", 7, oid_to_hex(&oid));
-
- /* Verify the tag-name: we don't allow control characters or spaces in it */
- tag_line += 4;
- for (;;) {
- unsigned char c = *tag_line++;
- if (c == '\n')
- break;
- if (c > ' ')
- continue;
- return error("char%"PRIuMAX": could not verify tag name",
- (uintmax_t) (tag_line - buffer));
- }
+ int ret;
+ enum object_type type;
+ unsigned long size;
+ void *buffer;
+ const struct object_id *repl;
+
+ buffer = read_object_file(tagged_oid, &type, &size);
+ if (!buffer)
+ die(_("could not read tagged object '%s'"),
+ oid_to_hex(tagged_oid));
+ if (type != *tagged_type)
+ die(_("object '%s' tagged as '%s', but is a '%s' type"),
+ oid_to_hex(tagged_oid),
+ type_name(*tagged_type), type_name(type));
+
+ repl = lookup_replace_object(the_repository, tagged_oid);
+ ret = check_object_signature(the_repository, repl,
+ buffer, size, type_name(*tagged_type));
+ free(buffer);
- /* Verify the tagger line */
- tagger_line = tag_line;
-
- if (memcmp(tagger_line, "tagger ", 7))
- return error("char%"PRIuMAX": could not find \"tagger \"",
- (uintmax_t) (tagger_line - buffer));
-
- /*
- * Check for correct form for name and email
- * i.e. " <" followed by "> " on _this_ line
- * No angle brackets within the name or email address fields.
- * No spaces within the email address field.
- */
- tagger_line += 7;
- if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) ||
- strpbrk(tagger_line, "<>\n") != lb+1 ||
- strpbrk(lb+2, "><\n ") != rb)
- return error("char%"PRIuMAX": malformed tagger field",
- (uintmax_t) (tagger_line - buffer));
-
- /* Check for author name, at least one character, space is acceptable */
- if (lb == tagger_line)
- return error("char%"PRIuMAX": missing tagger name",
- (uintmax_t) (tagger_line - buffer));
-
- /* timestamp, 1 or more digits followed by space */
- tagger_line = rb + 2;
- if (!(len = strspn(tagger_line, "0123456789")))
- return error("char%"PRIuMAX": missing tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += len;
- if (*tagger_line != ' ')
- return error("char%"PRIuMAX": malformed tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line++;
-
- /* timezone, 5 digits [+-]hhmm, max. 1400 */
- if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
- strspn(tagger_line+1, "0123456789") == 4 &&
- tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
- return error("char%"PRIuMAX": malformed tag timezone",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += 6;
-
- /* Verify the blank line separating the header from the body */
- if (*tagger_line != '\n')
- return error("char%"PRIuMAX": trailing garbage in tag header",
- (uintmax_t) (tagger_line - buffer));
-
- /* The actual stuff afterwards we don't care about.. */
- return 0;
+ return ret;
}
int cmd_mktag(int argc, const char **argv, const char *prefix)
{
+ static struct option builtin_mktag_options[] = {
+ OPT_BOOL(0, "strict", &option_strict,
+ N_("enable more strict checking")),
+ OPT_END(),
+ };
struct strbuf buf = STRBUF_INIT;
+ struct object_id tagged_oid;
+ int tagged_type;
struct object_id result;
- if (argc != 1)
- usage("git mktag");
+ argc = parse_options(argc, argv, NULL,
+ builtin_mktag_options,
+ builtin_mktag_usage, 0);
- if (strbuf_read(&buf, 0, 4096) < 0) {
- die_errno("could not read from stdin");
- }
+ if (strbuf_read(&buf, 0, 0) < 0)
+ die_errno(_("could not read from stdin"));
+
+ fsck_options.error_func = mktag_fsck_error_func;
+ fsck_set_msg_type(&fsck_options, "extraheaderentry", "warn");
+ /* config might set fsck.extraHeaderEntry=* again */
+ git_config(mktag_config, NULL);
+ if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
+ &tagged_oid, &tagged_type))
+ die(_("tag on stdin did not pass our strict fsck check"));
- /* Verify it for some basic sanity: it needs to start with
- "object <sha1>\ntype\ntagger " */
- if (verify_tag(buf.buf, buf.len) < 0)
- die("invalid tag signature file");
+ if (verify_object_in_tag(&tagged_oid, &tagged_type))
+ die(_("tag on stdin did not refer to a valid object"));
if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
- die("unable to write tag file");
+ die(_("unable to write tag file"));
strbuf_release(&buf);
- printf("%s\n", oid_to_hex(&result));
+ puts(oid_to_hex(&result));
return 0;
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 3fe71a8c01..b221d30014 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -390,10 +390,10 @@ static void name_tips(void)
}
}
-static const unsigned char *nth_tip_table_ent(size_t ix, void *table_)
+static const struct object_id *nth_tip_table_ent(size_t ix, const void *table_)
{
- struct tip_table_entry *table = table_;
- return table[ix].oid.hash;
+ const struct tip_table_entry *table = table_;
+ return &table[ix].oid;
}
static const char *get_exact_ref_match(const struct object *o)
@@ -408,8 +408,8 @@ static const char *get_exact_ref_match(const struct object *o)
tip_table.sorted = 1;
}
- found = hash_pos(o->oid.hash, tip_table.table, tip_table.nr,
- nth_tip_table_ent);
+ found = oid_pos(&o->oid, tip_table.table, tip_table.nr,
+ nth_tip_table_ent);
if (0 <= found)
return tip_table.table[found].refname;
return NULL;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 2a00358f34..13cde5896a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -419,7 +419,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
{
struct packed_git *p = IN_PACK(entry);
struct pack_window *w_curs = NULL;
- struct revindex_entry *revidx;
+ uint32_t pos;
off_t offset;
enum object_type type = oe_type(entry);
off_t datalen;
@@ -436,10 +436,15 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
type, entry_size);
offset = entry->in_pack_offset;
- revidx = find_pack_revindex(p, offset);
- datalen = revidx[1].offset - offset;
+ if (offset_to_pack_pos(p, offset, &pos) < 0)
+ die(_("write_reuse_object: could not locate %s, expected at "
+ "offset %"PRIuMAX" in pack %s"),
+ oid_to_hex(&entry->idx.oid), (uintmax_t)offset,
+ p->pack_name);
+ datalen = pack_pos_to_offset(p, pos + 1) - offset;
if (!pack_to_stdout && p->index_version > 1 &&
- check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
+ check_pack_crc(p, &w_curs, offset, datalen,
+ pack_pos_to_index(p, pos))) {
error(_("bad packed object CRC for %s"),
oid_to_hex(&entry->idx.oid));
unuse_pack(&w_curs);
@@ -629,7 +634,7 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
if (entry)
entry->tagged = 1;
- if (!peel_ref(path, &peeled)) {
+ if (!peel_iterated_oid(oid, &peeled)) {
entry = packlist_find(&to_pack, &peeled);
if (entry)
entry->tagged = 1;
@@ -863,8 +868,8 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
enum object_type type;
unsigned long size;
- offset = reuse_packfile->revindex[pos].offset;
- next = reuse_packfile->revindex[pos + 1].offset;
+ offset = pack_pos_to_offset(reuse_packfile, pos);
+ next = pack_pos_to_offset(reuse_packfile, pos + 1);
record_reused_object(offset, offset - hashfile_total(out));
@@ -884,11 +889,17 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
/* Convert to REF_DELTA if we must... */
if (!allow_ofs_delta) {
- int base_pos = find_revindex_position(reuse_packfile, base_offset);
+ uint32_t base_pos;
struct object_id base_oid;
+ if (offset_to_pack_pos(reuse_packfile, base_offset, &base_pos) < 0)
+ die(_("expected object at offset %"PRIuMAX" "
+ "in pack %s"),
+ (uintmax_t)base_offset,
+ reuse_packfile->pack_name);
+
nth_packed_object_id(&base_oid, reuse_packfile,
- reuse_packfile->revindex[base_pos].nr);
+ pack_pos_to_index(reuse_packfile, base_pos));
len = encode_in_pack_object_header(header, sizeof(header),
OBJ_REF_DELTA, size);
@@ -941,7 +952,7 @@ static size_t write_reused_pack_verbatim(struct hashfile *out,
off_t to_write;
written = (pos * BITS_IN_EWORD);
- to_write = reuse_packfile->revindex[written].offset
+ to_write = pack_pos_to_offset(reuse_packfile, written)
- sizeof(struct pack_header);
/* We're recording one chunk, not one object. */
@@ -1806,11 +1817,11 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
goto give_up;
}
if (reuse_delta && !entry->preferred_base) {
- struct revindex_entry *revidx;
- revidx = find_pack_revindex(p, ofs);
- if (!revidx)
+ uint32_t pos;
+ if (offset_to_pack_pos(p, ofs, &pos) < 0)
goto give_up;
- if (!nth_packed_object_id(&base_ref, p, revidx->nr))
+ if (!nth_packed_object_id(&base_ref, p,
+ pack_pos_to_index(p, pos)))
have_base = 1;
}
entry->in_pack_header_size = used + used_0;
@@ -2803,13 +2814,11 @@ static void add_tag_chain(const struct object_id *oid)
}
}
-static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data)
+static int add_ref_tag(const char *tag, const struct object_id *oid, int flag, void *cb_data)
{
struct object_id peeled;
- if (starts_with(path, "refs/tags/") && /* is a tag? */
- !peel_ref(path, &peeled) && /* peelable? */
- obj_is_packed(&peeled)) /* object packed? */
+ if (!peel_iterated_oid(oid, &peeled) && obj_is_packed(&peeled))
add_tag_chain(oid);
return 0;
}
@@ -3740,7 +3749,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
cleanup_preferred_base();
if (include_tag && nr_result)
- for_each_ref(add_ref_tag, NULL);
+ for_each_tag_ref(add_ref_tag, NULL);
stop_progress(&progress_state);
trace2_region_leave("pack-objects", "enumerate-objects",
the_repository);
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 9fcea3e253..6e115a811a 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -560,6 +560,7 @@ static void load_all(void)
int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
{
int i;
+ int i_still_use_this = 0;
struct pack_list *min = NULL, *red, *pl;
struct llist *ignore;
struct object_id *oid;
@@ -586,12 +587,24 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
alt_odb = 1;
continue;
}
+ if (!strcmp(arg, "--i-still-use-this")) {
+ i_still_use_this = 1;
+ continue;
+ }
if (*arg == '-')
usage(pack_redundant_usage);
else
break;
}
+ if (!i_still_use_this) {
+ fputs(_("'git pack-redundant' is nominated for removal.\n"
+ "If you still use this command, please add an extra\n"
+ "option, '--i-still-use-this', on the command line\n"
+ "and let us know you still use it by sending an e-mail\n"
+ "to <git@vger.kernel.org>. Thanks.\n"), stderr);
+ }
+
if (load_all_packs)
load_all();
else
diff --git a/builtin/repack.c b/builtin/repack.c
index 279be11a16..2158b48f4c 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -14,6 +14,7 @@
#include "object-store.h"
#include "promisor-remote.h"
#include "shallow.h"
+#include "pack.h"
static int delta_base_offset = 1;
static int pack_kept_objects = -1;
@@ -263,7 +264,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
while (strbuf_getline_lf(&line, out) != EOF) {
struct string_list_item *item;
char *promisor_name;
- int fd;
+
if (line.len != the_hash_algo->hexsz)
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
item = string_list_append(names, line.buf);
@@ -281,10 +282,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
*/
promisor_name = mkpathdup("%s-%s.promisor", packtmp,
line.buf);
- fd = open(promisor_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
- if (fd < 0)
- die_errno(_("unable to create '%s'"), promisor_name);
- close(fd);
+ write_promisor_file(promisor_name, NULL, 0);
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 1c0b3a9b05..3e7ab1ca82 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -61,8 +61,7 @@ static void insert_one_record(struct shortlog *log,
if (log->summary)
item->util = (void *)(UTIL_TO_INT(item) + 1);
else {
- const char *dot3 = log->common_repo_prefix;
- char *buffer, *p;
+ char *buffer;
struct strbuf subject = STRBUF_INIT;
const char *eol;
@@ -82,17 +81,6 @@ static void insert_one_record(struct shortlog *log,
format_subject(&subject, oneline, " ");
buffer = strbuf_detach(&subject, NULL);
- if (dot3) {
- int dot3len = strlen(dot3);
- if (dot3len > 5) {
- while ((p = strstr(buffer, dot3)) != NULL) {
- int taillen = strlen(p) - dot3len;
- memcpy(p, "/.../", 5);
- memmove(p + 5, p + dot3len, taillen + 1);
- }
- }
- }
-
if (item->util == NULL)
item->util = xcalloc(1, sizeof(struct string_list));
string_list_append(item->util, buffer);
@@ -342,7 +330,7 @@ void shortlog_init(struct shortlog *log)
{
memset(log, 0, sizeof(*log));
- read_mailmap(&log->mailmap, &log->common_repo_prefix);
+ read_mailmap(&log->mailmap);
log->list.strdup_strings = 1;
log->wrap = DEFAULT_WRAPLEN;
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index ae60b4acf2..7f8a5332f8 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -40,7 +40,7 @@ static void show_one(const char *refname, const struct object_id *oid)
if (!deref_tags)
return;
- if (!peel_ref(refname, &peeled)) {
+ if (!peel_iterated_oid(oid, &peeled)) {
hex = find_unique_abbrev(&peeled, abbrev);
printf("%s %s^{}\n", hex, refname);
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index e3140db2a0..2306a9ad98 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -22,11 +22,6 @@ static char const * const builtin_sparse_checkout_usage[] = {
NULL
};
-static char *get_sparse_checkout_filename(void)
-{
- return git_pathdup("info/sparse-checkout");
-}
-
static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
{
int i;
diff --git a/builtin/tag.c b/builtin/tag.c
index ecf011776d..e8b85eefd8 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -72,10 +72,10 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
}
typedef int (*each_tag_name_fn)(const char *name, const char *ref,
- const struct object_id *oid, const void *cb_data);
+ const struct object_id *oid, void *cb_data);
static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
- const void *cb_data)
+ void *cb_data)
{
const char **p;
struct strbuf ref = STRBUF_INIT;
@@ -97,18 +97,42 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
return had_error;
}
-static int delete_tag(const char *name, const char *ref,
- const struct object_id *oid, const void *cb_data)
+static int collect_tags(const char *name, const char *ref,
+ const struct object_id *oid, void *cb_data)
{
- if (delete_ref(NULL, ref, oid, 0))
- return 1;
- printf(_("Deleted tag '%s' (was %s)\n"), name,
- find_unique_abbrev(oid, DEFAULT_ABBREV));
+ struct string_list *ref_list = cb_data;
+
+ string_list_append(ref_list, ref);
+ ref_list->items[ref_list->nr - 1].util = oiddup(oid);
return 0;
}
+static int delete_tags(const char **argv)
+{
+ int result;
+ struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+
+ result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete);
+ if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
+ result = 1;
+
+ for_each_string_list_item(item, &refs_to_delete) {
+ const char *name = item->string;
+ struct object_id *oid = item->util;
+ if (!ref_exists(name))
+ printf(_("Deleted tag '%s' (was %s)\n"),
+ item->string + 10,
+ find_unique_abbrev(oid, DEFAULT_ABBREV));
+
+ free(oid);
+ }
+ string_list_clear(&refs_to_delete, 0);
+ return result;
+}
+
static int verify_tag(const char *name, const char *ref,
- const struct object_id *oid, const void *cb_data)
+ const struct object_id *oid, void *cb_data)
{
int flags;
const struct ref_format *format = cb_data;
@@ -485,7 +509,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
}
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
if (cmdmode == 'l') {
int ret;
@@ -512,7 +536,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (filter.reachable_from || filter.unreachable_from)
die(_("--merged and --no-merged options are only allowed in list mode"));
if (cmdmode == 'd')
- return for_each_tag_name(argv, delete_tag, NULL);
+ return delete_tags(argv);
if (cmdmode == 'v') {
if (format.format && verify_ref_format(&format))
usage_with_options(git_tag_usage, options);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 71287b2da6..1cd5c2016e 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -12,6 +12,7 @@
#include "submodule.h"
#include "utf8.h"
#include "worktree.h"
+#include "quote.h"
static const char * const worktree_usage[] = {
N_("git worktree add [<options>] <path> [<commit-ish>]"),
@@ -67,79 +68,6 @@ static void delete_worktrees_dir_if_empty(void)
rmdir(git_path("worktrees")); /* ignore failed removal */
}
-/*
- * Return true if worktree entry should be pruned, along with the reason for
- * pruning. Otherwise, return false and the worktree's path, or NULL if it
- * cannot be determined. Caller is responsible for freeing returned path.
- */
-static int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath)
-{
- struct stat st;
- char *path;
- int fd;
- size_t len;
- ssize_t read_result;
-
- *wtpath = NULL;
- if (!is_directory(git_path("worktrees/%s", id))) {
- strbuf_addstr(reason, _("not a valid directory"));
- return 1;
- }
- if (file_exists(git_path("worktrees/%s/locked", id)))
- return 0;
- if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
- strbuf_addstr(reason, _("gitdir file does not exist"));
- return 1;
- }
- fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
- if (fd < 0) {
- strbuf_addf(reason, _("unable to read gitdir file (%s)"),
- strerror(errno));
- return 1;
- }
- len = xsize_t(st.st_size);
- path = xmallocz(len);
-
- read_result = read_in_full(fd, path, len);
- if (read_result < 0) {
- strbuf_addf(reason, _("unable to read gitdir file (%s)"),
- strerror(errno));
- close(fd);
- free(path);
- return 1;
- }
- close(fd);
-
- if (read_result != len) {
- strbuf_addf(reason,
- _("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
- (uintmax_t)len, (uintmax_t)read_result);
- free(path);
- return 1;
- }
- while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
- len--;
- if (!len) {
- strbuf_addstr(reason, _("invalid gitdir file"));
- free(path);
- return 1;
- }
- path[len] = '\0';
- if (!file_exists(path)) {
- if (stat(git_path("worktrees/%s/index", id), &st) ||
- st.st_mtime <= expire) {
- strbuf_addstr(reason, _("gitdir file points to non-existent location"));
- free(path);
- return 1;
- } else {
- *wtpath = path;
- return 0;
- }
- }
- *wtpath = path;
- return 0;
-}
-
static void prune_worktree(const char *id, const char *reason)
{
if (show_only || verbose)
@@ -195,7 +123,7 @@ static void prune_worktrees(void)
if (is_dot_or_dotdot(d->d_name))
continue;
strbuf_reset(&reason);
- if (should_prune_worktree(d->d_name, &reason, &path))
+ if (should_prune_worktree(d->d_name, &reason, &path, expire))
prune_worktree(d->d_name, reason.buf);
else if (path)
string_list_append(&kept, path)->util = xstrdup(d->d_name);
@@ -642,6 +570,8 @@ static int add(int ac, const char **av, const char *prefix)
static void show_worktree_porcelain(struct worktree *wt)
{
+ const char *reason;
+
printf("worktree %s\n", wt->path);
if (wt->is_bare)
printf("bare\n");
@@ -652,6 +582,20 @@ static void show_worktree_porcelain(struct worktree *wt)
else if (wt->head_ref)
printf("branch %s\n", wt->head_ref);
}
+
+ reason = worktree_lock_reason(wt);
+ if (reason && *reason) {
+ struct strbuf sb = STRBUF_INIT;
+ quote_c_style(reason, &sb, NULL, 0);
+ printf("locked %s\n", sb.buf);
+ strbuf_release(&sb);
+ } else if (reason)
+ printf("locked\n");
+
+ reason = worktree_prune_reason(wt, expire);
+ if (reason)
+ printf("prunable %s\n", reason);
+
printf("\n");
}
@@ -660,6 +604,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
struct strbuf sb = STRBUF_INIT;
int cur_path_len = strlen(wt->path);
int path_adj = cur_path_len - utf8_strwidth(wt->path);
+ const char *reason;
strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path);
if (wt->is_bare)
@@ -677,9 +622,18 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(error)");
}
- if (!is_main_worktree(wt) && worktree_lock_reason(wt))
+ reason = worktree_lock_reason(wt);
+ if (verbose && reason && *reason)
+ strbuf_addf(&sb, "\n\tlocked: %s", reason);
+ else if (reason)
strbuf_addstr(&sb, " locked");
+ reason = worktree_prune_reason(wt, expire);
+ if (verbose && reason)
+ strbuf_addf(&sb, "\n\tprunable: %s", reason);
+ else if (reason)
+ strbuf_addstr(&sb, " prunable");
+
printf("%s\n", sb.buf);
strbuf_release(&sb);
}
@@ -723,12 +677,18 @@ static int list(int ac, const char **av, const char *prefix)
struct option options[] = {
OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+ OPT__VERBOSE(&verbose, N_("show extended annotations and reasons, if available")),
+ OPT_EXPIRY_DATE(0, "expire", &expire,
+ N_("add 'prunable' annotation to worktrees older than <time>")),
OPT_END()
};
+ expire = TIME_MAX;
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
if (ac)
usage_with_options(worktree_usage, options);
+ else if (verbose && porcelain)
+ die(_("--verbose and --porcelain are mutually exclusive"));
else {
struct worktree **worktrees = get_worktrees();
int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;