summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c4
-rw-r--r--builtin/apply.c3
-rw-r--r--builtin/blame.c27
-rw-r--r--builtin/branch.c34
-rw-r--r--builtin/bundle.c8
-rw-r--r--builtin/cat-file.c102
-rw-r--r--builtin/checkout.c4
-rw-r--r--builtin/clean.c8
-rw-r--r--builtin/clone.c21
-rw-r--r--builtin/commit.c5
-rw-r--r--builtin/describe.c12
-rw-r--r--builtin/fetch.c15
-rw-r--r--builtin/for-each-ref.c37
-rw-r--r--builtin/fsck.c20
-rw-r--r--builtin/index-pack.c8
-rw-r--r--builtin/log.c21
-rw-r--r--builtin/merge.c250
-rw-r--r--builtin/name-rev.c6
-rw-r--r--builtin/pack-objects.c14
-rw-r--r--builtin/receive-pack.c5
-rw-r--r--builtin/reflog.c9
-rw-r--r--builtin/remote.c21
-rw-r--r--builtin/replace.c16
-rw-r--r--builtin/rev-parse.c8
-rw-r--r--builtin/rm.c3
-rw-r--r--builtin/show-branch.c73
-rw-r--r--builtin/show-ref.c28
-rw-r--r--builtin/tag.c18
-rw-r--r--builtin/update-index.c188
29 files changed, 651 insertions, 317 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 3390933d68..df5135bf62 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -63,6 +63,7 @@ static void update_callback(struct diff_queue_struct *q,
switch (fix_unmerged_status(p, data)) {
default:
die(_("unexpected diff status %c"), p->status);
+ case DIFF_STATUS_ADDED:
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
if (add_file_to_index(&the_index, path, data->flags)) {
@@ -208,7 +209,8 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
if (run_diff_files(&rev, 0))
die(_("Could not write patch"));
- launch_editor(file, NULL, NULL);
+ if (launch_editor(file, NULL, NULL))
+ die(_("editing patch failed"));
if (stat(file, &st))
die_errno(_("Could not stat '%s'"), file);
diff --git a/builtin/apply.c b/builtin/apply.c
index 146be97a1a..54aba4e351 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1638,6 +1638,9 @@ static int parse_fragment(const char *line, unsigned long size,
}
if (oldlines || newlines)
return -1;
+ if (!deleted && !added)
+ return -1;
+
fragment->leading = leading;
fragment->trailing = trailing;
diff --git a/builtin/blame.c b/builtin/blame.c
index 8d70623cb8..a22ac17407 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -26,8 +26,9 @@
#include "userdiff.h"
#include "line-range.h"
#include "line-log.h"
+#include "dir.h"
-static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] file");
+static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
static const char *blame_opt_usage[] = {
blame_usage,
@@ -2151,16 +2152,6 @@ static void sanity_check_refcnt(struct scoreboard *sb)
}
}
-/*
- * Used for the command line parsing; check if the path exists
- * in the working tree.
- */
-static int has_string_in_work_tree(const char *path)
-{
- struct stat st;
- return !lstat(path, &st);
-}
-
static unsigned parse_score(const char *arg)
{
char *end;
@@ -2185,6 +2176,14 @@ static int git_blame_config(const char *var, const char *value, void *cb)
blank_boundary = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "blame.showemail")) {
+ int *output_option = cb;
+ if (git_config_bool(var, value))
+ *output_option |= OUTPUT_SHOW_EMAIL;
+ else
+ *output_option &= ~OUTPUT_SHOW_EMAIL;
+ return 0;
+ }
if (!strcmp(var, "blame.date")) {
if (!value)
return config_error_nonbool(var);
@@ -2529,7 +2528,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
- git_config(git_blame_config, NULL);
+ git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
@@ -2656,14 +2655,14 @@ parse_done:
if (argc < 2)
usage_with_options(blame_opt_usage, options);
path = add_prefix(prefix, argv[argc - 1]);
- if (argc == 3 && !has_string_in_work_tree(path)) { /* (2b) */
+ if (argc == 3 && !file_exists(path)) { /* (2b) */
path = add_prefix(prefix, argv[1]);
argv[1] = argv[2];
}
argv[argc - 1] = "--";
setup_work_tree();
- if (!has_string_in_work_tree(path))
+ if (!file_exists(path))
die_errno("cannot stat path '%s'", path);
}
diff --git a/builtin/branch.c b/builtin/branch.c
index 258fe2ff9b..b42e5b6dbc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -123,14 +123,12 @@ static int branch_merged(int kind, const char *name,
if (kind == REF_LOCAL_BRANCH) {
struct branch *branch = branch_get(name);
+ const char *upstream = branch_get_upstream(branch, NULL);
unsigned char sha1[20];
- if (branch &&
- branch->merge &&
- branch->merge[0] &&
- branch->merge[0]->dst &&
+ if (upstream &&
(reference_name = reference_name_to_free =
- resolve_refdup(branch->merge[0]->dst, RESOLVE_REF_READING,
+ resolve_refdup(upstream, RESOLVE_REF_READING,
sha1, NULL)) != NULL)
reference_rev = lookup_commit_reference(sha1);
}
@@ -242,7 +240,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
sha1, &flags);
if (!target) {
error(remote_branch
- ? _("remote branch '%s' not found.")
+ ? _("remote-tracking branch '%s' not found.")
: _("branch '%s' not found."), bname.buf);
ret = 1;
continue;
@@ -257,7 +255,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (delete_ref(name, sha1, REF_NODEREF)) {
error(remote_branch
- ? _("Error deleting remote branch '%s'")
+ ? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
@@ -265,7 +263,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
if (!quiet) {
printf(remote_branch
- ? _("Deleted remote branch %s (was %s).\n")
+ ? _("Deleted remote-tracking branch %s (was %s).\n")
: _("Deleted branch %s (was %s).\n"),
bname.buf,
(flags & REF_ISBROKEN) ? "broken"
@@ -328,7 +326,7 @@ static int match_patterns(const char **pattern, const char *refname)
return 0;
}
-static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
{
struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data);
struct ref_list *ref_list = cb->ref_list;
@@ -365,7 +363,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
commit = NULL;
if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
- commit = lookup_commit_reference_gently(sha1, 1);
+ commit = lookup_commit_reference_gently(oid->hash, 1);
if (!commit) {
cb->ret = error(_("branch '%s' does not point at a commit"), refname);
return 0;
@@ -427,25 +425,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
int ours, theirs;
char *ref = NULL;
struct branch *branch = branch_get(branch_name);
+ const char *upstream;
struct strbuf fancy = STRBUF_INIT;
int upstream_is_gone = 0;
int added_decoration = 1;
- switch (stat_tracking_info(branch, &ours, &theirs)) {
- case 0:
- /* no base */
- return;
- case -1:
- /* with "gone" base */
+ if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {
+ if (!upstream)
+ return;
upstream_is_gone = 1;
- break;
- default:
- /* with base */
- break;
}
if (show_upstream_ref) {
- ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+ ref = shorten_unambiguous_ref(upstream, 0);
if (want_color(branch_use_color))
strbuf_addf(&fancy, "%s%s%s",
branch_get_color(BRANCH_COLOR_UPSTREAM),
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 92a8a6026a..4883a435a9 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -42,6 +42,10 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
if (!strcmp(cmd, "verify")) {
close(bundle_fd);
+ if (argc != 1) {
+ usage(builtin_bundle_usage);
+ return 1;
+ }
if (verify_bundle(&header, 1))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
@@ -52,6 +56,10 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
return !!list_bundle_refs(&header, argc, argv);
}
if (!strcmp(cmd, "create")) {
+ if (argc < 2) {
+ usage(builtin_bundle_usage);
+ return 1;
+ }
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
return !!create_bundle(&header, bundle_file, argc, argv);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index df99df4db1..049a95f1f1 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -8,14 +8,22 @@
#include "parse-options.h"
#include "userdiff.h"
#include "streaming.h"
+#include "tree-walk.h"
-static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
+static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
+ int unknown_type)
{
unsigned char sha1[20];
enum object_type type;
char *buf;
unsigned long size;
struct object_context obj_context;
+ struct object_info oi = {NULL};
+ struct strbuf sb = STRBUF_INIT;
+ unsigned flags = LOOKUP_REPLACE_OBJECT;
+
+ if (unknown_type)
+ flags |= LOOKUP_UNKNOWN_OBJECT;
if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
die("Not a valid object name %s", obj_name);
@@ -23,20 +31,22 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
buf = NULL;
switch (opt) {
case 't':
- type = sha1_object_info(sha1, NULL);
- if (type > 0) {
- printf("%s\n", typename(type));
+ oi.typename = &sb;
+ if (sha1_object_info_extended(sha1, &oi, flags) < 0)
+ die("git cat-file: could not get object info");
+ if (sb.len) {
+ printf("%s\n", sb.buf);
+ strbuf_release(&sb);
return 0;
}
break;
case 's':
- type = sha1_object_info(sha1, &size);
- if (type > 0) {
- printf("%lu\n", size);
- return 0;
- }
- break;
+ oi.sizep = &size;
+ if (sha1_object_info_extended(sha1, &oi, flags) < 0)
+ die("git cat-file: could not get object info");
+ printf("%lu\n", size);
+ return 0;
case 'e':
return !has_sha1_file(sha1);
@@ -224,6 +234,7 @@ static void print_object_or_die(int fd, struct expand_data *data)
struct batch_options {
int enabled;
+ int follow_symlinks;
int print_contents;
const char *format;
};
@@ -232,12 +243,44 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
struct expand_data *data)
{
struct strbuf buf = STRBUF_INIT;
+ struct object_context ctx;
+ int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
+ enum follow_symlinks_result result;
if (!obj_name)
return 1;
- if (get_sha1(obj_name, data->sha1)) {
- printf("%s missing\n", obj_name);
+ result = get_sha1_with_context(obj_name, flags, data->sha1, &ctx);
+ if (result != FOUND) {
+ switch (result) {
+ case MISSING_OBJECT:
+ printf("%s missing\n", obj_name);
+ break;
+ case DANGLING_SYMLINK:
+ printf("dangling %"PRIuMAX"\n%s\n",
+ (uintmax_t)strlen(obj_name), obj_name);
+ break;
+ case SYMLINK_LOOP:
+ printf("loop %"PRIuMAX"\n%s\n",
+ (uintmax_t)strlen(obj_name), obj_name);
+ break;
+ case NOT_DIR:
+ printf("notdir %"PRIuMAX"\n%s\n",
+ (uintmax_t)strlen(obj_name), obj_name);
+ break;
+ default:
+ die("BUG: unknown get_sha1_with_context result %d\n",
+ result);
+ break;
+ }
+ fflush(stdout);
+ return 0;
+ }
+
+ if (ctx.mode == 0) {
+ printf("symlink %"PRIuMAX"\n%s\n",
+ (uintmax_t)ctx.symlink_path.len,
+ ctx.symlink_path.buf);
fflush(stdout);
return 0;
}
@@ -323,8 +366,8 @@ static int batch_objects(struct batch_options *opt)
}
static const char * const cat_file_usage[] = {
- N_("git cat-file (-t | -s | -e | -p | <type> | --textconv) <object>"),
- N_("git cat-file (--batch | --batch-check) < <list-of-objects>"),
+ N_("git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|<type>|--textconv) <object>"),
+ N_("git cat-file (--batch | --batch-check) [--follow-symlinks] < <list-of-objects>"),
NULL
};
@@ -342,9 +385,8 @@ static int batch_option_callback(const struct option *opt,
{
struct batch_options *bo = opt->value;
- if (unset) {
- memset(bo, 0, sizeof(*bo));
- return 0;
+ if (bo->enabled) {
+ return 1;
}
bo->enabled = 1;
@@ -359,30 +401,32 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
int opt = 0;
const char *exp_type = NULL, *obj_name = NULL;
struct batch_options batch = {0};
+ int unknown_type = 0;
const struct option options[] = {
OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
- OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'),
- OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'),
- OPT_SET_INT('e', NULL, &opt,
+ OPT_CMDMODE('t', NULL, &opt, N_("show object type"), 't'),
+ OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
+ OPT_CMDMODE('e', NULL, &opt,
N_("exit with zero when there's no error"), 'e'),
- OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
- OPT_SET_INT(0, "textconv", &opt,
+ OPT_CMDMODE('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
+ OPT_CMDMODE(0, "textconv", &opt,
N_("for blob objects, run textconv on object's content"), 'c'),
+ OPT_BOOL( 0, "allow-unknown-type", &unknown_type,
+ N_("allow -s and -t to work with broken/corrupt objects")),
{ OPTION_CALLBACK, 0, "batch", &batch, "format",
N_("show info and content of objects fed from the standard input"),
PARSE_OPT_OPTARG, batch_option_callback },
{ OPTION_CALLBACK, 0, "batch-check", &batch, "format",
N_("show info about objects fed from the standard input"),
PARSE_OPT_OPTARG, batch_option_callback },
+ OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
+ N_("follow in-tree symlinks (used with --batch or --batch-check)")),
OPT_END()
};
git_config(git_cat_file_config, NULL);
- if (argc != 3 && argc != 2)
- usage_with_options(cat_file_usage, options);
-
argc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);
if (opt) {
@@ -402,8 +446,14 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
usage_with_options(cat_file_usage, options);
}
+ if (batch.follow_symlinks && !batch.enabled) {
+ usage_with_options(cat_file_usage, options);
+ }
+
if (batch.enabled)
return batch_objects(&batch);
- return cat_one_file(opt, exp_type, obj_name);
+ if (unknown_type && opt != 't' && opt != 's')
+ die("git cat-file --allow-unknown-type: use with -s or -t");
+ return cat_one_file(opt, exp_type, obj_name, unknown_type);
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2f92328db4..9b49f0e413 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -702,10 +702,10 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
}
static int add_pending_uninteresting_ref(const char *refname,
- const unsigned char *sha1,
+ const struct object_id *oid,
int flags, void *cb_data)
{
- add_pending_sha1(cb_data, refname, sha1, UNINTERESTING);
+ add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING);
return 0;
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 98c103fa8b..6dcb72e644 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -314,7 +314,6 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
{
struct string_list menu_list = STRING_LIST_INIT_DUP;
struct strbuf menu = STRBUF_INIT;
- struct strbuf buf = STRBUF_INIT;
struct menu_item *menu_item;
struct string_list_item *string_list_item;
int i;
@@ -363,7 +362,6 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
pretty_print_menus(&menu_list);
strbuf_release(&menu);
- strbuf_release(&buf);
string_list_clear(&menu_list, 0);
}
@@ -941,15 +939,15 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!cache_name_is_other(ent->name, ent->len))
continue;
- if (lstat(ent->name, &st))
- die_errno("Cannot lstat '%s'", ent->name);
-
if (pathspec.nr)
matches = dir_path_match(ent, &pathspec, 0, NULL);
if (pathspec.nr && !matches)
continue;
+ if (lstat(ent->name, &st))
+ die_errno("Cannot lstat '%s'", ent->name);
+
if (S_ISDIR(st.st_mode) && !remove_directories &&
matches != MATCHED_EXACTLY)
continue;
diff --git a/builtin/clone.c b/builtin/clone.c
index 166a645e2d..00535d0178 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -51,15 +51,6 @@ static struct string_list option_config;
static struct string_list option_reference;
static int option_dissociate;
-static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
-{
- struct string_list *option_reference = opt->value;
- if (!arg)
- return -1;
- string_list_append(option_reference, arg);
- return 0;
-}
-
static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
@@ -83,8 +74,10 @@ static struct option builtin_clone_options[] = {
N_("initialize submodules in the clone")),
OPT_STRING(0, "template", &option_template, N_("template-directory"),
N_("directory from which templates will be used")),
- OPT_CALLBACK(0 , "reference", &option_reference, N_("repo"),
- N_("reference repository"), &opt_parse_reference),
+ OPT_STRING_LIST(0, "reference", &option_reference, N_("repo"),
+ N_("reference repository")),
+ OPT_BOOL(0, "dissociate", &option_dissociate,
+ N_("use --reference only while cloning")),
OPT_STRING('o', "origin", &option_origin, N_("name"),
N_("use <name> instead of 'origin' to track upstream")),
OPT_STRING('b', "branch", &option_branch, N_("branch"),
@@ -95,8 +88,6 @@ static struct option builtin_clone_options[] = {
N_("create a shallow clone of that depth")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
- OPT_BOOL(0, "dissociate", &option_dissociate,
- N_("use --reference only while cloning")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
@@ -907,6 +898,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
+ transport_set_verbosity(transport, option_verbosity, option_progress);
+
path = get_repo_path(remote->url[0], &is_bundle);
is_local = option_local != 0 && path && !is_bundle;
if (is_local) {
@@ -933,8 +926,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_single_branch)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- transport_set_verbosity(transport, option_verbosity, option_progress);
-
if (option_upload_pack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK,
option_upload_pack);
diff --git a/builtin/commit.c b/builtin/commit.c
index d6515a2a50..254477fd1d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1366,13 +1366,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
fd = hold_locked_index(&index_lock, 0);
- if (0 <= fd)
- update_index_if_able(&the_index, &index_lock);
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
s.ignore_submodule_arg = ignore_submodule_arg;
wt_status_collect(&s);
+ if (0 <= fd)
+ update_index_if_able(&the_index, &index_lock);
+
if (s.relative_paths)
s.prefix = prefix;
diff --git a/builtin/describe.c b/builtin/describe.c
index e00a75b121..a36c829e57 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -119,10 +119,10 @@ static void add_to_known_names(const char *path,
}
}
-static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int get_name(const char *path, const struct object_id *oid, int flag, void *cb_data)
{
int is_tag = starts_with(path, "refs/tags/");
- unsigned char peeled[20];
+ struct object_id peeled;
int is_annotated, prio;
/* Reject anything outside refs/tags/ unless --all */
@@ -134,10 +134,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
return 0;
/* Is it annotated? */
- if (!peel_ref(path, peeled)) {
- is_annotated = !!hashcmp(sha1, peeled);
+ if (!peel_ref(path, peeled.hash)) {
+ is_annotated = !!oidcmp(oid, &peeled);
} else {
- hashcpy(peeled, sha1);
+ oidcpy(&peeled, oid);
is_annotated = 0;
}
@@ -154,7 +154,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
else
prio = 0;
- add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
+ add_to_known_names(all ? path + 5 : path + 10, peeled.hash, prio, oid->hash);
return 0;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7910419c93..8d5b2dba2b 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -179,13 +179,15 @@ static void add_merge_config(struct ref **head,
}
}
-static int add_existing(const char *refname, const unsigned char *sha1,
+static int add_existing(const char *refname, const struct object_id *oid,
int flag, void *cbdata)
{
struct string_list *list = (struct string_list *)cbdata;
struct string_list_item *item = string_list_insert(list, refname);
- item->util = xmalloc(20);
- hashcpy(item->util, sha1);
+ struct object_id *old_oid = xmalloc(sizeof(*old_oid));
+
+ oidcpy(old_oid, oid);
+ item->util = old_oid;
return 0;
}
@@ -913,9 +915,10 @@ static int do_fetch(struct transport *transport,
struct string_list_item *peer_item =
string_list_lookup(&existing_refs,
rm->peer_ref->name);
- if (peer_item)
- hashcpy(rm->peer_ref->old_sha1,
- peer_item->util);
+ if (peer_item) {
+ struct object_id *old_oid = peer_item->util;
+ hashcpy(rm->peer_ref->old_sha1, old_oid->hash);
+ }
}
}
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 83f9cf9163..f7e51a7fad 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -74,6 +74,7 @@ static struct {
{ "contents:body" },
{ "contents:signature" },
{ "upstream" },
+ { "push" },
{ "symref" },
{ "flag" },
{ "HEAD" },
@@ -659,15 +660,26 @@ static void populate_value(struct refinfo *ref)
else if (starts_with(name, "symref"))
refname = ref->symref ? ref->symref : "";
else if (starts_with(name, "upstream")) {
+ const char *branch_name;
/* only local branches may have an upstream */
- if (!starts_with(ref->refname, "refs/heads/"))
+ if (!skip_prefix(ref->refname, "refs/heads/",
+ &branch_name))
continue;
- branch = branch_get(ref->refname + 11);
+ branch = branch_get(branch_name);
- if (!branch || !branch->merge || !branch->merge[0] ||
- !branch->merge[0]->dst)
+ refname = branch_get_upstream(branch, NULL);
+ if (!refname)
+ continue;
+ } else if (starts_with(name, "push")) {
+ const char *branch_name;
+ if (!skip_prefix(ref->refname, "refs/heads/",
+ &branch_name))
+ continue;
+ branch = branch_get(branch_name);
+
+ refname = branch_get_push(branch, NULL);
+ if (!refname)
continue;
- refname = branch->merge[0]->dst;
} else if (starts_with(name, "color:")) {
char color[COLOR_MAXLEN] = "";
@@ -713,11 +725,12 @@ static void populate_value(struct refinfo *ref)
refname = shorten_unambiguous_ref(refname,
warn_ambiguous_refs);
else if (!strcmp(formatp, "track") &&
- starts_with(name, "upstream")) {
+ (starts_with(name, "upstream") ||
+ starts_with(name, "push"))) {
char buf[40];
if (stat_tracking_info(branch, &num_ours,
- &num_theirs) != 1)
+ &num_theirs, NULL))
continue;
if (!num_ours && !num_theirs)
@@ -735,11 +748,12 @@ static void populate_value(struct refinfo *ref)
}
continue;
} else if (!strcmp(formatp, "trackshort") &&
- starts_with(name, "upstream")) {
+ (starts_with(name, "upstream") ||
+ starts_with(name, "push"))) {
assert(branch);
if (stat_tracking_info(branch, &num_ours,
- &num_theirs) != 1)
+ &num_theirs, NULL))
continue;
if (!num_ours && !num_theirs)
@@ -840,7 +854,8 @@ struct grab_ref_cbdata {
* A call-back given to for_each_ref(). Filter refs and keep them for
* later object processing.
*/
-static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int grab_single_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
struct grab_ref_cbdata *cb = cb_data;
struct refinfo *ref;
@@ -878,7 +893,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
*/
ref = xcalloc(1, sizeof(*ref));
ref->refname = xstrdup(refname);
- hashcpy(ref->objectname, sha1);
+ hashcpy(ref->objectname, oid->hash);
ref->flag = flag;
cnt = cb->grab_cnt;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 4783896fd6..4e8e2ee5b7 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -25,7 +25,7 @@ static int include_reflogs = 1;
static int check_full = 1;
static int check_strict;
static int keep_cache_objects;
-static unsigned char head_sha1[20];
+static struct object_id head_oid;
static const char *head_points_at;
static int errors_found;
static int write_lost_and_found;
@@ -476,19 +476,21 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0;
}
-static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, int flag, void *cb_data)
+static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
+ int flag, void *cb_data)
{
for_each_reflog_ent(logname, fsck_handle_reflog_ent, NULL);
return 0;
}
-static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int fsck_handle_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
struct object *obj;
- obj = parse_object(sha1);
+ obj = parse_object(oid->hash);
if (!obj) {
- error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
+ error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
/* We'll continue with the rest despite the error.. */
return 0;
@@ -504,8 +506,8 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
static void get_default_heads(void)
{
- if (head_points_at && !is_null_sha1(head_sha1))
- fsck_handle_ref("HEAD", head_sha1, 0, NULL);
+ if (head_points_at && !is_null_oid(&head_oid))
+ fsck_handle_ref("HEAD", &head_oid, 0, NULL);
for_each_rawref(fsck_handle_ref, NULL);
if (include_reflogs)
for_each_reflog(fsck_handle_reflog, NULL);
@@ -556,7 +558,7 @@ static int fsck_head_link(void)
if (verbose)
fprintf(stderr, "Checking HEAD link\n");
- head_points_at = resolve_ref_unsafe("HEAD", 0, head_sha1, &flag);
+ head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, &flag);
if (!head_points_at)
return error("Invalid HEAD");
if (!strcmp(head_points_at, "HEAD"))
@@ -565,7 +567,7 @@ static int fsck_head_link(void)
else if (!starts_with(head_points_at, "refs/heads/"))
return error("HEAD points to something strange (%s)",
head_points_at);
- if (is_null_sha1(head_sha1)) {
+ if (is_null_oid(&head_oid)) {
if (null_is_error)
return error("HEAD: detached HEAD points at nothing");
fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n",
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 7ea2020d82..2ecfbae239 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -616,7 +616,9 @@ static int compare_ofs_delta_bases(off_t offset1, off_t offset2,
int cmp = type1 - type2;
if (cmp)
return cmp;
- return offset1 - offset2;
+ return offset1 < offset2 ? -1 :
+ offset1 > offset2 ? 1 :
+ 0;
}
static int find_ofs_delta(const off_t offset, enum object_type type)
@@ -1051,7 +1053,9 @@ static int compare_ofs_delta_entry(const void *a, const void *b)
const struct ofs_delta_entry *delta_a = a;
const struct ofs_delta_entry *delta_b = b;
- return delta_a->offset - delta_b->offset;
+ return delta_a->offset < delta_b->offset ? -1 :
+ delta_a->offset > delta_b->offset ? 1 :
+ 0;
}
static int compare_ref_delta_entry(const void *a, const void *b)
diff --git a/builtin/log.c b/builtin/log.c
index dd8f3fcfc4..878104943f 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -38,7 +38,7 @@ static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- N_("git log [<options>] [<revision range>] [[--] <path>...]"),
+ N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
N_("git show [<options>] <object>..."),
NULL
};
@@ -795,7 +795,7 @@ static int reopen_stdout(struct commit *commit, const char *subject,
static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
{
struct rev_info check_rev;
- struct commit *commit;
+ struct commit *commit, *c1, *c2;
struct object *o1, *o2;
unsigned flags1, flags2;
@@ -803,9 +803,11 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
die(_("Need exactly one range."));
o1 = rev->pending.objects[0].item;
- flags1 = o1->flags;
o2 = rev->pending.objects[1].item;
+ flags1 = o1->flags;
flags2 = o2->flags;
+ c1 = lookup_commit_reference(o1->sha1);
+ c2 = lookup_commit_reference(o2->sha1);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("Not a range."));
@@ -827,10 +829,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
}
/* reset for next revision walk */
- clear_commit_marks((struct commit *)o1,
- SEEN | UNINTERESTING | SHOWN | ADDED);
- clear_commit_marks((struct commit *)o2,
- SEEN | UNINTERESTING | SHOWN | ADDED);
+ clear_commit_marks(c1, SEEN | UNINTERESTING | SHOWN | ADDED);
+ clear_commit_marks(c2, SEEN | UNINTERESTING | SHOWN | ADDED);
o1->flags = flags1;
o2->flags = flags2;
}
@@ -1632,16 +1632,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
break;
default:
current_branch = branch_get(NULL);
- if (!current_branch || !current_branch->merge
- || !current_branch->merge[0]
- || !current_branch->merge[0]->dst) {
+ upstream = branch_get_upstream(current_branch, NULL);
+ if (!upstream) {
fprintf(stderr, _("Could not find a tracked"
" remote branch, please"
" specify <upstream> manually.\n"));
usage_with_options(cherry_usage, options);
}
-
- upstream = current_branch->merge[0]->dst;
}
init_revisions(&revs, prefix);
diff --git a/builtin/merge.c b/builtin/merge.c
index 3b0f8f96d4..85c54dcd5a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -492,8 +492,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
}
if (len) {
struct strbuf truname = STRBUF_INIT;
- strbuf_addstr(&truname, "refs/heads/");
- strbuf_addstr(&truname, remote);
+ strbuf_addf(&truname, "refs/heads/%s", remote);
strbuf_setlen(&truname, truname.len - len);
if (ref_exists(truname.buf)) {
strbuf_addf(msg,
@@ -504,28 +503,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_release(&truname);
goto cleanup;
}
- }
-
- if (!strcmp(remote, "FETCH_HEAD") &&
- !access(git_path("FETCH_HEAD"), R_OK)) {
- const char *filename;
- FILE *fp;
- struct strbuf line = STRBUF_INIT;
- char *ptr;
-
- filename = git_path("FETCH_HEAD");
- fp = fopen(filename, "r");
- if (!fp)
- die_errno(_("could not open '%s' for reading"),
- filename);
- strbuf_getline(&line, fp, '\n');
- fclose(fp);
- ptr = strstr(line.buf, "\tnot-for-merge\t");
- if (ptr)
- strbuf_remove(&line, ptr-line.buf+1, 13);
- strbuf_addbuf(msg, &line);
- strbuf_release(&line);
- goto cleanup;
+ strbuf_release(&truname);
}
if (remote_head->util) {
@@ -955,7 +933,7 @@ static int setup_with_upstream(const char ***argv)
if (!branch)
die(_("No current branch."));
- if (!branch->remote)
+ if (!branch->remote_name)
die(_("No remote for the current branch."));
if (!branch->merge_nr)
die(_("No default upstream defined for the current branch."));
@@ -1037,28 +1015,24 @@ static int default_edit_option(void)
st_stdin.st_mode == st_stdout.st_mode);
}
-static struct commit_list *collect_parents(struct commit *head_commit,
- int *head_subsumed,
- int argc, const char **argv)
+static struct commit_list *reduce_parents(struct commit *head_commit,
+ int *head_subsumed,
+ struct commit_list *remoteheads)
{
- int i;
- struct commit_list *remoteheads = NULL, *parents, *next;
- struct commit_list **remotes = &remoteheads;
+ struct commit_list *parents, *next, **remotes = &remoteheads;
- if (head_commit)
- remotes = &commit_list_insert(head_commit, remotes)->next;
- for (i = 0; i < argc; i++) {
- struct commit *commit = get_merge_parent(argv[i]);
- if (!commit)
- help_unknown_ref(argv[i], "merge",
- "not something we can merge");
- remotes = &commit_list_insert(commit, remotes)->next;
- }
- *remotes = NULL;
+ /*
+ * Is the current HEAD reachable from another commit being
+ * merged? If so we do not want to record it as a parent of
+ * the resulting merge, unless --no-ff is given. We will flip
+ * this variable to 0 when we find HEAD among the independent
+ * tips being merged.
+ */
+ *head_subsumed = 1;
+ /* Find what parents to record by checking independent ones. */
parents = reduce_heads(remoteheads);
- *head_subsumed = 1; /* we will flip this to 0 when we find it */
for (remoteheads = NULL, remotes = &remoteheads;
parents;
parents = next) {
@@ -1068,7 +1042,119 @@ static struct commit_list *collect_parents(struct commit *head_commit,
*head_subsumed = 0;
else
remotes = &commit_list_insert(commit, remotes)->next;
+ free(parents);
+ }
+ return remoteheads;
+}
+
+static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *merge_msg)
+{
+ struct fmt_merge_msg_opts opts;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.add_title = !have_message;
+ opts.shortlog_len = shortlog_len;
+ opts.credit_people = (0 < option_edit);
+
+ fmt_merge_msg(merge_names, merge_msg, &opts);
+ if (merge_msg->len)
+ strbuf_setlen(merge_msg, merge_msg->len - 1);
+}
+
+static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)
+{
+ const char *filename;
+ int fd, pos, npos;
+ struct strbuf fetch_head_file = STRBUF_INIT;
+
+ if (!merge_names)
+ merge_names = &fetch_head_file;
+
+ filename = git_path("FETCH_HEAD");
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ die_errno(_("could not open '%s' for reading"), filename);
+
+ if (strbuf_read(merge_names, fd, 0) < 0)
+ die_errno(_("could not read '%s'"), filename);
+ if (close(fd) < 0)
+ die_errno(_("could not close '%s'"), filename);
+
+ for (pos = 0; pos < merge_names->len; pos = npos) {
+ unsigned char sha1[20];
+ char *ptr;
+ struct commit *commit;
+
+ ptr = strchr(merge_names->buf + pos, '\n');
+ if (ptr)
+ npos = ptr - merge_names->buf + 1;
+ else
+ npos = merge_names->len;
+
+ if (npos - pos < 40 + 2 ||
+ get_sha1_hex(merge_names->buf + pos, sha1))
+ commit = NULL; /* bad */
+ else if (memcmp(merge_names->buf + pos + 40, "\t\t", 2))
+ continue; /* not-for-merge */
+ else {
+ char saved = merge_names->buf[pos + 40];
+ merge_names->buf[pos + 40] = '\0';
+ commit = get_merge_parent(merge_names->buf + pos);
+ merge_names->buf[pos + 40] = saved;
+ }
+ if (!commit) {
+ if (ptr)
+ *ptr = '\0';
+ die("not something we can merge in %s: %s",
+ filename, merge_names->buf + pos);
+ }
+ remotes = &commit_list_insert(commit, remotes)->next;
+ }
+
+ if (merge_names == &fetch_head_file)
+ strbuf_release(&fetch_head_file);
+}
+
+static struct commit_list *collect_parents(struct commit *head_commit,
+ int *head_subsumed,
+ int argc, const char **argv,
+ struct strbuf *merge_msg)
+{
+ int i;
+ struct commit_list *remoteheads = NULL;
+ struct commit_list **remotes = &remoteheads;
+ struct strbuf merge_names = STRBUF_INIT, *autogen = NULL;
+
+ if (merge_msg && (!have_message || shortlog_len))
+ autogen = &merge_names;
+
+ if (head_commit)
+ remotes = &commit_list_insert(head_commit, remotes)->next;
+
+ if (argc == 1 && !strcmp(argv[0], "FETCH_HEAD")) {
+ handle_fetch_head(remotes, autogen);
+ remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+ } else {
+ for (i = 0; i < argc; i++) {
+ struct commit *commit = get_merge_parent(argv[i]);
+ if (!commit)
+ help_unknown_ref(argv[i], "merge",
+ "not something we can merge");
+ remotes = &commit_list_insert(commit, remotes)->next;
+ }
+ remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+ if (autogen) {
+ struct commit_list *p;
+ for (p = remoteheads; p; p = p->next)
+ merge_name(merge_remote_util(p->item)->name, autogen);
+ }
}
+
+ if (autogen) {
+ prepare_merge_message(autogen, merge_msg);
+ strbuf_release(autogen);
+ }
+
return remoteheads;
}
@@ -1158,61 +1244,62 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
option_commit = 0;
}
- if (!abort_current_merge) {
- if (!argc) {
- if (default_to_upstream)
- argc = setup_with_upstream(&argv);
- else
- die(_("No commit specified and merge.defaultToUpstream not set."));
- } else if (argc == 1 && !strcmp(argv[0], "-"))
- argv[0] = "@{-1}";
+ if (!argc) {
+ if (default_to_upstream)
+ argc = setup_with_upstream(&argv);
+ else
+ die(_("No commit specified and merge.defaultToUpstream not set."));
+ } else if (argc == 1 && !strcmp(argv[0], "-")) {
+ argv[0] = "@{-1}";
}
+
if (!argc)
usage_with_options(builtin_merge_usage,
builtin_merge_options);
- /*
- * This could be traditional "merge <msg> HEAD <commit>..." and
- * the way we can tell it is to see if the second token is HEAD,
- * but some people might have misused the interface and used a
- * commit-ish that is the same as HEAD there instead.
- * Traditional format never would have "-m" so it is an
- * additional safety measure to check for it.
- */
-
- if (!have_message && head_commit &&
- is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
- strbuf_addstr(&merge_msg, argv[0]);
- head_arg = argv[1];
- argv += 2;
- argc -= 2;
- remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
- } else if (!head_commit) {
+ if (!head_commit) {
struct commit *remote_head;
/*
* If the merged head is a valid one there is no reason
* to forbid "git merge" into a branch yet to be born.
* We do the same for "git pull".
*/
- if (argc != 1)
- die(_("Can merge only exactly one commit into "
- "empty head"));
if (squash)
die(_("Squash commit into empty head not supported yet"));
if (fast_forward == FF_NO)
die(_("Non-fast-forward commit does not make sense into "
"an empty head"));
- remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+ remoteheads = collect_parents(head_commit, &head_subsumed,
+ argc, argv, NULL);
remote_head = remoteheads->item;
if (!remote_head)
die(_("%s - not something we can merge"), argv[0]);
+ if (remoteheads->next)
+ die(_("Can merge only exactly one commit into empty head"));
read_empty(remote_head->object.sha1, 0);
update_ref("initial pull", "HEAD", remote_head->object.sha1,
NULL, 0, UPDATE_REFS_DIE_ON_ERR);
goto done;
- } else {
- struct strbuf merge_names = STRBUF_INIT;
+ }
+ /*
+ * This could be traditional "merge <msg> HEAD <commit>..." and
+ * the way we can tell it is to see if the second token is HEAD,
+ * but some people might have misused the interface and used a
+ * commit-ish that is the same as HEAD there instead.
+ * Traditional format never would have "-m" so it is an
+ * additional safety measure to check for it.
+ */
+ if (!have_message &&
+ is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
+ warning("old-style 'git merge <msg> HEAD <commit>' is deprecated.");
+ strbuf_addstr(&merge_msg, argv[0]);
+ head_arg = argv[1];
+ argv += 2;
+ argc -= 2;
+ remoteheads = collect_parents(head_commit, &head_subsumed,
+ argc, argv, NULL);
+ } else {
/* We are invoked directly as the first-class UI. */
head_arg = "HEAD";
@@ -1221,21 +1308,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* the standard merge summary message to be appended
* to the given message.
*/
- remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
- for (p = remoteheads; p; p = p->next)
- merge_name(merge_remote_util(p->item)->name, &merge_names);
-
- if (!have_message || shortlog_len) {
- struct fmt_merge_msg_opts opts;
- memset(&opts, 0, sizeof(opts));
- opts.add_title = !have_message;
- opts.shortlog_len = shortlog_len;
- opts.credit_people = (0 < option_edit);
-
- fmt_merge_msg(&merge_names, &merge_msg, &opts);
- if (merge_msg.len)
- strbuf_setlen(&merge_msg, merge_msg.len - 1);
- }
+ remoteheads = collect_parents(head_commit, &head_subsumed,
+ argc, argv, &merge_msg);
}
if (!head_commit || !argc)
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 9736d4452f..248a3eb260 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -138,9 +138,9 @@ static int tipcmp(const void *a_, const void *b_)
return hashcmp(a->sha1, b->sha1);
}
-static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
+static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
{
- struct object *o = parse_object(sha1);
+ struct object *o = parse_object(oid->hash);
struct name_ref_data *data = cb_data;
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
@@ -160,7 +160,7 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
}
}
- add_to_tip_table(sha1, path, can_abbreviate_output);
+ add_to_tip_table(oid->hash, path, can_abbreviate_output);
while (o && o->type == OBJ_TAG) {
struct tag *t = (struct tag *) o;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index c067107a6a..80fe8c7dc1 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -540,11 +540,11 @@ static enum write_one_status write_one(struct sha1file *f,
return WRITE_ONE_WRITTEN;
}
-static int mark_tagged(const char *path, const unsigned char *sha1, int flag,
+static int mark_tagged(const char *path, const struct object_id *oid, int flag,
void *cb_data)
{
unsigned char peeled[20];
- struct object_entry *entry = packlist_find(&to_pack, sha1, NULL);
+ struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL);
if (entry)
entry->tagged = 1;
@@ -2097,14 +2097,14 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
#endif
-static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int add_ref_tag(const char *path, const struct object_id *oid, int flag, void *cb_data)
{
- unsigned char peeled[20];
+ struct object_id peeled;
if (starts_with(path, "refs/tags/") && /* is a tag? */
- !peel_ref(path, peeled) && /* peelable? */
- packlist_find(&to_pack, peeled, NULL)) /* object packed? */
- add_object_entry(sha1, OBJ_TAG, NULL, 0);
+ !peel_ref(path, peeled.hash) && /* peelable? */
+ packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */
+ add_object_entry(oid->hash, OBJ_TAG, NULL, 0);
return 0;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d2ec52bca9..94d0571776 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -197,7 +197,7 @@ static void show_ref(const char *path, const unsigned char *sha1)
}
}
-static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *unused)
+static int show_ref_cb(const char *path, const struct object_id *oid, int flag, void *unused)
{
path = strip_namespace(path);
/*
@@ -210,7 +210,7 @@ static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, vo
*/
if (!path)
path = ".have";
- show_ref(path, sha1);
+ show_ref(path, oid->hash);
return 0;
}
@@ -228,6 +228,7 @@ static void collect_one_alternate_ref(const struct ref *ref, void *data)
static void write_head_info(void)
{
struct sha1_array sa = SHA1_ARRAY_INIT;
+
for_each_alternate_ref(collect_one_alternate_ref, &sa);
sha1_array_for_each_unique(&sa, show_one_alternate_sha1, NULL);
sha1_array_clear(&sa);
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 8182b648b9..c2eb8ff840 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -313,14 +313,14 @@ static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0;
}
-static int push_tip_to_list(const char *refname, const unsigned char *sha1,
+static int push_tip_to_list(const char *refname, const struct object_id *oid,
int flags, void *cb_data)
{
struct commit_list **list = cb_data;
struct commit *tip_commit;
if (flags & REF_ISSYMREF)
return 0;
- tip_commit = lookup_commit_reference_gently(sha1, 1);
+ tip_commit = lookup_commit_reference_gently(oid->hash, 1);
if (!tip_commit)
return 0;
commit_list_insert(tip_commit, list);
@@ -352,6 +352,7 @@ static void reflog_expiry_prepare(const char *refname,
if (cb->unreachable_expire_kind != UE_ALWAYS) {
if (cb->unreachable_expire_kind == UE_HEAD) {
struct commit_list *elem;
+
for_each_ref(push_tip_to_list, &cb->tips);
for (elem = cb->tips; elem; elem = elem->next)
commit_list_insert(elem->item, &cb->mark_list);
@@ -379,14 +380,14 @@ static void reflog_expiry_cleanup(void *cb_data)
}
}
-static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
{
struct collected_reflog *e;
struct collect_reflog_cb *cb = cb_data;
size_t namelen = strlen(ref);
e = xmalloc(sizeof(*e) + namelen + 1);
- hashcpy(e->sha1, sha1);
+ hashcpy(e->sha1, oid->hash);
memcpy(e->reflog, ref, namelen + 1);
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
cb->e[cb->nr++] = e;
diff --git a/builtin/remote.c b/builtin/remote.c
index ad57fc984e..f4a6ec9f13 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -509,11 +509,10 @@ struct branches_for_remote {
};
static int add_branch_for_removal(const char *refname,
- const unsigned char *sha1, int flags, void *cb_data)
+ const struct object_id *oid, int flags, void *cb_data)
{
struct branches_for_remote *branches = cb_data;
struct refspec refspec;
- struct string_list_item *item;
struct known_remote *kr;
memset(&refspec, 0, sizeof(refspec));
@@ -543,9 +542,7 @@ static int add_branch_for_removal(const char *refname,
if (flags & REF_ISSYMREF)
return unlink(git_path("%s", refname));
- item = string_list_append(branches->branches, refname);
- item->util = xmalloc(20);
- hashcpy(item->util, sha1);
+ string_list_append(branches->branches, refname);
return 0;
}
@@ -557,20 +554,20 @@ struct rename_info {
};
static int read_remote_branches(const char *refname,
- const unsigned char *sha1, int flags, void *cb_data)
+ const struct object_id *oid, int flags, void *cb_data)
{
struct rename_info *rename = cb_data;
struct strbuf buf = STRBUF_INIT;
struct string_list_item *item;
int flag;
- unsigned char orig_sha1[20];
+ struct object_id orig_oid;
const char *symref;
strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
if (starts_with(refname, buf.buf)) {
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
- orig_sha1, &flag);
+ orig_oid.hash, &flag);
if (flag & REF_ISSYMREF)
item->util = xstrdup(symref);
else
@@ -704,9 +701,9 @@ static int mv(int argc, const char **argv)
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
int flag = 0;
- unsigned char sha1[20];
+ struct object_id oid;
- read_ref_full(item->string, RESOLVE_REF_READING, sha1, &flag);
+ read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
if (!(flag & REF_ISSYMREF))
continue;
if (delete_ref(item->string, NULL, REF_NODEREF))
@@ -826,7 +823,7 @@ static int rm(int argc, const char **argv)
if (!result)
result = remove_branches(&branches);
- string_list_clear(&branches, 1);
+ string_list_clear(&branches, 0);
if (skipped.nr) {
fprintf_ln(stderr,
@@ -867,7 +864,7 @@ static void free_remote_ref_states(struct ref_states *states)
}
static int append_ref_to_tracked_list(const char *refname,
- const unsigned char *sha1, int flags, void *cb_data)
+ const struct object_id *oid, int flags, void *cb_data)
{
struct ref_states *states = cb_data;
struct refspec refspec;
diff --git a/builtin/replace.c b/builtin/replace.c
index 54bf01acb4..0d52e7fa1d 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -35,7 +35,7 @@ struct show_data {
enum replace_format format;
};
-static int show_reference(const char *refname, const unsigned char *sha1,
+static int show_reference(const char *refname, const struct object_id *oid,
int flag, void *cb_data)
{
struct show_data *data = cb_data;
@@ -44,19 +44,19 @@ static int show_reference(const char *refname, const unsigned char *sha1,
if (data->format == REPLACE_FORMAT_SHORT)
printf("%s\n", refname);
else if (data->format == REPLACE_FORMAT_MEDIUM)
- printf("%s -> %s\n", refname, sha1_to_hex(sha1));
+ printf("%s -> %s\n", refname, oid_to_hex(oid));
else { /* data->format == REPLACE_FORMAT_LONG */
- unsigned char object[20];
+ struct object_id object;
enum object_type obj_type, repl_type;
- if (get_sha1(refname, object))
+ if (get_sha1(refname, object.hash))
return error("Failed to resolve '%s' as a valid ref.", refname);
- obj_type = sha1_object_info(object, NULL);
- repl_type = sha1_object_info(sha1, NULL);
+ obj_type = sha1_object_info(object.hash, NULL);
+ repl_type = sha1_object_info(oid->hash, NULL);
printf("%s (%s) -> %s (%s)\n", refname, typename(obj_type),
- sha1_to_hex(sha1), typename(repl_type));
+ oid_to_hex(oid), typename(repl_type));
}
}
@@ -82,7 +82,7 @@ static int list_replace_refs(const char *pattern, const char *format)
"valid formats are 'short', 'medium' and 'long'\n",
format);
- for_each_replace_ref(show_reference, (void *) &data);
+ for_each_replace_ref(show_reference, (void *)&data);
return 0;
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 4d10dd9545..b6232390a6 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -190,17 +190,17 @@ static int show_default(void)
return 0;
}
-static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int show_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
{
if (ref_excluded(ref_excludes, refname))
return 0;
- show_rev(NORMAL, sha1, refname);
+ show_rev(NORMAL, oid->hash, refname);
return 0;
}
-static int anti_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
{
- show_rev(REVERSED, sha1, refname);
+ show_rev(REVERSED, oid->hash, refname);
return 0;
}
diff --git a/builtin/rm.c b/builtin/rm.c
index 3304bff42a..80b972f92f 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -84,7 +84,6 @@ static int check_submodules_use_gitfiles(void)
const char *name = list.entry[i].name;
int pos;
const struct cache_entry *ce;
- struct stat st;
pos = cache_name_pos(name, strlen(name));
if (pos < 0) {
@@ -95,7 +94,7 @@ static int check_submodules_use_gitfiles(void)
ce = active_cache[pos];
if (!S_ISGITLINK(ce->ce_mode) ||
- (lstat(ce->name, &st) < 0) ||
+ !file_exists(ce->name) ||
is_empty_dir(name))
continue;
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e69fb7c489..323f857463 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -369,10 +369,10 @@ static void sort_ref_range(int bottom, int top)
compare_ref_name);
}
-static int append_ref(const char *refname, const unsigned char *sha1,
+static int append_ref(const char *refname, const struct object_id *oid,
int allow_dups)
{
- struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+ struct commit *commit = lookup_commit_reference_gently(oid->hash, 1);
int i;
if (!commit)
@@ -394,39 +394,42 @@ static int append_ref(const char *refname, const unsigned char *sha1,
return 0;
}
-static int append_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int append_head_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
- unsigned char tmp[20];
+ struct object_id tmp;
int ofs = 11;
if (!starts_with(refname, "refs/heads/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
+ if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
ofs = 5;
- return append_ref(refname + ofs, sha1, 0);
+ return append_ref(refname + ofs, oid, 0);
}
-static int append_remote_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int append_remote_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
- unsigned char tmp[20];
+ struct object_id tmp;
int ofs = 13;
if (!starts_with(refname, "refs/remotes/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
+ if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
ofs = 5;
- return append_ref(refname + ofs, sha1, 0);
+ return append_ref(refname + ofs, oid, 0);
}
-static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int append_tag_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
if (!starts_with(refname, "refs/tags/"))
return 0;
- return append_ref(refname + 5, sha1, 0);
+ return append_ref(refname + 5, oid, 0);
}
static const char *match_ref_pattern = NULL;
@@ -440,7 +443,8 @@ static int count_slash(const char *s)
return cnt;
}
-static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int append_matching_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
/* we want to allow pattern hold/<asterisk> to show all
* branches under refs/heads/hold/, and v0.99.9? to show
@@ -456,21 +460,23 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
if (wildmatch(match_ref_pattern, tail, 0, NULL))
return 0;
if (starts_with(refname, "refs/heads/"))
- return append_head_ref(refname, sha1, flag, cb_data);
+ return append_head_ref(refname, oid, flag, cb_data);
if (starts_with(refname, "refs/tags/"))
- return append_tag_ref(refname, sha1, flag, cb_data);
- return append_ref(refname, sha1, 0);
+ return append_tag_ref(refname, oid, flag, cb_data);
+ return append_ref(refname, oid, 0);
}
static void snarf_refs(int head, int remotes)
{
if (head) {
int orig_cnt = ref_name_cnt;
+
for_each_ref(append_head_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
if (remotes) {
int orig_cnt = ref_name_cnt;
+
for_each_ref(append_remote_ref, NULL);
sort_ref_range(orig_cnt, ref_name_cnt);
}
@@ -530,14 +536,15 @@ static int show_independent(struct commit **rev,
static void append_one_rev(const char *av)
{
- unsigned char revkey[20];
- if (!get_sha1(av, revkey)) {
- append_ref(av, revkey, 0);
+ struct object_id revkey;
+ if (!get_sha1(av, revkey.hash)) {
+ append_ref(av, &revkey, 0);
return;
}
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
/* glob style match */
int saved_matches = ref_name_cnt;
+
match_ref_pattern = av;
match_ref_slash = count_slash(av);
for_each_ref(append_matching_ref, NULL);
@@ -636,7 +643,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
char head[128];
const char *head_p;
int head_len;
- unsigned char head_sha1[20];
+ struct object_id head_oid;
int merge_base = 0;
int independent = 0;
int no_name = 0;
@@ -722,7 +729,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
all_heads = 1;
if (reflog) {
- unsigned char sha1[20];
+ struct object_id oid;
char nth_desc[256];
char *ref;
int base = 0;
@@ -733,7 +740,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
fake_av[0] = resolve_refdup("HEAD",
RESOLVE_REF_READING,
- sha1, NULL);
+ oid.hash, NULL);
fake_av[1] = NULL;
av = fake_av;
ac = 1;
@@ -744,7 +751,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (MAX_REVS < reflog)
die("Only %d entries can be shown at one time.",
MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), sha1, &ref))
+ if (!dwim_ref(*av, strlen(*av), oid.hash, &ref))
die("No such ref %s", *av);
/* Has the base been specified? */
@@ -755,7 +762,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
/* Ah, that is a date spec... */
unsigned long at;
at = approxidate(reflog_base);
- read_ref_at(ref, flags, at, -1, sha1, NULL,
+ read_ref_at(ref, flags, at, -1, oid.hash, NULL,
NULL, NULL, &base);
}
}
@@ -766,7 +773,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
unsigned long timestamp;
int tz;
- if (read_ref_at(ref, flags, 0, base+i, sha1, &logmsg,
+ if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
&timestamp, &tz, NULL)) {
reflog = i;
break;
@@ -781,7 +788,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
msg);
free(logmsg);
sprintf(nth_desc, "%s@{%d}", *av, base+i);
- append_ref(nth_desc, sha1, 1);
+ append_ref(nth_desc, &oid, 1);
}
free(ref);
}
@@ -795,7 +802,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
}
head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- head_sha1, NULL);
+ head_oid.hash, NULL);
if (head_p) {
head_len = strlen(head_p);
memcpy(head, head_p, head_len + 1);
@@ -814,7 +821,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (rev_is_head(head,
head_len,
ref_name[i],
- head_sha1, NULL))
+ head_oid.hash, NULL))
has_head++;
}
if (!has_head) {
@@ -829,17 +836,17 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
}
for (num_rev = 0; ref_name[num_rev]; num_rev++) {
- unsigned char revkey[20];
+ struct object_id revkey;
unsigned int flag = 1u << (num_rev + REV_SHIFT);
if (MAX_REVS <= num_rev)
die("cannot handle more than %d revs.", MAX_REVS);
- if (get_sha1(ref_name[num_rev], revkey))
+ if (get_sha1(ref_name[num_rev], revkey.hash))
die("'%s' is not a valid ref.", ref_name[num_rev]);
- commit = lookup_commit_reference(revkey);
+ commit = lookup_commit_reference(revkey.hash);
if (!commit)
die("cannot find commit %s (%s)",
- ref_name[num_rev], revkey);
+ ref_name[num_rev], oid_to_hex(&revkey));
parse_commit(commit);
mark_seen(commit, &seen);
@@ -873,7 +880,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int is_head = rev_is_head(head,
head_len,
ref_name[i],
- head_sha1,
+ head_oid.hash,
rev[i]->object.sha1);
if (extra < 0)
printf("%c [%s] ",
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index afb10309d6..dfbc314ac2 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -17,19 +17,20 @@ static int deref_tags, show_head, tags_only, heads_only, found_match, verify,
static const char **pattern;
static const char *exclude_existing_arg;
-static void show_one(const char *refname, const unsigned char *sha1)
+static void show_one(const char *refname, const struct object_id *oid)
{
- const char *hex = find_unique_abbrev(sha1, abbrev);
+ const char *hex = find_unique_abbrev(oid->hash, abbrev);
if (hash_only)
printf("%s\n", hex);
else
printf("%s %s\n", hex, refname);
}
-static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
+static int show_ref(const char *refname, const struct object_id *oid,
+ int flag, void *cbdata)
{
const char *hex;
- unsigned char peeled[20];
+ struct object_id peeled;
if (show_head && !strcmp(refname, "HEAD"))
goto match;
@@ -69,26 +70,27 @@ match:
* detect and return error if the repository is corrupt and
* ref points at a nonexistent object.
*/
- if (!has_sha1_file(sha1))
+ if (!has_sha1_file(oid->hash))
die("git show-ref: bad ref %s (%s)", refname,
- sha1_to_hex(sha1));
+ oid_to_hex(oid));
if (quiet)
return 0;
- show_one(refname, sha1);
+ show_one(refname, oid);
if (!deref_tags)
return 0;
- if (!peel_ref(refname, peeled)) {
- hex = find_unique_abbrev(peeled, abbrev);
+ if (!peel_ref(refname, peeled.hash)) {
+ hex = find_unique_abbrev(peeled.hash, abbrev);
printf("%s %s^{}\n", hex, refname);
}
return 0;
}
-static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
+static int add_existing(const char *refname, const struct object_id *oid,
+ int flag, void *cbdata)
{
struct string_list *list = (struct string_list *)cbdata;
string_list_insert(list, refname);
@@ -208,12 +210,12 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
if (!pattern)
die("--verify requires a reference");
while (*pattern) {
- unsigned char sha1[20];
+ struct object_id oid;
if (starts_with(*pattern, "refs/") &&
- !read_ref(*pattern, sha1)) {
+ !read_ref(*pattern, oid.hash)) {
if (!quiet)
- show_one(*pattern, sha1);
+ show_one(*pattern, &oid);
}
else if (!quiet)
die("'%s' - not a valid ref", *pattern);
diff --git a/builtin/tag.c b/builtin/tag.c
index 6f07ac6b93..5f6cdc5a03 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -176,7 +176,7 @@ static enum contains_result contains(struct commit *candidate,
return contains_test(candidate, want);
}
-static void show_tag_lines(const unsigned char *sha1, int lines)
+static void show_tag_lines(const struct object_id *oid, int lines)
{
int i;
unsigned long size;
@@ -184,14 +184,14 @@ static void show_tag_lines(const unsigned char *sha1, int lines)
char *buf, *sp, *eol;
size_t len;
- buf = read_sha1_file(sha1, &type, &size);
+ buf = read_sha1_file(oid->hash, &type, &size);
if (!buf)
- die_errno("unable to read object %s", sha1_to_hex(sha1));
+ die_errno("unable to read object %s", oid_to_hex(oid));
if (type != OBJ_COMMIT && type != OBJ_TAG)
goto free_return;
if (!size)
die("an empty %s object %s?",
- typename(type), sha1_to_hex(sha1));
+ typename(type), oid_to_hex(oid));
/* skip header */
sp = strstr(buf, "\n\n");
@@ -215,7 +215,7 @@ free_return:
free(buf);
}
-static int show_reference(const char *refname, const unsigned char *sha1,
+static int show_reference(const char *refname, const struct object_id *oid,
int flag, void *cb_data)
{
struct tag_filter *filter = cb_data;
@@ -224,14 +224,14 @@ static int show_reference(const char *refname, const unsigned char *sha1,
if (filter->with_commit) {
struct commit *commit;
- commit = lookup_commit_reference_gently(sha1, 1);
+ commit = lookup_commit_reference_gently(oid->hash, 1);
if (!commit)
return 0;
if (!contains(commit, filter->with_commit))
return 0;
}
- if (points_at.nr && !match_points_at(refname, sha1))
+ if (points_at.nr && !match_points_at(refname, oid->hash))
return 0;
if (!filter->lines) {
@@ -242,7 +242,7 @@ static int show_reference(const char *refname, const unsigned char *sha1,
return 0;
}
printf("%-15s ", refname);
- show_tag_lines(sha1, filter->lines);
+ show_tag_lines(oid, filter->lines);
putchar('\n');
}
@@ -268,7 +268,7 @@ static int list_tags(const char **patterns, int lines,
memset(&filter.tags, 0, sizeof(filter.tags));
filter.tags.strdup_strings = 1;
- for_each_tag_ref(show_reference, (void *) &filter);
+ for_each_tag_ref(show_reference, (void *)&filter);
if (sort) {
int i;
if ((sort & SORT_MASK) == VERCMP_SORT)
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 0665b31ea1..7431938fa6 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -33,6 +33,7 @@ static int mark_valid_only;
static int mark_skip_worktree_only;
#define MARK_FLAG 1
#define UNMARK_FLAG 2
+static struct strbuf mtime_dir = STRBUF_INIT;
__attribute__((format (printf, 1, 2)))
static void report(const char *fmt, ...)
@@ -48,6 +49,166 @@ static void report(const char *fmt, ...)
va_end(vp);
}
+static void remove_test_directory(void)
+{
+ if (mtime_dir.len)
+ remove_dir_recursively(&mtime_dir, 0);
+}
+
+static const char *get_mtime_path(const char *path)
+{
+ static struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/%s", mtime_dir.buf, path);
+ return sb.buf;
+}
+
+static void xmkdir(const char *path)
+{
+ path = get_mtime_path(path);
+ if (mkdir(path, 0700))
+ die_errno(_("failed to create directory %s"), path);
+}
+
+static int xstat_mtime_dir(struct stat *st)
+{
+ if (stat(mtime_dir.buf, st))
+ die_errno(_("failed to stat %s"), mtime_dir.buf);
+ return 0;
+}
+
+static int create_file(const char *path)
+{
+ int fd;
+ path = get_mtime_path(path);
+ fd = open(path, O_CREAT | O_RDWR, 0644);
+ if (fd < 0)
+ die_errno(_("failed to create file %s"), path);
+ return fd;
+}
+
+static void xunlink(const char *path)
+{
+ path = get_mtime_path(path);
+ if (unlink(path))
+ die_errno(_("failed to delete file %s"), path);
+}
+
+static void xrmdir(const char *path)
+{
+ path = get_mtime_path(path);
+ if (rmdir(path))
+ die_errno(_("failed to delete directory %s"), path);
+}
+
+static void avoid_racy(void)
+{
+ /*
+ * not use if we could usleep(10) if USE_NSEC is defined. The
+ * field nsec could be there, but the OS could choose to
+ * ignore it?
+ */
+ sleep(1);
+}
+
+static int test_if_untracked_cache_is_supported(void)
+{
+ struct stat st;
+ struct stat_data base;
+ int fd, ret = 0;
+
+ strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX");
+ if (!mkdtemp(mtime_dir.buf))
+ die_errno("Could not make temporary directory");
+
+ fprintf(stderr, _("Testing "));
+ atexit(remove_test_directory);
+ xstat_mtime_dir(&st);
+ fill_stat_data(&base, &st);
+ fputc('.', stderr);
+
+ avoid_racy();
+ fd = create_file("newfile");
+ xstat_mtime_dir(&st);
+ if (!match_stat_data(&base, &st)) {
+ close(fd);
+ fputc('\n', stderr);
+ fprintf_ln(stderr,_("directory stat info does not "
+ "change after adding a new file"));
+ goto done;
+ }
+ fill_stat_data(&base, &st);
+ fputc('.', stderr);
+
+ avoid_racy();
+ xmkdir("new-dir");
+ xstat_mtime_dir(&st);
+ if (!match_stat_data(&base, &st)) {
+ close(fd);
+ fputc('\n', stderr);
+ fprintf_ln(stderr, _("directory stat info does not change "
+ "after adding a new directory"));
+ goto done;
+ }
+ fill_stat_data(&base, &st);
+ fputc('.', stderr);
+
+ avoid_racy();
+ write_or_die(fd, "data", 4);
+ close(fd);
+ xstat_mtime_dir(&st);
+ if (match_stat_data(&base, &st)) {
+ fputc('\n', stderr);
+ fprintf_ln(stderr, _("directory stat info changes "
+ "after updating a file"));
+ goto done;
+ }
+ fputc('.', stderr);
+
+ avoid_racy();
+ close(create_file("new-dir/new"));
+ xstat_mtime_dir(&st);
+ if (match_stat_data(&base, &st)) {
+ fputc('\n', stderr);
+ fprintf_ln(stderr, _("directory stat info changes after "
+ "adding a file inside subdirectory"));
+ goto done;
+ }
+ fputc('.', stderr);
+
+ avoid_racy();
+ xunlink("newfile");
+ xstat_mtime_dir(&st);
+ if (!match_stat_data(&base, &st)) {
+ fputc('\n', stderr);
+ fprintf_ln(stderr, _("directory stat info does not "
+ "change after deleting a file"));
+ goto done;
+ }
+ fill_stat_data(&base, &st);
+ fputc('.', stderr);
+
+ avoid_racy();
+ xunlink("new-dir/new");
+ xrmdir("new-dir");
+ xstat_mtime_dir(&st);
+ if (!match_stat_data(&base, &st)) {
+ fputc('\n', stderr);
+ fprintf_ln(stderr, _("directory stat info does not "
+ "change after deleting a directory"));
+ goto done;
+ }
+
+ if (rmdir(mtime_dir.buf))
+ die_errno(_("failed to delete directory %s"), mtime_dir.buf);
+ fprintf_ln(stderr, _(" OK"));
+ ret = 1;
+
+done:
+ strbuf_release(&mtime_dir);
+ return ret;
+}
+
static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
@@ -741,6 +902,7 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx,
int cmd_update_index(int argc, const char **argv, const char *prefix)
{
int newfd, entries, has_errors = 0, line_termination = '\n';
+ int untracked_cache = -1;
int read_from_stdin = 0;
int prefix_length = prefix ? strlen(prefix) : 0;
int preferred_index_format = 0;
@@ -832,6 +994,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
N_("write index in this format")),
OPT_BOOL(0, "split-index", &split_index,
N_("enable or disable split index")),
+ OPT_BOOL(0, "untracked-cache", &untracked_cache,
+ N_("enable/disable untracked cache")),
+ OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
+ N_("enable untracked cache without testing the filesystem"), 2),
OPT_END()
};
@@ -938,6 +1104,28 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
the_index.split_index = NULL;
the_index.cache_changed |= SOMETHING_CHANGED;
}
+ if (untracked_cache > 0) {
+ struct untracked_cache *uc;
+
+ if (untracked_cache < 2) {
+ setup_work_tree();
+ if (!test_if_untracked_cache_is_supported())
+ return 1;
+ }
+ if (!the_index.untracked) {
+ uc = xcalloc(1, sizeof(*uc));
+ strbuf_init(&uc->ident, 100);
+ uc->exclude_per_dir = ".gitignore";
+ /* should be the same flags used by git-status */
+ uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+ the_index.untracked = uc;
+ }
+ add_untracked_ident(the_index.untracked);
+ the_index.cache_changed |= UNTRACKED_CHANGED;
+ } else if (!untracked_cache && the_index.untracked) {
+ the_index.untracked = NULL;
+ the_index.cache_changed |= UNTRACKED_CHANGED;
+ }
if (active_cache_changed) {
if (newfd < 0) {