summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c34
-rw-r--r--builtin/am.c137
-rw-r--r--builtin/apply.c4
-rw-r--r--builtin/bisect--helper.c137
-rw-r--r--builtin/blame.c15
-rw-r--r--builtin/branch.c139
-rw-r--r--builtin/cat-file.c14
-rw-r--r--builtin/check-ref-format.c7
-rw-r--r--builtin/checkout-index.c8
-rw-r--r--builtin/checkout.c108
-rw-r--r--builtin/clean.c29
-rw-r--r--builtin/clone.c38
-rw-r--r--builtin/commit-tree.c5
-rw-r--r--builtin/commit.c106
-rw-r--r--builtin/config.c21
-rw-r--r--builtin/count-objects.c1
-rw-r--r--builtin/describe.c192
-rw-r--r--builtin/diff-files.c1
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c3
-rw-r--r--builtin/diff.c22
-rw-r--r--builtin/difftool.c40
-rw-r--r--builtin/fast-export.c55
-rw-r--r--builtin/fetch.c47
-rw-r--r--builtin/fmt-merge-msg.c7
-rw-r--r--builtin/for-each-ref.c1
-rw-r--r--builtin/fsck.c21
-rw-r--r--builtin/gc.c11
-rw-r--r--builtin/get-tar-commit-id.c9
-rw-r--r--builtin/grep.c411
-rw-r--r--builtin/hash-object.c12
-rw-r--r--builtin/help.c5
-rw-r--r--builtin/index-pack.c16
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/interpret-trailers.c107
-rw-r--r--builtin/log.c66
-rw-r--r--builtin/ls-files.c15
-rw-r--r--builtin/merge-base.c42
-rw-r--r--builtin/merge-ours.c16
-rw-r--r--builtin/merge-tree.c16
-rw-r--r--builtin/merge.c50
-rw-r--r--builtin/mv.c5
-rw-r--r--builtin/name-rev.c3
-rw-r--r--builtin/notes.c29
-rw-r--r--builtin/pack-objects.c220
-rw-r--r--builtin/pack-redundant.c1
-rw-r--r--builtin/prune-packed.c4
-rw-r--r--builtin/prune.c4
-rw-r--r--builtin/pull.c39
-rw-r--r--builtin/push.c28
-rw-r--r--builtin/read-tree.c2
-rw-r--r--builtin/rebase--helper.c38
-rw-r--r--builtin/receive-pack.c44
-rw-r--r--builtin/reflog.c38
-rw-r--r--builtin/remote-ext.c2
-rw-r--r--builtin/remote.c23
-rw-r--r--builtin/replace.c14
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/reset.c49
-rw-r--r--builtin/rev-list.c123
-rw-r--r--builtin/rev-parse.c37
-rw-r--r--builtin/rm.c5
-rw-r--r--builtin/send-pack.c2
-rw-r--r--builtin/shortlog.c56
-rw-r--r--builtin/show-branch.c24
-rw-r--r--builtin/show-ref.c4
-rw-r--r--builtin/submodule--helper.c358
-rw-r--r--builtin/symbolic-ref.c5
-rw-r--r--builtin/tag.c22
-rw-r--r--builtin/unpack-file.c14
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-index.c65
-rw-r--r--builtin/update-ref.c73
-rw-r--r--builtin/verify-tag.c9
-rw-r--r--builtin/worktree.c100
75 files changed, 2138 insertions, 1278 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 5d5773d..bf01d89 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -26,6 +26,7 @@ static const char * const builtin_add_usage[] = {
};
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
+static int add_renormalize;
struct update_callback_data {
int flags;
@@ -116,11 +117,32 @@ int add_files_to_cache(const char *prefix,
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
+ rev.diffopt.flags.override_submodule_config = 1;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+ clear_pathspec(&rev.prune_data);
return !!data.add_errors;
}
+static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
+{
+ int i, retval = 0;
+
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+
+ if (ce_stage(ce))
+ continue; /* do not touch unmerged paths */
+ if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
+ continue; /* do not touch non blobs */
+ if (pathspec && !ce_path_match(ce, pathspec, NULL))
+ continue;
+ retval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE);
+ }
+
+ return retval;
+}
+
static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
{
char *seen;
@@ -216,7 +238,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
rev.diffopt.use_color = 0;
- DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
+ rev.diffopt.flags.ignore_dirty_submodules = 1;
out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
die(_("Could not open '%s' for writing."), file);
@@ -274,6 +296,7 @@ static struct option builtin_add_options[] = {
OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
+ OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
{ OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
@@ -404,7 +427,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
chmod_arg[1] != 'x' || chmod_arg[2]))
die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
- add_new_files = !take_worktree_changes && !refresh_only;
+ add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
@@ -498,7 +521,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
plug_bulk_checkin();
- exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+ if (add_renormalize)
+ exit_status |= renormalize_tracked_files(&pathspec, flags);
+ else
+ exit_status |= add_files_to_cache(prefix, &pathspec, flags);
if (add_new_files)
exit_status |= add_files(&dir, flags);
@@ -513,5 +539,7 @@ finish:
die(_("Unable to write new index file"));
}
+ UNLEAK(pathspec);
+ UNLEAK(dir);
return exit_status;
}
diff --git a/builtin/am.c b/builtin/am.c
index 73f542b..acfe9d3 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -31,6 +31,7 @@
#include "mailinfo.h"
#include "apply.h"
#include "string-list.h"
+#include "packfile.h"
/**
* Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -670,9 +671,7 @@ static int detect_patch_format(const char **paths)
goto done;
}
- strbuf_reset(&l2);
strbuf_getline(&l2, fp);
- strbuf_reset(&l3);
strbuf_getline(&l3, fp);
/*
@@ -695,6 +694,8 @@ static int detect_patch_format(const char **paths)
done:
fclose(fp);
strbuf_release(&l1);
+ strbuf_release(&l2);
+ strbuf_release(&l3);
return ret;
}
@@ -707,6 +708,7 @@ static int split_mail_mbox(struct am_state *state, const char **paths,
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf last = STRBUF_INIT;
+ int ret;
cp.git_cmd = 1;
argv_array_push(&cp.args, "mailsplit");
@@ -720,13 +722,16 @@ static int split_mail_mbox(struct am_state *state, const char **paths,
argv_array_push(&cp.args, "--");
argv_array_pushv(&cp.args, paths);
- if (capture_command(&cp, &last, 8))
- return -1;
+ ret = capture_command(&cp, &last, 8);
+ if (ret)
+ goto exit;
state->cur = 1;
state->last = strtol(last.buf, NULL, 10);
- return 0;
+exit:
+ strbuf_release(&last);
+ return ret ? -1 : 0;
}
/**
@@ -880,6 +885,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,
static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
{
struct strbuf sb = STRBUF_INIT;
+ int rc = 0;
while (!strbuf_getline_lf(&sb, in)) {
const char *str;
@@ -893,19 +899,27 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
errno = 0;
timestamp = parse_timestamp(str, &end, 10);
- if (errno)
- return error(_("invalid timestamp"));
+ if (errno) {
+ rc = error(_("invalid timestamp"));
+ goto exit;
+ }
- if (!skip_prefix(end, " ", &str))
- return error(_("invalid Date line"));
+ if (!skip_prefix(end, " ", &str)) {
+ rc = error(_("invalid Date line"));
+ goto exit;
+ }
errno = 0;
tz = strtol(str, &end, 10);
- if (errno)
- return error(_("invalid timezone offset"));
+ if (errno) {
+ rc = error(_("invalid timezone offset"));
+ goto exit;
+ }
- if (*end)
- return error(_("invalid Date line"));
+ if (*end) {
+ rc = error(_("invalid Date line"));
+ goto exit;
+ }
/*
* mercurial's timezone is in seconds west of UTC,
@@ -930,9 +944,9 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
fwrite(sb.buf, 1, sb.len, out);
strbuf_reset(&sb);
}
-
+exit:
strbuf_release(&sb);
- return 0;
+ return rc;
}
/**
@@ -1058,8 +1072,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
if (!get_oid("HEAD", &curr_head)) {
write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
- update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
@@ -1124,52 +1138,15 @@ static const char *msgnum(const struct am_state *state)
*/
static void refresh_and_write_cache(void)
{
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file lock_file = LOCK_INIT;
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write index file"));
}
/**
- * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn
- * branch, returns 1 if there are entries in the index, 0 otherwise. If an
- * strbuf is provided, the space-separated list of files that differ will be
- * appended to it.
- */
-static int index_has_changes(struct strbuf *sb)
-{
- struct object_id head;
- int i;
-
- if (!get_sha1_tree("HEAD", head.hash)) {
- struct diff_options opt;
-
- diff_setup(&opt);
- DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
- if (!sb)
- DIFF_OPT_SET(&opt, QUICK);
- do_diff_cache(&head, &opt);
- diffcore_std(&opt);
- for (i = 0; sb && i < diff_queued_diff.nr; i++) {
- if (i)
- strbuf_addch(sb, ' ');
- strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
- }
- diff_flush(&opt);
- return DIFF_OPT_TST(&opt, HAS_CHANGES) != 0;
- } else {
- for (i = 0; sb && i < active_nr; i++) {
- if (i)
- strbuf_addch(sb, ' ');
- strbuf_addstr(sb, active_cache[i]->name);
- }
- return !!active_nr;
- }
-}
-
-/**
* Dies with a user-friendly message on how to proceed after resolving the
* problem. This message can be overridden with state->resolvemsg.
*/
@@ -1399,8 +1376,8 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
rev_info.show_root_diff = 1;
rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
rev_info.no_commit_id = 1;
- DIFF_OPT_SET(&rev_info.diffopt, BINARY);
- DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
+ rev_info.diffopt.flags.binary = 1;
+ rev_info.diffopt.flags.full_index = 1;
rev_info.diffopt.use_color = 0;
rev_info.diffopt.file = fp;
rev_info.diffopt.close_file = 1;
@@ -1420,10 +1397,10 @@ static void write_index_patch(const struct am_state *state)
struct rev_info rev_info;
FILE *fp;
- if (!get_sha1_tree("HEAD", head.hash))
+ if (!get_oid_tree("HEAD", &head))
tree = lookup_tree(&head);
else
- tree = lookup_tree(&empty_tree_oid);
+ tree = lookup_tree(the_hash_algo->empty_tree);
fp = xfopen(am_path(state, "patch"), "w");
init_revisions(&rev_info, NULL);
@@ -1478,11 +1455,10 @@ static int run_apply(const struct am_state *state, const char *index_file)
struct argv_array apply_opts = ARGV_ARRAY_INIT;
struct apply_state apply_state;
int res, opts_left;
- static struct lock_file lock_file;
int force_apply = 0;
int options = 0;
- if (init_apply_state(&apply_state, NULL, &lock_file))
+ if (init_apply_state(&apply_state, NULL))
die("BUG: init_apply_state() failed");
argv_array_push(&apply_opts, "apply");
@@ -1649,7 +1625,7 @@ static void do_commit(const struct am_state *state)
if (write_cache_as_tree(tree.hash, 0, NULL))
die(_("git write-tree failed to write a tree"));
- if (!get_sha1_commit("HEAD", parent.hash)) {
+ if (!get_oid_commit("HEAD", &parent)) {
old_oid = &parent;
commit_list_insert(lookup_commit(&parent), &parents);
} else {
@@ -1676,8 +1652,8 @@ static void do_commit(const struct am_state *state)
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
@@ -1936,15 +1912,14 @@ next:
*/
static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree_desc t[2];
if (parse_tree(head) || parse_tree(remote))
return -1;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
@@ -1960,11 +1935,11 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
init_tree_desc(&t[1], remote->buffer, remote->size);
if (unpack_trees(2, t, &opts)) {
- rollback_lock_file(lock_file);
+ rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -1976,15 +1951,14 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
*/
static int merge_tree(struct tree *tree)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree_desc t[1];
if (parse_tree(tree))
return -1;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
@@ -1995,11 +1969,11 @@ static int merge_tree(struct tree *tree)
init_tree_desc(&t[0], tree->buffer, tree->size);
if (unpack_trees(1, t, &opts)) {
- rollback_lock_file(lock_file);
+ rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
@@ -2095,6 +2069,7 @@ static int safe_to_abort(const struct am_state *state)
die(_("could not parse %s"), am_path(state, "abort-safety"));
} else
oidclr(&abort_safety);
+ strbuf_release(&sb);
if (get_oid("HEAD", &head))
oidclr(&head);
@@ -2124,7 +2099,7 @@ static void am_abort(struct am_state *state)
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+ curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
@@ -2136,11 +2111,11 @@ static void am_abort(struct am_state *state)
clean_index(&curr_head, &orig_head);
if (has_orig_head)
- update_ref_oid("am --abort", "HEAD", &orig_head,
- has_curr_head ? &curr_head : NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref("am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
+ delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
free(curr_branch);
am_destroy(state);
diff --git a/builtin/apply.c b/builtin/apply.c
index 81b9a61..48d3989 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -9,8 +9,6 @@ static const char * const apply_usage[] = {
NULL
};
-static struct lock_file lock_file;
-
int cmd_apply(int argc, const char **argv, const char *prefix)
{
int force_apply = 0;
@@ -18,7 +16,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
int ret;
struct apply_state state;
- if (init_apply_state(&state, prefix, &lock_file))
+ if (init_apply_state(&state, prefix))
exit(128);
argc = apply_parse_options(argc, argv,
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 3324229..4b5fadc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -2,19 +2,128 @@
#include "cache.h"
#include "parse-options.h"
#include "bisect.h"
+#include "refs.h"
+
+static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --next-all [--no-checkout]"),
+ N_("git bisect--helper --write-terms <bad_term> <good_term>"),
+ N_("git bisect--helper --bisect-clean-state"),
NULL
};
+/*
+ * Check whether the string `term` belongs to the set of strings
+ * included in the variable arguments.
+ */
+LAST_ARG_MUST_BE_NULL
+static int one_of(const char *term, ...)
+{
+ int res = 0;
+ va_list matches;
+ const char *match;
+
+ va_start(matches, term);
+ while (!res && (match = va_arg(matches, const char *)))
+ res = !strcmp(term, match);
+ va_end(matches);
+
+ return res;
+}
+
+static int check_term_format(const char *term, const char *orig_term)
+{
+ int res;
+ char *new_term = xstrfmt("refs/bisect/%s", term);
+
+ res = check_refname_format(new_term, 0);
+ free(new_term);
+
+ if (res)
+ return error(_("'%s' is not a valid term"), term);
+
+ if (one_of(term, "help", "start", "skip", "next", "reset",
+ "visualize", "view", "replay", "log", "run", "terms", NULL))
+ return error(_("can't use the builtin command '%s' as a term"), term);
+
+ /*
+ * In theory, nothing prevents swapping completely good and bad,
+ * but this situation could be confusing and hasn't been tested
+ * enough. Forbid it for now.
+ */
+
+ if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
+ (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
+ return error(_("can't change the meaning of the term '%s'"), term);
+
+ return 0;
+}
+
+static int write_terms(const char *bad, const char *good)
+{
+ FILE *fp = NULL;
+ int res;
+
+ if (!strcmp(bad, good))
+ return error(_("please use two different terms"));
+
+ if (check_term_format(bad, "bad") || check_term_format(good, "good"))
+ return -1;
+
+ fp = fopen(git_path_bisect_terms(), "w");
+ if (!fp)
+ return error_errno(_("could not open the file BISECT_TERMS"));
+
+ res = fprintf(fp, "%s\n%s\n", bad, good);
+ res |= fclose(fp);
+ return (res < 0) ? -1 : 0;
+}
+
+static int is_expected_rev(const char *expected_hex)
+{
+ struct strbuf actual_hex = STRBUF_INIT;
+ int res = 0;
+ if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
+ strbuf_trim(&actual_hex);
+ res = !strcmp(actual_hex.buf, expected_hex);
+ }
+ strbuf_release(&actual_hex);
+ return res;
+}
+
+static void check_expected_revs(const char **revs, int rev_nr)
+{
+ int i;
+
+ for (i = 0; i < rev_nr; i++) {
+ if (!is_expected_rev(revs[i])) {
+ unlink_or_warn(git_path_bisect_ancestors_ok());
+ unlink_or_warn(git_path_bisect_expected_rev());
+ }
+ }
+}
+
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
- int next_all = 0;
+ enum {
+ NEXT_ALL = 1,
+ WRITE_TERMS,
+ BISECT_CLEAN_STATE,
+ CHECK_EXPECTED_REVS
+ } cmdmode = 0;
int no_checkout = 0;
struct option options[] = {
- OPT_BOOL(0, "next-all", &next_all,
- N_("perform 'git bisect next'")),
+ OPT_CMDMODE(0, "next-all", &cmdmode,
+ N_("perform 'git bisect next'"), NEXT_ALL),
+ OPT_CMDMODE(0, "write-terms", &cmdmode,
+ N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
+ OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
+ N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
+ OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
+ N_("check for expected revs"), CHECK_EXPECTED_REVS),
OPT_BOOL(0, "no-checkout", &no_checkout,
N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
@@ -23,9 +132,25 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options,
git_bisect_helper_usage, 0);
- if (!next_all)
+ if (!cmdmode)
usage_with_options(git_bisect_helper_usage, options);
- /* next-all */
- return bisect_next_all(prefix, no_checkout);
+ switch (cmdmode) {
+ case NEXT_ALL:
+ return bisect_next_all(prefix, no_checkout);
+ case WRITE_TERMS:
+ if (argc != 2)
+ return error(_("--write-terms requires two arguments"));
+ return write_terms(argv[0], argv[1]);
+ case BISECT_CLEAN_STATE:
+ if (argc != 0)
+ return error(_("--bisect-clean-state requires no arguments"));
+ return bisect_clean_state();
+ case CHECK_EXPECTED_REVS:
+ check_expected_revs(argv, argc);
+ return 0;
+ default:
+ return error("BUG: unknown subcommand '%d'", cmdmode);
+ }
+ return 0;
}
diff --git a/builtin/blame.c b/builtin/blame.c
index bda1a78..005f55a 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -488,7 +488,7 @@ static int read_ancestry(const char *graft_file)
return -1;
while (!strbuf_getwholeline(&buf, fp, '\n')) {
/* The format is just "Commit Parent1 Parent2 ...\n" */
- struct commit_graft *graft = read_graft_line(buf.buf, buf.len);
+ struct commit_graft *graft = read_graft_line(&buf);
if (graft)
register_commit_graft(graft, 0);
}
@@ -708,8 +708,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
- DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
- DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES);
+ revs.diffopt.flags.allow_textconv = 1;
+ revs.diffopt.flags.follow_renames = 1;
save_commit_buffer = 0;
dashdash_pos = 0;
@@ -734,9 +734,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
}
parse_done:
- no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
+ no_whole_file_rename = !revs.diffopt.flags.follow_renames;
xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
- DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
+ revs.diffopt.flags.follow_renames = 0;
argc = parse_options_end(&ctx);
if (incremental || (output_option & OUTPUT_PORCELAIN)) {
@@ -803,7 +803,7 @@ parse_done:
}
blame_date_width -= 1; /* strip the null */
- if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
+ if (revs.diffopt.flags.find_copies_harder)
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
PICKAXE_BLAME_COPY_HARDER);
@@ -925,8 +925,7 @@ parse_done:
sb.found_guilty_entry = &found_guilty_entry;
sb.found_guilty_entry_data = &pi;
if (show_progress)
- pi.progress = start_progress_delay(_("Blaming lines"),
- sb.num_lines, 50, 1);
+ pi.progress = start_delayed_progress(_("Blaming lines"), sb.num_lines);
assign_blame(&sb, opt);
diff --git a/builtin/branch.c b/builtin/branch.c
index 16d391b..8dcc2ed 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -28,6 +28,7 @@ static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
+ N_("git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"),
N_("git branch [<options>] [-r | -a] [--points-at]"),
N_("git branch [<options>] [-r | -a] [--format]"),
NULL
@@ -92,7 +93,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)
return config_error_nonbool(var);
return color_parse(value, branch_colors[slot]);
}
- return git_default_config(var, value, cb);
+ return git_color_default_config(var, value, cb);
}
static const char *branch_get_color(enum color_branch ix)
@@ -124,7 +125,7 @@ static int branch_merged(int kind, const char *name,
if (upstream &&
(reference_name = reference_name_to_free =
resolve_refdup(upstream, RESOLVE_REF_READING,
- oid.hash, NULL)) != NULL)
+ &oid, NULL)) != NULL)
reference_rev = lookup_commit_reference(&oid);
}
if (!reference_rev)
@@ -216,7 +217,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (!head_rev)
die(_("Couldn't look up commit object for HEAD"));
}
- for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+ for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
char *target = NULL;
int flags = 0;
@@ -240,7 +241,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
RESOLVE_REF_READING
| RESOLVE_REF_NO_RECURSE
| RESOLVE_REF_ALLOW_BAD_NAME,
- oid.hash, &flags);
+ &oid, &flags);
if (!target) {
error(remote_branch
? _("remote-tracking branch '%s' not found.")
@@ -256,8 +257,8 @@ 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.hash,
- REF_NODEREF)) {
+ 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'"),
@@ -281,8 +282,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
free(name);
+ strbuf_release(&bname);
- return(ret);
+ return ret;
}
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
@@ -352,7 +354,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
strbuf_addf(&obname, "%%(objectname:short=%d)", filter->abbrev);
strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth);
- strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
strbuf_addf(&local, " %s ", obname.buf);
if (filter->verbose > 1)
@@ -456,15 +458,20 @@ static void reject_rebase_or_bisect_branch(const char *target)
free_worktrees(worktrees);
}
-static void rename_branch(const char *oldname, const char *newname, int force)
+static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
{
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
+ const char *interpreted_oldname = NULL;
+ const char *interpreted_newname = NULL;
int recovery = 0;
- int clobber_head_ok;
- if (!oldname)
- die(_("cannot rename the current branch while not on any."));
+ if (!oldname) {
+ if (copy)
+ die(_("cannot copy the current branch while not on any."));
+ else
+ die(_("cannot rename the current branch while not on any."));
+ }
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
@@ -481,32 +488,53 @@ static void rename_branch(const char *oldname, const char *newname, int force)
* A command like "git branch -M currentbranch currentbranch" cannot
* cause the worktree to become inconsistent with HEAD, so allow it.
*/
- clobber_head_ok = !strcmp(oldname, newname);
-
- validate_new_branchname(newname, &newref, force, clobber_head_ok);
+ if (!strcmp(oldname, newname))
+ validate_branchname(newname, &newref);
+ else
+ validate_new_branchname(newname, &newref, force);
reject_rebase_or_bisect_branch(oldref.buf);
- strbuf_addf(&logmsg, "Branch: renamed %s to %s",
- oldref.buf, newref.buf);
+ if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
+ !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
+ die("BUG: expected prefix missing for refs");
+ }
+
+ if (copy)
+ strbuf_addf(&logmsg, "Branch: copied %s to %s",
+ oldref.buf, newref.buf);
+ else
+ strbuf_addf(&logmsg, "Branch: renamed %s to %s",
+ oldref.buf, newref.buf);
- if (rename_ref(oldref.buf, newref.buf, logmsg.buf))
+ if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch rename failed"));
+ if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
+ die(_("Branch copy failed"));
- if (recovery)
- warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11);
+ if (recovery) {
+ if (copy)
+ warning(_("Created a copy of a misnamed branch '%s'"),
+ interpreted_oldname);
+ else
+ warning(_("Renamed a misnamed branch '%s' away"),
+ interpreted_oldname);
+ }
- if (replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
+ if (!copy &&
+ replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
strbuf_release(&logmsg);
- strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11);
+ strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
strbuf_release(&oldref);
- strbuf_addf(&newsection, "branch.%s", newref.buf + 11);
+ strbuf_addf(&newsection, "branch.%s", interpreted_newname);
strbuf_release(&newref);
- if (git_config_rename_section(oldsection.buf, newsection.buf) < 0)
+ if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
die(_("Branch is renamed, but update of config-file failed"));
+ if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
+ die(_("Branch is copied, but update of config-file failed"));
strbuf_release(&oldsection);
strbuf_release(&newsection);
}
@@ -544,7 +572,7 @@ static int edit_branch_description(const char *branch_name)
int cmd_branch(int argc, const char **argv, const char *prefix)
{
- int delete = 0, rename = 0, force = 0, list = 0;
+ int delete = 0, rename = 0, copy = 0, force = 0, list = 0;
int reflog = 0, edit_description = 0;
int quiet = 0, unset_upstream = 0;
const char *new_upstream = NULL;
@@ -561,8 +589,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("suppress informational messages")),
OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"),
BRANCH_TRACK_EXPLICIT),
- OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
- BRANCH_TRACK_OVERRIDE),
+ { OPTION_SET_INT, 0, "set-upstream", &track, NULL, N_("do not use"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, BRANCH_TRACK_OVERRIDE },
OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("Unset the upstream info")),
OPT__COLOR(&branch_use_color, N_("use colored output")),
@@ -581,6 +609,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+ OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
+ OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
OPT_BOOL(0, "list", &list, N_("list branch names")),
OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
@@ -613,7 +643,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
track = git_branch_track;
- head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ head = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
@@ -624,14 +654,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
- if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
+ if (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0)
list = 1;
if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||
filter.no_commit)
list = 1;
- if (!!delete + !!rename + !!new_upstream +
+ if (!!delete + !!rename + !!copy + !!new_upstream +
list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
@@ -649,8 +679,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (force) {
delete *= 2;
rename *= 2;
+ copy *= 2;
}
+ if (list)
+ setup_auto_pager("branch", 1);
+
if (delete) {
if (!argc)
die(_("branch name required"));
@@ -703,20 +737,29 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (edit_branch_description(branch_name))
return 1;
+ } else if (copy) {
+ if (!argc)
+ die(_("branch name required"));
+ else if (argc == 1)
+ copy_or_rename_branch(head, argv[0], 1, copy > 1);
+ else if (argc == 2)
+ copy_or_rename_branch(argv[0], argv[1], 1, copy > 1);
+ else
+ die(_("too many branches for a copy operation"));
} else if (rename) {
if (!argc)
die(_("branch name required"));
else if (argc == 1)
- rename_branch(head, argv[0], rename > 1);
+ copy_or_rename_branch(head, argv[0], 0, rename > 1);
else if (argc == 2)
- rename_branch(argv[0], argv[1], rename > 1);
+ copy_or_rename_branch(argv[0], argv[1], 0, rename > 1);
else
- die(_("too many branches for a rename operation"));
+ die(_("too many arguments for a rename operation"));
} else if (new_upstream) {
struct branch *branch = branch_get(argv[0]);
if (argc > 1)
- die(_("too many branches to set new upstream"));
+ die(_("too many arguments to set new upstream"));
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
@@ -739,7 +782,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
if (argc > 1)
- die(_("too many branches to unset upstream"));
+ die(_("too many arguments to unset upstream"));
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
@@ -759,11 +802,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
} else if (argc > 0 && argc <= 2) {
struct branch *branch = branch_get(argv[0]);
- int branch_existed = 0, remote_tracking = 0;
- struct strbuf buf = STRBUF_INIT;
-
- if (!strcmp(argv[0], "HEAD"))
- die(_("it does not make sense to create 'HEAD' manually"));
if (!branch)
die(_("no such branch '%s'"), argv[0]);
@@ -772,27 +810,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
if (track == BRANCH_TRACK_OVERRIDE)
- fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
-
- strbuf_addf(&buf, "refs/remotes/%s", branch->name);
- remote_tracking = ref_exists(buf.buf);
- strbuf_release(&buf);
+ die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
- branch_existed = ref_exists(branch->refname);
create_branch(argv[0], (argc == 2) ? argv[1] : head,
- force, reflog, 0, quiet, track);
-
- /*
- * We only show the instructions if the user gave us
- * one branch which doesn't exist locally, but is the
- * name of a remote-tracking branch.
- */
- if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
- !branch_existed && remote_tracking) {
- fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
- fprintf(stderr, " git branch -d %s\n", branch->name);
- fprintf(stderr, " git branch --set-upstream-to %s\n", branch->name);
- }
+ force, 0, reflog, quiet, track);
} else
usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 96b786e..f5fa4fd 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -12,6 +12,7 @@
#include "streaming.h"
#include "tree-walk.h"
#include "sha1-array.h"
+#include "packfile.h"
struct batch_options {
int enabled;
@@ -63,8 +64,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (unknown_type)
flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
- if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
- oid.hash, &obj_context))
+ if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+ &oid, &obj_context))
die("Not a valid object name %s", obj_name);
if (!path)
@@ -96,7 +97,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
return !has_object_file(&oid);
case 'w':
- if (!path[0])
+ if (!path)
die("git cat-file --filters %s: <object> must be "
"<sha1:path>", obj_name);
@@ -106,12 +107,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
break;
case 'c':
- if (!path[0])
+ if (!path)
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);
if (textconv_object(path, obj_context.mode, &oid, 1, &buf, &size))
break;
+ /* else fallthrough */
case 'p':
type = sha1_object_info(oid.hash, NULL);
@@ -361,10 +363,10 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
struct expand_data *data)
{
struct object_context ctx;
- int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
+ int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
enum follow_symlinks_result result;
- result = get_sha1_with_context(obj_name, flags, data->oid.hash, &ctx);
+ result = get_oid_with_context(obj_name, flags, &data->oid, &ctx);
if (result != FOUND) {
switch (result) {
case MISSING_OBJECT:
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index eac4994..bc67d3f 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -39,12 +39,15 @@ static char *collapse_slashes(const char *refname)
static int check_ref_format_branch(const char *arg)
{
struct strbuf sb = STRBUF_INIT;
+ const char *name;
int nongit;
setup_git_directory_gently(&nongit);
- if (strbuf_check_branch_ref(&sb, arg))
+ if (strbuf_check_branch_ref(&sb, arg) ||
+ !skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
- printf("%s\n", sb.buf + 11);
+ printf("%s\n", name);
+ strbuf_release(&sb);
return 0;
}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 39c8be0..b0e78b8 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -129,8 +129,6 @@ static const char * const builtin_checkout_index_usage[] = {
NULL
};
-static struct lock_file lock_file;
-
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
@@ -150,7 +148,7 @@ static int option_parse_stage(const struct option *opt,
int cmd_checkout_index(int argc, const char **argv, const char *prefix)
{
int i;
- int newfd = -1;
+ struct lock_file lock_file = LOCK_INIT;
int all = 0;
int read_from_stdin = 0;
int prefix_length;
@@ -206,7 +204,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (index_opt && !state.base_dir_len && !to_tempfile) {
state.refresh_cache = 1;
state.istate = &the_index;
- newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
}
/* Check out named files first */
@@ -251,7 +249,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (all)
checkout_all(prefix, prefix_length);
- if (0 <= newfd &&
+ if (is_lock_file_locked(&lock_file) &&
write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
return 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2d75ac6..8bdc927 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "checkout.h"
#include "lockfile.h"
#include "parse-options.h"
#include "refs.h"
@@ -247,7 +248,7 @@ static int checkout_paths(const struct checkout_opts *opts,
struct object_id rev;
struct commit *head;
int errs = 0;
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
die(_("'%s' cannot be used with updating paths"), "--track");
@@ -275,9 +276,7 @@ static int checkout_paths(const struct checkout_opts *opts,
return run_add_interactive(revision, "--patch=checkout",
&opts->pathspec);
- lock_file = xcalloc(1, sizeof(struct lock_file));
-
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache_preload(&opts->pathspec) < 0)
return error(_("index file corrupt"));
@@ -376,10 +375,10 @@ static int checkout_paths(const struct checkout_opts *opts,
}
errs |= finish_delayed_checkout(&state);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- read_ref_full("HEAD", 0, rev.hash, NULL);
+ read_ref_full("HEAD", 0, &rev, NULL);
head = lookup_commit_reference_gently(&rev, 1);
errs |= post_checkout_hook(head, head, 0);
@@ -402,10 +401,16 @@ static void show_local_changes(struct object *head,
static void describe_detached_head(const char *msg, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
+
if (!parse_commit(commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
- fprintf(stderr, "%s %s... %s\n", msg,
- find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+ if (print_sha1_ellipsis()) {
+ fprintf(stderr, "%s %s... %s\n", msg,
+ find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+ } else {
+ fprintf(stderr, "%s %s %s\n", msg,
+ find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV), sb.buf);
+ }
strbuf_release(&sb);
}
@@ -436,6 +441,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
* update paths in the work tree, and we cannot revert
* them.
*/
+ /* fallthrough */
case 0:
return 0;
default:
@@ -471,9 +477,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
int *writeout_error)
{
int ret;
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file lock_file = LOCK_INIT;
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache_preload(NULL) < 0)
return error(_("index file corrupt"));
@@ -515,7 +521,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
tree = parse_tree_indirect(old->commit ?
&old->commit->object.oid :
- &empty_tree_oid);
+ the_hash_algo->empty_tree);
init_tree_desc(&trees[0], tree->buffer, tree->size);
tree = parse_tree_indirect(&new->commit->object.oid);
init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -590,7 +596,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (!cache_tree_fully_valid(active_cache_tree))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
if (!opts->force && !opts->quiet)
@@ -641,8 +647,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
else
create_branch(opts->new_branch, new->name,
opts->new_branch_force ? 1 : 0,
- opts->new_branch_log,
opts->new_branch_force ? 1 : 0,
+ opts->new_branch_log,
opts->quiet,
opts->track);
new->name = opts->new_branch;
@@ -663,8 +669,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
/* Nothing to do. */
} else if (opts->force_detach || !new->path) { /* No longer on any branch. */
- update_ref(msg.buf, "HEAD", new->commit->object.oid.hash, NULL,
- REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
+ REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
if (!opts->quiet) {
if (old->path &&
advice_detached_head && !opts->force_detach)
@@ -796,9 +802,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
for_each_ref(add_pending_uninteresting_ref, &revs);
add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
+ /* Save pending objects, so they can be cleaned up later. */
refs = revs.pending;
revs.leak_pending = 1;
+ /*
+ * prepare_revision_walk (together with .leak_pending = 1) makes us
+ * the sole owner of the list of pending objects.
+ */
if (prepare_revision_walk(&revs))
die(_("internal error in revision walk"));
if (!(old->object.flags & UNINTERESTING))
@@ -806,8 +817,10 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
else
describe_detached_head(_("Previous HEAD position was"), old);
+ /* Clean up objects used, as they will be reused. */
clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
- free(refs.objects);
+
+ object_array_clear(&refs);
}
static int switch_branches(const struct checkout_opts *opts,
@@ -819,7 +832,7 @@ static int switch_branches(const struct checkout_opts *opts,
struct object_id rev;
int flag, writeout_error = 0;
memset(&old, 0, sizeof(old));
- old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
+ old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
if (old.path)
old.commit = lookup_commit_reference_gently(&rev, 1);
if (!(flag & REF_ISSYMREF))
@@ -861,51 +874,11 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
}
if (starts_with(var, "submodule."))
- return submodule_config(var, value, NULL);
+ return git_default_submodule_config(var, value, NULL);
return git_xmerge_config(var, value, NULL);
}
-struct tracking_name_data {
- /* const */ char *src_ref;
- char *dst_ref;
- struct object_id *dst_oid;
- int unique;
-};
-
-static int check_tracking_name(struct remote *remote, void *cb_data)
-{
- struct tracking_name_data *cb = cb_data;
- struct refspec query;
- memset(&query, 0, sizeof(struct refspec));
- query.src = cb->src_ref;
- if (remote_find_tracking(remote, &query) ||
- get_oid(query.dst, cb->dst_oid)) {
- free(query.dst);
- return 0;
- }
- if (cb->dst_ref) {
- free(query.dst);
- cb->unique = 0;
- return 0;
- }
- cb->dst_ref = query.dst;
- return 0;
-}
-
-static const char *unique_tracking_name(const char *name, struct object_id *oid)
-{
- struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
- cb_data.src_ref = xstrfmt("refs/heads/%s", name);
- cb_data.dst_oid = oid;
- for_each_remote(check_tracking_name, &cb_data);
- free(cb_data.src_ref);
- if (cb_data.unique)
- return cb_data.dst_ref;
- free(cb_data.dst_ref);
- return NULL;
-}
-
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new,
@@ -1030,7 +1003,7 @@ static int parse_branchname_arg(int argc, const char **argv,
setup_branch_path(new);
if (!check_refname_format(new->path, 0) &&
- !read_ref(new->path, branch_rev.hash))
+ !read_ref(new->path, &branch_rev))
oidcpy(rev, &branch_rev);
else
new->path = NULL; /* not an existing branch */
@@ -1116,9 +1089,8 @@ static int checkout_branch(struct checkout_opts *opts,
if (new->path && !opts->force_detach && !opts->new_branch &&
!opts->ignore_other_worktrees) {
- struct object_id oid;
int flag;
- char *head_ref = resolve_refdup("HEAD", 0, oid.hash, &flag);
+ char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
if (head_ref &&
(!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
die_if_checked_out(new->path, 1);
@@ -1129,7 +1101,7 @@ static int checkout_branch(struct checkout_opts *opts,
struct object_id rev;
int flag;
- if (!read_ref_full("HEAD", 0, rev.hash, &flag) &&
+ if (!read_ref_full("HEAD", 0, &rev, &flag) &&
(flag & REF_ISSYMREF) && is_null_oid(&rev))
return switch_unborn_to_new_branch(opts);
}
@@ -1182,7 +1154,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.prefix = prefix;
opts.show_progress = -1;
- gitmodules_config();
git_config(git_checkout_config, &opts);
opts.track = BRANCH_TRACK_UNSPECIFIED;
@@ -1283,14 +1254,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (opts.new_branch) {
struct strbuf buf = STRBUF_INIT;
- opts.branch_exists =
- validate_new_branchname(opts.new_branch, &buf,
- !!opts.new_branch_force,
- !!opts.new_branch_force);
-
+ if (opts.new_branch_force)
+ opts.branch_exists = validate_branchname(opts.new_branch, &buf);
+ else
+ opts.branch_exists =
+ validate_new_branchname(opts.new_branch, &buf, 0);
strbuf_release(&buf);
}
+ UNLEAK(opts);
if (opts.patch_mode || opts.pathspec.nr)
return checkout_paths(&opts, new.name);
else
diff --git a/builtin/clean.c b/builtin/clean.c
index c1bafda..189e206 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -33,15 +33,6 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
static const char *msg_warn_remove_failed = N_("failed to remove %s");
-static int clean_use_color = -1;
-static char clean_colors[][COLOR_MAXLEN] = {
- GIT_COLOR_RESET,
- GIT_COLOR_NORMAL, /* PLAIN */
- GIT_COLOR_BOLD_BLUE, /* PROMPT */
- GIT_COLOR_BOLD, /* HEADER */
- GIT_COLOR_BOLD_RED, /* HELP */
- GIT_COLOR_BOLD_RED, /* ERROR */
-};
enum color_clean {
CLEAN_COLOR_RESET = 0,
CLEAN_COLOR_PLAIN = 1,
@@ -51,6 +42,16 @@ enum color_clean {
CLEAN_COLOR_ERROR = 5
};
+static int clean_use_color = -1;
+static char clean_colors[][COLOR_MAXLEN] = {
+ [CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,
+ [CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,
+ [CLEAN_COLOR_HELP] = GIT_COLOR_BOLD_RED,
+ [CLEAN_COLOR_PLAIN] = GIT_COLOR_NORMAL,
+ [CLEAN_COLOR_PROMPT] = GIT_COLOR_BOLD_BLUE,
+ [CLEAN_COLOR_RESET] = GIT_COLOR_RESET,
+};
+
#define MENU_OPTS_SINGLETON 01
#define MENU_OPTS_IMMEDIATE 02
#define MENU_OPTS_LIST_ONLY 04
@@ -125,7 +126,8 @@ static int git_clean_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ /* inspect the color.ui config variable and others */
+ return git_color_default_config(var, value, cb);
}
static const char *clean_get_color(enum color_clean ix)
@@ -166,7 +168,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
}
*dir_gone = 0;
- return 0;
+ goto out;
}
dir = opendir(path->buf);
@@ -180,7 +182,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
}
- return res;
+ ret = res;
+ goto out;
}
strbuf_complete(path, '/');
@@ -248,6 +251,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
for (i = 0; i < dels.nr; i++)
printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
}
+out:
+ strbuf_release(&quoted);
string_list_clear(&dels, 0);
return ret;
}
diff --git a/builtin/clone.c b/builtin/clone.c
index f7e17d2..2da71db 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -25,6 +25,7 @@
#include "remote.h"
#include "run-command.h"
#include "connected.h"
+#include "packfile.h"
/*
* Overall FIXMEs:
@@ -451,7 +452,8 @@ static void clone_local(const char *src_repo, const char *dest_repo)
{
if (option_shared) {
struct strbuf alt = STRBUF_INIT;
- strbuf_addf(&alt, "%s/objects", src_repo);
+ get_common_dir(&alt, src_repo);
+ strbuf_addstr(&alt, "/objects");
add_to_alternates_file(alt.buf);
strbuf_release(&alt);
} else {
@@ -506,8 +508,8 @@ static void remove_junk(void)
if (junk_work_tree) {
strbuf_addstr(&sb, junk_work_tree);
remove_dir_recursively(&sb, 0);
- strbuf_reset(&sb);
}
+ strbuf_release(&sb);
}
static void remove_junk_on_signal(int signo)
@@ -587,7 +589,7 @@ static void write_remote_refs(const struct ref *local_refs)
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
- if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash,
+ if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
0, NULL, &err))
die("%s", err.buf);
}
@@ -609,12 +611,12 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue;
if (!has_object_file(&ref->old_oid))
continue;
- update_ref(msg, ref->name, ref->old_oid.hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
{
struct ref **rm = cb_data;
struct ref *ref = *rm;
@@ -629,7 +631,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
if (!ref)
return -1;
- hashcpy(sha1, ref->old_oid.hash);
+ oidcpy(oid, &ref->old_oid);
*rm = ref->next;
return 0;
}
@@ -681,23 +683,23 @@ static void update_head(const struct ref *our, const struct ref *remote,
if (create_symref("HEAD", our->name, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare) {
- update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0,
+ update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
install_branch_config(0, head, option_origin, our->name);
}
} else if (our) {
struct commit *c = lookup_commit_reference(&our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
- update_ref(msg, "HEAD", c->object.oid.hash,
- NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (remote) {
/*
* We know remote HEAD points to a non-branch, or
* HEAD points to a branch but we don't know which one.
* Detach HEAD in all these cases.
*/
- update_ref(msg, "HEAD", remote->old_oid.hash,
- NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
@@ -705,7 +707,7 @@ static int checkout(int submodule_progress)
{
struct object_id oid;
char *head;
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree *tree;
struct tree_desc t;
@@ -714,7 +716,7 @@ static int checkout(int submodule_progress)
if (option_no_checkout)
return 0;
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
+ head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
"unable to checkout.\n"));
@@ -732,8 +734,7 @@ static int checkout(int submodule_progress)
/* We need to be in the new work tree for the checkout */
setup_work_tree();
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof opts);
opts.update = 1;
@@ -749,7 +750,7 @@ static int checkout(int submodule_progress)
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
@@ -1082,9 +1083,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
warning(_("--local is ignored"));
transport->cloning = 1;
- if (!transport->get_refs_list || (!is_local && !transport->fetch))
- die(_("Don't know how to clone %s"), transport->url);
-
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
if (option_depth)
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index a4a923d..2177251 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -56,7 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
struct object_id oid;
if (argc <= ++i)
usage(commit_tree_usage);
- if (get_sha1_commit(argv[i], oid.hash))
+ if (get_oid_commit(argv[i], &oid))
die("Not a valid object name %s", argv[i]);
assert_sha1_type(oid.hash, OBJ_COMMIT);
new_parent(lookup_commit(&oid), &parents);
@@ -102,11 +102,10 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (fd && close(fd))
die_errno("git commit-tree: failed to close '%s'",
argv[i]);
- strbuf_complete_line(&buffer);
continue;
}
- if (get_sha1_tree(arg, tree_oid.hash))
+ if (get_oid_tree(arg, &tree_oid))
die("Not a valid object name %s", arg);
if (got_tree)
die("Cannot give more than one trees");
diff --git a/builtin/commit.c b/builtin/commit.c
index 1a0da71..8a87701 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -118,7 +118,7 @@ static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
static int no_post_rewrite, allow_empty_message;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
+static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
static char *sign_commit;
/*
@@ -139,7 +139,7 @@ static const char *cleanup_arg;
static enum commit_whence whence;
static int sequencer_in_use;
static int use_editor = 1, include_status = 1;
-static int show_ignored_in_status, have_option_m;
+static int have_option_m;
static struct strbuf message = STRBUF_INIT;
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
@@ -195,7 +195,6 @@ static void determine_whence(struct wt_status *s)
static void status_init_config(struct wt_status *s, config_fn_t fn)
{
wt_status_prepare(s);
- gitmodules_config();
git_config(fn, s);
determine_whence(s);
init_diff_ui_defaults();
@@ -336,7 +335,7 @@ static void refresh_cache_or_die(int refresh_flags)
static const char *prepare_index(int argc, const char **argv, const char *prefix,
const struct commit *current_head, int is_status)
{
- struct string_list partial;
+ struct string_list partial = STRING_LIST_INIT_DUP;
struct pathspec pathspec;
int refresh_flags = REFRESH_QUIET;
const char *ret;
@@ -356,7 +355,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
refresh_cache_or_die(refresh_flags);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to create temporary index"));
old_index_env = getenv(INDEX_ENVIRONMENT);
@@ -375,13 +374,14 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to update temporary index"));
} else
warning(_("Failed to update main cache tree"));
commit_style = COMMIT_NORMAL;
- return get_lock_file_path(&index_lock);
+ ret = get_lock_file_path(&index_lock);
+ goto out;
}
/*
@@ -401,10 +401,11 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
refresh_cache_or_die(refresh_flags);
update_main_cache_tree(WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
commit_style = COMMIT_NORMAL;
- return get_lock_file_path(&index_lock);
+ ret = get_lock_file_path(&index_lock);
+ goto out;
}
/*
@@ -430,7 +431,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
rollback_lock_file(&index_lock);
}
commit_style = COMMIT_AS_IS;
- return get_index_file();
+ ret = get_index_file();
+ goto out;
}
/*
@@ -461,7 +463,6 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
die(_("cannot do a partial commit during a cherry-pick."));
}
- string_list_init(&partial, 1);
if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
exit(1);
@@ -473,7 +474,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
update_main_cache_tree(WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
hold_lock_file_for_update(&false_lock,
@@ -485,12 +486,15 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
- if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &false_lock, 0))
die(_("unable to write temporary index file"));
discard_cache();
ret = get_lock_file_path(&false_lock);
read_cache_from(ret);
+out:
+ string_list_clear(&partial, 0);
+ clear_pathspec(&pathspec);
return ret;
}
@@ -510,7 +514,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
s->index_file = index_file;
s->fp = fp;
s->nowarn = nowarn;
- s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0;
+ s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
if (!s->is_initial)
hashcpy(s->sha1_commit, oid.hash);
s->status_format = status_format;
@@ -891,7 +895,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (amend)
parent = "HEAD^1";
- if (get_sha1(parent, oid.hash)) {
+ if (get_oid(parent, &oid)) {
int i, ita_nr = 0;
for (i = 0; i < active_nr; i++)
@@ -908,11 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
* submodules which were manually staged, which would
* be really confusing.
*/
- int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+ struct diff_flags flags = DIFF_FLAGS_INIT;
+ flags.override_submodule_config = 1;
if (ignore_submodule_arg &&
!strcmp(ignore_submodule_arg, "all"))
- diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
- commitable = index_differs_from(parent, diff_flags, 1);
+ flags.ignore_submodules = 1;
+ commitable = index_differs_from(parent, &flags, 1);
}
}
strbuf_release(&committer_ident);
@@ -940,13 +945,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 0;
}
- /*
- * Re-read the index as pre-commit hook could have updated it,
- * and write it out as a tree. We must do this before we invoke
- * the editor and after we invoke run_status above.
- */
- discard_cache();
+ if (!no_verify && find_hook("pre-commit")) {
+ /*
+ * Re-read the index as pre-commit hook could have updated it,
+ * and write it out as a tree. We must do this before we invoke
+ * the editor and after we invoke run_status above.
+ */
+ discard_cache();
+ }
read_cache_from(index_file);
+
if (update_main_cache_tree(0)) {
error(_("Error building trees"));
return 0;
@@ -1068,6 +1076,19 @@ static const char *find_author_by_nickname(const char *name)
die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
}
+static void handle_ignored_arg(struct wt_status *s)
+{
+ if (!ignored_arg)
+ ; /* default already initialized */
+ else if (!strcmp(ignored_arg, "traditional"))
+ s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
+ else if (!strcmp(ignored_arg, "no"))
+ s->show_ignored_mode = SHOW_NO_IGNORED;
+ else if (!strcmp(ignored_arg, "matching"))
+ s->show_ignored_mode = SHOW_MATCHING_IGNORED;
+ else
+ die(_("Invalid ignored mode '%s'"), ignored_arg);
+}
static void handle_untracked_files_arg(struct wt_status *s)
{
@@ -1356,8 +1377,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("mode"),
N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- OPT_BOOL(0, "ignored", &show_ignored_in_status,
- N_("show ignored files")),
+ { OPTION_STRING, 0, "ignored", &ignored_arg,
+ N_("mode"),
+ N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
+ PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
@@ -1376,8 +1399,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
finalize_deferred_config(&s);
handle_untracked_files_arg(&s);
- if (show_ignored_in_status)
- s.show_ignored_files = 1;
+ handle_ignored_arg(&s);
+
+ if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
+ s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
+ die(_("Unsupported combination of ignored and untracked-files arguments"));
+
parse_pathspec(&s.pathspec, 0,
PATHSPEC_PREFER_FULL,
prefix, argv);
@@ -1385,9 +1412,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
read_cache_preload(&s.pathspec);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
- fd = hold_locked_index(&index_lock, 0);
+ if (use_optional_locks())
+ fd = hold_locked_index(&index_lock, 0);
+ else
+ fd = -1;
- s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0;
+ s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
if (!s.is_initial)
hashcpy(s.sha1_commit, oid.hash);
@@ -1429,7 +1459,6 @@ static void print_summary(const char *prefix, const struct object_id *oid,
struct rev_info rev;
struct commit *commit;
struct strbuf format = STRBUF_INIT;
- struct object_id junk_oid;
const char *head;
struct pretty_print_context pctx = {0};
struct strbuf author_ident = STRBUF_INIT;
@@ -1482,7 +1511,9 @@ static void print_summary(const char *prefix, const struct object_id *oid,
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
- head = resolve_ref_unsafe("HEAD", 0, junk_oid.hash, NULL);
+ head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ if (!head)
+ die_errno(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
@@ -1657,7 +1688,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
s.colopts = 0;
- if (get_sha1("HEAD", oid.hash))
+ if (get_oid("HEAD", &oid))
current_head = NULL;
else {
current_head = lookup_commit_or_die(&oid, "HEAD");
@@ -1719,7 +1750,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
allow_fast_forward = 0;
}
if (allow_fast_forward)
- parents = reduce_heads(parents);
+ reduce_heads_replace(&parents);
} else {
if (!reflog_msg)
reflog_msg = (whence == FROM_CHERRY_PICK)
@@ -1779,9 +1810,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, "HEAD", oid.hash,
+ ref_transaction_update(transaction, "HEAD", &oid,
current_head
- ? current_head->object.oid.hash : null_sha1,
+ ? &current_head->object.oid : &null_oid,
0, sb.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
rollback_index_files();
@@ -1816,6 +1847,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!quiet)
print_summary(prefix, &oid, !current_head);
- strbuf_release(&err);
+ UNLEAK(err);
+ UNLEAK(sb);
return 0;
}
diff --git a/builtin/config.c b/builtin/config.c
index 70ff231..ab5f954 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -52,6 +52,7 @@ static int show_origin;
#define TYPE_INT (1<<1)
#define TYPE_BOOL_OR_INT (1<<2)
#define TYPE_PATH (1<<3)
+#define TYPE_EXPIRY_DATE (1<<4)
static struct option builtin_config_options[] = {
OPT_GROUP(N_("Config file location")),
@@ -80,6 +81,7 @@ static struct option builtin_config_options[] = {
OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
+ OPT_BIT(0, "expiry-date", &types, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
OPT_GROUP(N_("Other")),
OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
@@ -159,6 +161,11 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
return -1;
strbuf_addstr(buf, v);
free((char *)v);
+ } else if (types == TYPE_EXPIRY_DATE) {
+ timestamp_t t;
+ if (git_config_expiry_date(&t, key_, value_) < 0)
+ return -1;
+ strbuf_addf(buf, "%"PRItime, t);
} else if (value_) {
strbuf_addstr(buf, value_);
} else {
@@ -273,12 +280,13 @@ static char *normalize_value(const char *key, const char *value)
if (!value)
return NULL;
- if (types == 0 || types == TYPE_PATH)
+ if (types == 0 || types == TYPE_PATH || types == TYPE_EXPIRY_DATE)
/*
* We don't do normalization for TYPE_PATH here: If
* the path is like ~/foobar/, we prefer to store
* "~/foobar/" in the config file, and to expand the ~
* when retrieving the value.
+ * Also don't do normalization for expiry dates.
*/
return xstrdup(value);
if (types == TYPE_INT)
@@ -518,10 +526,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
die("$HOME not set");
if (access_or_warn(user_config, R_OK, 0) &&
- xdg_config && !access_or_warn(xdg_config, R_OK, 0))
+ xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
given_config_source.file = xdg_config;
- else
+ free(user_config);
+ } else {
given_config_source.file = user_config;
+ free(xdg_config);
+ }
}
else if (use_system_config)
given_config_source.file = git_etc_gitconfig();
@@ -628,6 +639,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
+ UNLEAK(value);
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
@@ -638,6 +650,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
+ UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2], 0);
}
@@ -645,6 +658,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
+ UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value,
CONFIG_REGEX_NONE, 0);
@@ -653,6 +667,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
+ UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2], 1);
}
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 1d82e61..3334381 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -10,6 +10,7 @@
#include "builtin.h"
#include "parse-options.h"
#include "quote.h"
+#include "packfile.h"
static unsigned long garbage;
static off_t size_garbage;
diff --git a/builtin/describe.c b/builtin/describe.c
index 89ea1cd..6fe1c51 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -3,16 +3,19 @@
#include "lockfile.h"
#include "commit.h"
#include "tag.h"
+#include "blob.h"
#include "refs.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
+#include "revision.h"
#include "diff.h"
#include "hashmap.h"
#include "argv-array.h"
#include "run-command.h"
+#include "revision.h"
+#include "list-objects.h"
-#define SEEN (1u << 0)
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
@@ -55,10 +58,13 @@ static const char *prio_names[] = {
};
static int commit_name_cmp(const void *unused_cmp_data,
- const struct commit_name *cn1,
- const struct commit_name *cn2,
+ const void *entry,
+ const void *entry_or_key,
const void *peeled)
{
+ const struct commit_name *cn1 = entry;
+ const struct commit_name *cn2 = entry_or_key;
+
return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
}
@@ -126,13 +132,24 @@ static void add_to_known_names(const char *path,
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/");
+ int is_tag = 0;
struct object_id peeled;
int is_annotated, prio;
-
- /* Reject anything outside refs/tags/ unless --all */
- if (!all && !is_tag)
+ const char *path_to_match = NULL;
+
+ if (skip_prefix(path, "refs/tags/", &path_to_match)) {
+ is_tag = 1;
+ } else if (all) {
+ if ((exclude_patterns.nr || patterns.nr) &&
+ !skip_prefix(path, "refs/heads/", &path_to_match) &&
+ !skip_prefix(path, "refs/remotes/", &path_to_match)) {
+ /* Only accept reference of known type if there are match/exclude patterns */
+ return 0;
+ }
+ } else {
+ /* Reject anything outside refs/tags/ unless --all */
return 0;
+ }
/*
* If we're given exclude patterns, first exclude any tag which match
@@ -141,11 +158,8 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
if (exclude_patterns.nr) {
struct string_list_item *item;
- if (!is_tag)
- return 0;
-
for_each_string_list_item(item, &exclude_patterns) {
- if (!wildmatch(item->string, path + 10, 0))
+ if (!wildmatch(item->string, path_to_match, 0))
return 0;
}
}
@@ -155,22 +169,22 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
* pattern.
*/
if (patterns.nr) {
+ int found = 0;
struct string_list_item *item;
- if (!is_tag)
- return 0;
-
for_each_string_list_item(item, &patterns) {
- if (!wildmatch(item->string, path + 10, 0))
+ if (!wildmatch(item->string, path_to_match, 0)) {
+ found = 1;
break;
+ }
+ }
- /* If we get here, no pattern matched. */
+ if (!found)
return 0;
- }
}
/* Is it annotated? */
- if (!peel_ref(path, peeled.hash)) {
+ if (!peel_ref(path, &peeled)) {
is_annotated = !!oidcmp(oid, &peeled);
} else {
oidcpy(&peeled, oid);
@@ -245,7 +259,7 @@ static unsigned long finish_depth_computation(
return seen_commits;
}
-static void display_name(struct commit_name *n)
+static void append_name(struct commit_name *n, struct strbuf *dst)
{
if (n->prio == 2 && !n->tag) {
n->tag = lookup_tag(&n->oid);
@@ -260,20 +274,22 @@ static void display_name(struct commit_name *n)
n->name_checked = 1;
}
- if (n->tag)
- printf("%s", n->tag->tag);
- else
- printf("%s", n->path);
+ if (n->tag) {
+ if (all)
+ strbuf_addstr(dst, "tags/");
+ strbuf_addstr(dst, n->tag->tag);
+ } else {
+ strbuf_addstr(dst, n->path);
+ }
}
-static void show_suffix(int depth, const struct object_id *oid)
+static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
{
- printf("-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
+ strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
}
-static void describe(const char *arg, int last_one)
+static void describe_commit(struct object_id *oid, struct strbuf *dst)
{
- struct object_id oid;
struct commit *cmit, *gave_up_on = NULL;
struct commit_list *list;
struct commit_name *n;
@@ -282,30 +298,25 @@ static void describe(const char *arg, int last_one)
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;
- if (get_oid(arg, &oid))
- die(_("Not a valid object name %s"), arg);
- cmit = lookup_commit_reference(&oid);
- if (!cmit)
- die(_("%s is not a valid '%s' object"), arg, commit_type);
+ cmit = lookup_commit_reference(oid);
n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
/*
* Exact match to an existing ref.
*/
- display_name(n);
+ append_name(n, dst);
if (longformat)
- show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid);
+ append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst);
if (suffix)
- printf("%s", suffix);
- printf("\n");
+ strbuf_addstr(dst, suffix);
return;
}
if (!max_candidates)
die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
if (debug)
- fprintf(stderr, _("searching to describe %s\n"), arg);
+ fprintf(stderr, _("No exact match on refs or tags, searching to describe\n"));
if (!have_util) {
struct hashmap_iter iter;
@@ -370,22 +381,21 @@ static void describe(const char *arg, int last_one)
}
if (!match_cnt) {
- struct object_id *oid = &cmit->object.oid;
+ struct object_id *cmit_oid = &cmit->object.oid;
if (always) {
- printf("%s", find_unique_abbrev(oid->hash, abbrev));
+ strbuf_addstr(dst, find_unique_abbrev(cmit_oid->hash, abbrev));
if (suffix)
- printf("%s", suffix);
- printf("\n");
+ strbuf_addstr(dst, suffix);
return;
}
if (unannotated_cnt)
die(_("No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."),
- oid_to_hex(oid));
+ oid_to_hex(cmit_oid));
else
die(_("No tags can describe '%s'.\n"
"Try --always, or create some tags."),
- oid_to_hex(oid));
+ oid_to_hex(cmit_oid));
}
QSORT(all_matches, match_cnt, compare_pt);
@@ -423,15 +433,86 @@ static void describe(const char *arg, int last_one)
}
}
- display_name(all_matches[0].name);
+ append_name(all_matches[0].name, dst);
if (abbrev)
- show_suffix(all_matches[0].depth, &cmit->object.oid);
+ append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
if (suffix)
- printf("%s", suffix);
- printf("\n");
+ strbuf_addstr(dst, suffix);
+}
+
+struct process_commit_data {
+ struct object_id current_commit;
+ struct object_id looking_for;
+ struct strbuf *dst;
+ struct rev_info *revs;
+};
+
+static void process_commit(struct commit *commit, void *data)
+{
+ struct process_commit_data *pcd = data;
+ pcd->current_commit = commit->object.oid;
+}
+
+static void process_object(struct object *obj, const char *path, void *data)
+{
+ struct process_commit_data *pcd = data;
+
+ if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
+ reset_revision_walk();
+ describe_commit(&pcd->current_commit, pcd->dst);
+ strbuf_addf(pcd->dst, ":%s", path);
+ free_commit_list(pcd->revs->commits);
+ pcd->revs->commits = NULL;
+ }
+}
+
+static void describe_blob(struct object_id oid, struct strbuf *dst)
+{
+ struct rev_info revs;
+ struct argv_array args = ARGV_ARRAY_INIT;
+ struct process_commit_data pcd = { null_oid, oid, dst, &revs};
+
+ argv_array_pushl(&args, "internal: The first arg is not parsed",
+ "--objects", "--in-commit-order", "--reverse", "HEAD",
+ NULL);
+
+ init_revisions(&revs, NULL);
+ if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
+ BUG("setup_revisions could not handle all args?");
+
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
+
+ traverse_commit_list(&revs, process_commit, process_object, &pcd);
+ reset_revision_walk();
+}
+
+static void describe(const char *arg, int last_one)
+{
+ struct object_id oid;
+ struct commit *cmit;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (debug)
+ fprintf(stderr, _("describe %s\n"), arg);
+
+ if (get_oid(arg, &oid))
+ die(_("Not a valid object name %s"), arg);
+ cmit = lookup_commit_reference_gently(&oid, 1);
+
+ if (cmit)
+ describe_commit(&oid, &sb);
+ else if (lookup_blob(&oid))
+ describe_blob(oid, &sb);
+ else
+ die(_("%s is neither a commit nor blob"), arg);
+
+ puts(sb.buf);
if (!last_one)
clear_commit_marks(cmit, -1);
+
+ strbuf_release(&sb);
}
int cmd_describe(int argc, const char **argv, const char *prefix)
@@ -503,9 +584,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
return cmd_name_rev(args.argc, args.argv, prefix);
}
- hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0);
+ hashmap_init(&names, commit_name_cmp, NULL, 0);
for_each_rawref(get_name, NULL);
- if (!names.size && !always)
+ if (!hashmap_get_size(&names) && !always)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
@@ -532,7 +613,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
}
} else if (dirty) {
static struct lock_file index_lock;
- int fd;
+ struct rev_info revs;
+ struct argv_array args = ARGV_ARRAY_INIT;
+ int fd, result;
read_cache_preload(NULL);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
@@ -541,8 +624,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (0 <= fd)
update_index_if_able(&the_index, &index_lock);
- if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
- diff_index_args, prefix))
+ init_revisions(&revs, prefix);
+ argv_array_pushv(&args, diff_index_args);
+ if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
+ BUG("malformed internal diff-index command line");
+ result = run_diff_index(&revs, 0);
+
+ if (!diff_result_code(&revs.diffopt, result))
suffix = NULL;
else
suffix = dirty;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 17bf84d..e88493f 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -26,7 +26,6 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
init_revisions(&rev, prefix);
- gitmodules_config();
rev.abbrev = 0;
precompose_argv(argc, argv);
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 185e6f9..522f4fd 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -23,7 +23,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
init_revisions(&rev, prefix);
- gitmodules_config();
rev.abbrev = 0;
precompose_argv(argc, argv);
@@ -57,5 +56,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
return -1;
}
result = run_diff_index(&rev, cached);
+ UNLEAK(rev);
return diff_result_code(&rev.diffopt, result);
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 31d2cb4..b775a75 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -110,7 +110,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
init_revisions(opt, prefix);
- gitmodules_config();
+ if (read_cache() < 0)
+ die(_("index file corrupt"));
opt->abbrev = 0;
opt->diff = 1;
opt->disable_stdin = 1;
diff --git a/builtin/diff.c b/builtin/diff.c
index 7cde6ab..16bfb22 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -44,7 +44,7 @@ static void stuff_change(struct diff_options *opt,
!oidcmp(old_oid, new_oid) && (old_mode == new_mode))
return;
- if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
+ if (opt->flags.reverse_diff) {
SWAP(old_mode, new_mode);
SWAP(old_oid, new_oid);
SWAP(old_path, new_path);
@@ -203,17 +203,16 @@ static int builtin_diff_combined(struct rev_info *revs,
static void refresh_index_quietly(void)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
int fd;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- fd = hold_locked_index(lock_file, 0);
+ fd = hold_locked_index(&lock_file, 0);
if (fd < 0)
return;
discard_cache();
read_cache();
refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
- update_index_if_able(&the_index, lock_file);
+ update_index_if_able(&the_index, &lock_file);
}
static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
@@ -315,8 +314,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
no_index = DIFF_NO_INDEX_IMPLICIT;
}
- if (!no_index)
- gitmodules_config();
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
precompose_argv(argc, argv);
@@ -352,8 +349,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
rev.diffopt.stat_graph_width = -1;
/* Default to let external and textconv be used */
- DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
- DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+ rev.diffopt.flags.allow_external = 1;
+ rev.diffopt.flags.allow_textconv = 1;
if (nongit)
die(_("Not a git repository"));
@@ -363,7 +360,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
diff_setup_done(&rev.diffopt);
}
- DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+ rev.diffopt.flags.recursive = 1;
setup_diff_pager(&rev.diffopt);
@@ -382,7 +379,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
- tree = lookup_tree(&empty_tree_oid);
+ tree = lookup_tree(the_hash_algo->empty_tree);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
@@ -466,5 +463,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
+ UNLEAK(rev);
+ UNLEAK(ent);
+ UNLEAK(blob);
return result;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index a1a26ba..bcc79d1 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -111,7 +111,7 @@ static int use_wt_file(const char *workdir, const char *name,
int fd = open(buf.buf, O_RDONLY);
if (fd >= 0 &&
- !index_fd(wt_oid.hash, fd, &st, OBJ_BLOB, name, 0)) {
+ !index_fd(&wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
if (is_null_oid(oid)) {
oidcpy(oid, &wt_oid);
use = 1;
@@ -131,10 +131,12 @@ struct working_tree_entry {
};
static int working_tree_entry_cmp(const void *unused_cmp_data,
- struct working_tree_entry *a,
- struct working_tree_entry *b,
- void *unused_keydata)
+ const void *entry,
+ const void *entry_or_key,
+ const void *unused_keydata)
{
+ const struct working_tree_entry *a = entry;
+ const struct working_tree_entry *b = entry_or_key;
return strcmp(a->path, b->path);
}
@@ -149,9 +151,13 @@ struct pair_entry {
};
static int pair_cmp(const void *unused_cmp_data,
- struct pair_entry *a, struct pair_entry *b,
- void *unused_keydata)
+ const void *entry,
+ const void *entry_or_key,
+ const void *unused_keydata)
{
+ const struct pair_entry *a = entry;
+ const struct pair_entry *b = entry_or_key;
+
return strcmp(a->path, b->path);
}
@@ -179,9 +185,13 @@ struct path_entry {
};
static int path_entry_cmp(const void *unused_cmp_data,
- struct path_entry *a, struct path_entry *b,
- void *key)
+ const void *entry,
+ const void *entry_or_key,
+ const void *key)
{
+ const struct path_entry *a = entry;
+ const struct path_entry *b = entry_or_key;
+
return strcmp(a->path, key ? key : b->path);
}
@@ -372,10 +382,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
rdir_len = rdir.len;
wtdir_len = wtdir.len;
- hashmap_init(&working_tree_dups,
- (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0);
- hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0);
- hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0);
+ hashmap_init(&working_tree_dups, working_tree_entry_cmp, NULL, 0);
+ hashmap_init(&submodules, pair_cmp, NULL, 0);
+ hashmap_init(&symlinks2, pair_cmp, NULL, 0);
child.no_stdin = 1;
child.git_cmd = 1;
@@ -585,10 +594,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* in the common case of --symlinks and the difftool updating
* files through the symlink.
*/
- hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp,
- NULL, wtindex.cache_nr);
- hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp,
- NULL, wtindex.cache_nr);
+ hashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr);
+ hashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr);
for (i = 0; i < wtindex.cache_nr; i++) {
struct hashmap_entry dummy;
@@ -609,7 +616,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
ret = error("could not write %s", buf.buf);
- rollback_lock_file(&lock);
goto finish;
}
changed_files(&wt_modified, buf.buf, workdir);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index d412c0a..796d0cd 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -344,6 +344,7 @@ static void show_filemodify(struct diff_queue_struct *q,
struct diff_options *options, void *data)
{
int i;
+ struct string_list *changed = data;
/*
* Handle files below a directory first, in case they are all deleted
@@ -359,20 +360,31 @@ static void show_filemodify(struct diff_queue_struct *q,
case DIFF_STATUS_DELETED:
printf("D ");
print_path(spec->path);
+ string_list_insert(changed, spec->path);
putchar('\n');
break;
case DIFF_STATUS_COPIED:
case DIFF_STATUS_RENAMED:
- printf("%c ", q->queue[i]->status);
- print_path(ospec->path);
- putchar(' ');
- print_path(spec->path);
- putchar('\n');
-
- if (!oidcmp(&ospec->oid, &spec->oid) &&
- ospec->mode == spec->mode)
- break;
+ /*
+ * If a change in the file corresponding to ospec->path
+ * has been observed, we cannot trust its contents
+ * because the diff is calculated based on the prior
+ * contents, not the current contents. So, declare a
+ * copy or rename only if there was no change observed.
+ */
+ if (!string_list_has_string(changed, ospec->path)) {
+ printf("%c ", q->queue[i]->status);
+ print_path(ospec->path);
+ putchar(' ');
+ print_path(spec->path);
+ string_list_insert(changed, spec->path);
+ putchar('\n');
+
+ if (!oidcmp(&ospec->oid, &spec->oid) &&
+ ospec->mode == spec->mode)
+ break;
+ }
/* fallthrough */
case DIFF_STATUS_TYPE_CHANGED:
@@ -393,6 +405,7 @@ static void show_filemodify(struct diff_queue_struct *q,
get_object_mark(object));
}
print_path(spec->path);
+ string_list_insert(changed, spec->path);
putchar('\n');
break;
@@ -528,7 +541,8 @@ static void anonymize_ident_line(const char **beg, const char **end)
*end = out->buf + out->len;
}
-static void handle_commit(struct commit *commit, struct rev_info *rev)
+static void handle_commit(struct commit *commit, struct rev_info *rev,
+ struct string_list *paths_of_changed_objects)
{
int saved_output_format = rev->diffopt.output_format;
const char *commit_buffer;
@@ -615,6 +629,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
if (full_tree)
printf("deleteall\n");
log_tree_diff_flush(rev);
+ string_list_clear(paths_of_changed_objects, 0);
rev->diffopt.output_format = saved_output_format;
printf("\n");
@@ -630,15 +645,15 @@ static void *anonymize_tag(const void *old, size_t *len)
return strbuf_detach(&out, len);
}
-static void handle_tail(struct object_array *commits, struct rev_info *revs)
+static void handle_tail(struct object_array *commits, struct rev_info *revs,
+ struct string_list *paths_of_changed_objects)
{
struct commit *commit;
while (commits->nr) {
- commit = (struct commit *)commits->objects[commits->nr - 1].item;
+ commit = (struct commit *)object_array_pop(commits);
if (has_unshown_parent(commit))
return;
- handle_commit(commit, revs);
- commits->nr--;
+ handle_commit(commit, revs, paths_of_changed_objects);
}
}
@@ -808,7 +823,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), oid.hash, &full_name) != 1)
+ if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
continue;
if (refspecs) {
@@ -880,7 +895,7 @@ static void export_marks(char *file)
{
unsigned int i;
uint32_t mark;
- struct object_decoration *deco = idnums.hash;
+ struct decoration_entry *deco = idnums.entries;
FILE *f;
int e = 0;
@@ -977,6 +992,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
char *export_filename = NULL, *import_filename = NULL;
uint32_t lastimportid;
struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
+ struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP;
struct option options[] = {
OPT_INTEGER(0, "progress", &progress,
N_("show progress after <n> objects")),
@@ -1049,14 +1065,15 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
revs.diffopt.format_callback = show_filemodify;
- DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+ revs.diffopt.format_callback_data = &paths_of_changed_objects;
+ revs.diffopt.flags.recursive = 1;
while ((commit = get_revision(&revs))) {
if (has_unshown_parent(commit)) {
add_object_array(&commit->object, NULL, &commits);
}
else {
- handle_commit(commit, &revs);
- handle_tail(&commits, &revs);
+ handle_commit(commit, &revs, &paths_of_changed_objects);
+ handle_tail(&commits, &revs, &paths_of_changed_objects);
}
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c87e59f..7bbcd26 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -3,6 +3,7 @@
*/
#include "cache.h"
#include "config.h"
+#include "repository.h"
#include "refs.h"
#include "commit.h"
#include "builtin.h"
@@ -17,6 +18,7 @@
#include "connected.h"
#include "argv-array.h"
#include "utf8.h"
+#include "packfile.h"
static const char * const builtin_fetch_usage[] = {
N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -39,7 +41,7 @@ static int prune = -1; /* unspecified */
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
static int progress = -1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
-static int max_children = -1;
+static int max_children = 1;
static enum transport_family family;
static const char *depth;
static const char *deepen_since;
@@ -68,9 +70,30 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
recurse_submodules = r;
}
+ if (!strcmp(k, "submodule.fetchjobs")) {
+ max_children = parse_submodule_fetchjobs(k, v);
+ return 0;
+ } else if (!strcmp(k, "fetch.recursesubmodules")) {
+ recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+ return 0;
+ }
+
return git_default_config(k, v, cb);
}
+static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "submodule.fetchjobs")) {
+ max_children = parse_submodule_fetchjobs(var, value);
+ return 0;
+ } else if (!strcmp(var, "fetch.recursesubmodules")) {
+ recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
+ return 0;
+ }
+
+ return 0;
+}
+
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
@@ -435,8 +458,8 @@ static int s_update_ref(const char *action,
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref->name,
- ref->new_oid.hash,
- check_old ? ref->old_oid.hash : NULL,
+ &ref->new_oid,
+ check_old ? &ref->old_oid : NULL,
0, msg, &err))
goto fail;
@@ -705,7 +728,7 @@ static int update_local_ref(struct ref *ref,
}
}
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
{
struct ref **rm = cb_data;
struct ref *ref = *rm;
@@ -715,7 +738,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
- hashcpy(sha1, ref->old_oid.hash);
+ oidcpy(oid, &ref->old_oid);
return 0;
}
@@ -1072,9 +1095,6 @@ static int do_fetch(struct transport *transport,
tags = TAGS_UNSET;
}
- if (!transport->get_refs_list || !transport->fetch)
- die(_("Don't know how to fetch from %s"), transport->url);
-
/* if not appending, truncate FETCH_HEAD */
if (!append && !dry_run) {
retcode = truncate_fetch_head();
@@ -1311,6 +1331,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
+ config_from_gitmodules(gitmodules_fetch_config, NULL);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
@@ -1338,12 +1359,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (depth || deepen_since || deepen_not.nr)
deepen = 1;
- if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
- set_config_fetch_recurse_submodules(recurse_submodules_default);
- gitmodules_config();
- git_config(submodule_config, NULL);
- }
-
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
@@ -1380,9 +1395,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct argv_array options = ARGV_ARRAY_INIT;
add_options_to_argv(&options);
- result = fetch_populated_submodules(&options,
+ result = fetch_populated_submodules(the_repository,
+ &options,
submodule_prefix,
recurse_submodules,
+ recurse_submodules_default,
verbosity < 0,
max_children);
argv_array_clear(&options);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index e99b5dd..8e8a15e 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -377,7 +377,8 @@ static void shortlog(const char *name,
string_list_append(&subjects,
oid_to_hex(&commit->object.oid));
else
- string_list_append(&subjects, strbuf_detach(&sb, NULL));
+ string_list_append_nodup(&subjects,
+ strbuf_detach(&sb, NULL));
}
if (opts->credit_people)
@@ -571,7 +572,7 @@ static void find_merge_parents(struct merge_parents *result,
head_commit = lookup_commit(head);
if (head_commit)
commit_list_insert(head_commit, &parents);
- parents = reduce_heads(parents);
+ reduce_heads_replace(&parents);
while (parents) {
struct commit *cmit = pop_commit(&parents);
@@ -603,7 +604,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
/* get current branch */
current_branch = current_branch_to_free =
- resolve_refdup("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL);
+ resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
if (!current_branch)
die("No current branch");
if (starts_with(current_branch, "refs/heads/"))
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 5d7c921..e931be9 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -36,6 +36,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+ OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
N_("field name to sort on"), &parse_opt_ref_sorting),
OPT_CALLBACK(0, "points-at", &filter.points_at,
diff --git a/builtin/fsck.c b/builtin/fsck.c
index d18244a..04846d4 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -15,6 +15,7 @@
#include "progress.h"
#include "streaming.h"
#include "decorate.h"
+#include "packfile.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -179,14 +180,9 @@ static int traverse_reachable(void)
unsigned int nr = 0;
int result = 0;
if (show_progress)
- progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2);
+ progress = start_delayed_progress(_("Checking connectivity"), 0);
while (pending.nr) {
- struct object_array_entry *entry;
- struct object *obj;
-
- entry = pending.objects + --pending.nr;
- obj = entry->item;
- result |= traverse_one_object(obj);
+ result |= traverse_one_object(object_array_pop(&pending));
display_progress(progress, ++nr);
}
stop_progress(&progress);
@@ -559,7 +555,7 @@ static int fsck_head_link(void)
if (verbose)
fprintf(stderr, "Checking HEAD link\n");
- head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, NULL);
+ head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
if (!head_points_at) {
errors_found |= ERROR_REFS;
return error("Invalid HEAD");
@@ -730,12 +726,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
- unsigned char sha1[20];
- if (!get_sha1(arg, sha1)) {
- struct object *obj = lookup_object(sha1);
+ struct object_id oid;
+ if (!get_oid(arg, &oid)) {
+ struct object *obj = lookup_object(oid.hash);
if (!obj || !(obj->flags & HAS_OBJ)) {
- error("%s: object missing", sha1_to_hex(sha1));
+ error("%s: object missing", oid_to_hex(&oid));
errors_found |= ERROR_OBJECT;
continue;
}
@@ -763,6 +759,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
if (keep_cache_objects) {
verify_index_checksum = 1;
+ verify_ce_order = 1;
read_cache();
for (i = 0; i < active_nr; i++) {
unsigned int mode;
diff --git a/builtin/gc.c b/builtin/gc.c
index e6b8447..3c5eae0 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -19,6 +19,7 @@
#include "sigchain.h"
#include "argv-array.h"
#include "commit.h"
+#include "packfile.h"
#define FAILED_RUN "failed to run %s"
@@ -46,7 +47,7 @@ static struct argv_array prune = ARGV_ARRAY_INIT;
static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
static struct argv_array rerere = ARGV_ARRAY_INIT;
-static struct tempfile pidfile;
+static struct tempfile *pidfile;
static struct lock_file log_lock;
static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
@@ -77,7 +78,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_tempfile_path(log_lock.tempfile),
strerror(saved_errno));
fflush(stderr);
commit_lock_file(&log_lock);
@@ -241,7 +242,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
int fd;
char *pidfile_path;
- if (is_tempfile_active(&pidfile))
+ if (is_tempfile_active(pidfile))
/* already locked */
return NULL;
@@ -257,7 +258,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
int should_exit;
if (!scan_fmt)
- scan_fmt = xstrfmt("%s %%%dc", "%"SCNuMAX, HOST_NAME_MAX);
+ scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX);
fp = fopen(pidfile_path, "r");
memset(locking_host, 0, sizeof(locking_host));
should_exit =
@@ -292,7 +293,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb);
commit_lock_file(&lock);
- register_tempfile(&pidfile, pidfile_path);
+ pidfile = register_tempfile(pidfile_path);
free(pidfile_path);
return NULL;
}
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index e21c541..2706fcf 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -26,15 +26,16 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
usage(builtin_get_tar_commit_id_usage);
n = read_in_full(0, buffer, HEADERSIZE);
- if (n < HEADERSIZE)
- die("git get-tar-commit-id: read error");
+ if (n < 0)
+ die_errno("git get-tar-commit-id: read error");
+ if (n != HEADERSIZE)
+ die_errno("git get-tar-commit-id: EOF before reading tar header");
if (header->typeflag[0] != 'g')
return 1;
if (!skip_prefix(content, "52 comment=", &comment))
return 1;
- n = write_in_full(1, comment, 41);
- if (n < 41)
+ if (write_in_full(1, comment, 41) < 0)
die_errno("git get-tar-commit-id: write error");
return 0;
diff --git a/builtin/grep.c b/builtin/grep.c
index 42ff870..3ca4ac8 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -28,13 +28,7 @@ static char const * const grep_usage[] = {
NULL
};
-static const char *super_prefix;
static int recurse_submodules;
-static struct argv_array submodule_options = ARGV_ARRAY_INIT;
-static const char *parent_basename;
-
-static int grep_submodule_launch(struct grep_opt *opt,
- const struct grep_source *gs);
#define GREP_NUM_THREADS_DEFAULT 8
static int num_threads;
@@ -186,10 +180,7 @@ static void *run(void *arg)
break;
opt->output_priv = w;
- if (w->source.type == GREP_SOURCE_SUBMODULE)
- hit |= grep_submodule_launch(opt, &w->source);
- else
- hit |= grep_source(opt, &w->source);
+ hit |= grep_source(opt, &w->source);
grep_source_clear_data(&w->source);
work_done(w);
}
@@ -284,7 +275,7 @@ static int wait_all(void)
static int grep_cmd_config(const char *var, const char *value, void *cb)
{
int st = grep_config(var, value, cb);
- if (git_default_config(var, value, cb) < 0)
+ if (git_color_default_config(var, value, cb) < 0)
st = -1;
if (!strcmp(var, "grep.threads")) {
@@ -327,21 +318,13 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
{
struct strbuf pathbuf = STRBUF_INIT;
- if (super_prefix) {
- strbuf_add(&pathbuf, filename, tree_name_len);
- strbuf_addstr(&pathbuf, super_prefix);
- strbuf_addstr(&pathbuf, filename + tree_name_len);
+ if (opt->relative && opt->prefix_length) {
+ quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
+ strbuf_insert(&pathbuf, 0, filename, tree_name_len);
} else {
strbuf_addstr(&pathbuf, filename);
}
- if (opt->relative && opt->prefix_length) {
- char *name = strbuf_detach(&pathbuf, NULL);
- quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf);
- strbuf_insert(&pathbuf, 0, name, tree_name_len);
- free(name);
- }
-
#ifndef NO_PTHREADS
if (num_threads) {
add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid);
@@ -366,15 +349,10 @@ static int grep_file(struct grep_opt *opt, const char *filename)
{
struct strbuf buf = STRBUF_INIT;
- if (super_prefix)
- strbuf_addstr(&buf, super_prefix);
- strbuf_addstr(&buf, filename);
-
- if (opt->relative && opt->prefix_length) {
- char *name = strbuf_detach(&buf, NULL);
- quote_path_relative(name, opt->prefix, &buf);
- free(name);
- }
+ if (opt->relative && opt->prefix_length)
+ quote_path_relative(filename, opt->prefix, &buf);
+ else
+ strbuf_addstr(&buf, filename);
#ifndef NO_PTHREADS
if (num_threads) {
@@ -421,284 +399,91 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
exit(status);
}
-static void compile_submodule_options(const struct grep_opt *opt,
- const char **argv,
- int cached, int untracked,
- int opt_exclude, int use_index,
- int pattern_type_arg)
-{
- struct grep_pat *pattern;
-
- if (recurse_submodules)
- argv_array_push(&submodule_options, "--recurse-submodules");
-
- if (cached)
- argv_array_push(&submodule_options, "--cached");
- if (!use_index)
- argv_array_push(&submodule_options, "--no-index");
- if (untracked)
- argv_array_push(&submodule_options, "--untracked");
- if (opt_exclude > 0)
- argv_array_push(&submodule_options, "--exclude-standard");
-
- if (opt->invert)
- argv_array_push(&submodule_options, "-v");
- if (opt->ignore_case)
- argv_array_push(&submodule_options, "-i");
- if (opt->word_regexp)
- argv_array_push(&submodule_options, "-w");
- switch (opt->binary) {
- case GREP_BINARY_NOMATCH:
- argv_array_push(&submodule_options, "-I");
- break;
- case GREP_BINARY_TEXT:
- argv_array_push(&submodule_options, "-a");
- break;
- default:
- break;
- }
- if (opt->allow_textconv)
- argv_array_push(&submodule_options, "--textconv");
- if (opt->max_depth != -1)
- argv_array_pushf(&submodule_options, "--max-depth=%d",
- opt->max_depth);
- if (opt->linenum)
- argv_array_push(&submodule_options, "-n");
- if (!opt->pathname)
- argv_array_push(&submodule_options, "-h");
- if (!opt->relative)
- argv_array_push(&submodule_options, "--full-name");
- if (opt->name_only)
- argv_array_push(&submodule_options, "-l");
- if (opt->unmatch_name_only)
- argv_array_push(&submodule_options, "-L");
- if (opt->null_following_name)
- argv_array_push(&submodule_options, "-z");
- if (opt->count)
- argv_array_push(&submodule_options, "-c");
- if (opt->file_break)
- argv_array_push(&submodule_options, "--break");
- if (opt->heading)
- argv_array_push(&submodule_options, "--heading");
- if (opt->pre_context)
- argv_array_pushf(&submodule_options, "--before-context=%d",
- opt->pre_context);
- if (opt->post_context)
- argv_array_pushf(&submodule_options, "--after-context=%d",
- opt->post_context);
- if (opt->funcname)
- argv_array_push(&submodule_options, "-p");
- if (opt->funcbody)
- argv_array_push(&submodule_options, "-W");
- if (opt->all_match)
- argv_array_push(&submodule_options, "--all-match");
- if (opt->debug)
- argv_array_push(&submodule_options, "--debug");
- if (opt->status_only)
- argv_array_push(&submodule_options, "-q");
-
- switch (pattern_type_arg) {
- case GREP_PATTERN_TYPE_BRE:
- argv_array_push(&submodule_options, "-G");
- break;
- case GREP_PATTERN_TYPE_ERE:
- argv_array_push(&submodule_options, "-E");
- break;
- case GREP_PATTERN_TYPE_FIXED:
- argv_array_push(&submodule_options, "-F");
- break;
- case GREP_PATTERN_TYPE_PCRE:
- argv_array_push(&submodule_options, "-P");
- break;
- case GREP_PATTERN_TYPE_UNSPECIFIED:
- break;
- default:
- die("BUG: Added a new grep pattern type without updating switch statement");
- }
-
- for (pattern = opt->pattern_list; pattern != NULL;
- pattern = pattern->next) {
- switch (pattern->token) {
- case GREP_PATTERN:
- argv_array_pushf(&submodule_options, "-e%s",
- pattern->pattern);
- break;
- case GREP_AND:
- case GREP_OPEN_PAREN:
- case GREP_CLOSE_PAREN:
- case GREP_NOT:
- case GREP_OR:
- argv_array_push(&submodule_options, pattern->pattern);
- break;
- /* BODY and HEAD are not used by git-grep */
- case GREP_PATTERN_BODY:
- case GREP_PATTERN_HEAD:
- break;
- }
- }
-
- /*
- * Limit number of threads for child process to use.
- * This is to prevent potential fork-bomb behavior of git-grep as each
- * submodule process has its own thread pool.
- */
- argv_array_pushf(&submodule_options, "--threads=%d",
- DIV_ROUND_UP(num_threads, 2));
-
- /* Add Pathspecs */
- argv_array_push(&submodule_options, "--");
- for (; *argv; argv++)
- argv_array_push(&submodule_options, *argv);
-}
+static int grep_cache(struct grep_opt *opt, struct repository *repo,
+ const struct pathspec *pathspec, int cached);
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+ struct tree_desc *tree, struct strbuf *base, int tn_len,
+ int check_attr, struct repository *repo);
-/*
- * Launch child process to grep contents of a submodule
- */
-static int grep_submodule_launch(struct grep_opt *opt,
- const struct grep_source *gs)
+static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
+ const struct pathspec *pathspec,
+ const struct object_id *oid,
+ const char *filename, const char *path)
{
- struct child_process cp = CHILD_PROCESS_INIT;
- int status, i;
- const char *end_of_base;
- const char *name;
- struct strbuf child_output = STRBUF_INIT;
-
- end_of_base = strchr(gs->name, ':');
- if (gs->identifier && end_of_base)
- name = end_of_base + 1;
- else
- name = gs->name;
+ struct repository submodule;
+ int hit;
- prepare_submodule_repo_env(&cp.env_array);
- argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
+ if (!is_submodule_active(superproject, path))
+ return 0;
- if (opt->relative && opt->prefix_length)
- argv_array_pushf(&cp.env_array, "%s=%s",
- GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
- opt->prefix);
+ if (repo_submodule_init(&submodule, superproject, path))
+ return 0;
- /* Add super prefix */
- argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
- super_prefix ? super_prefix : "",
- name);
- argv_array_push(&cp.args, "grep");
+ repo_read_gitmodules(&submodule);
/*
- * Add basename of parent project
- * When performing grep on a tree object the filename is prefixed
- * with the object's name: 'tree-name:filename'. In order to
- * provide uniformity of output we want to pass the name of the
- * parent project's object name to the submodule so the submodule can
- * prefix its output with the parent's name and not its own OID.
+ * NEEDSWORK: This adds the submodule's object directory to the list of
+ * alternates for the single in-memory object store. This has some bad
+ * consequences for memory (processed objects will never be freed) and
+ * performance (this increases the number of pack files git has to pay
+ * attention to, to the sum of the number of pack files in all the
+ * repositories processed so far). This can be removed once the object
+ * store is no longer global and instead is a member of the repository
+ * object.
*/
- if (gs->identifier && end_of_base)
- argv_array_pushf(&cp.args, "--parent-basename=%.*s",
- (int) (end_of_base - gs->name),
- gs->name);
+ grep_read_lock();
+ add_to_alternates_memory(submodule.objectdir);
+ grep_read_unlock();
- /* Add options */
- for (i = 0; i < submodule_options.argc; i++) {
- /*
- * If there is a tree identifier for the submodule, add the
- * rev after adding the submodule options but before the
- * pathspecs. To do this we listen for the '--' and insert the
- * oid before pushing the '--' onto the child process argv
- * array.
- */
- if (gs->identifier &&
- !strcmp("--", submodule_options.argv[i])) {
- argv_array_push(&cp.args, oid_to_hex(gs->identifier));
- }
+ if (oid) {
+ struct object *object;
+ struct tree_desc tree;
+ void *data;
+ unsigned long size;
+ struct strbuf base = STRBUF_INIT;
- argv_array_push(&cp.args, submodule_options.argv[i]);
- }
+ object = parse_object_or_die(oid, oid_to_hex(oid));
- cp.git_cmd = 1;
- cp.dir = gs->path;
+ grep_read_lock();
+ data = read_object_with_reference(object->oid.hash, tree_type,
+ &size, NULL);
+ grep_read_unlock();
- /*
- * Capture output to output buffer and check the return code from the
- * child process. A '0' indicates a hit, a '1' indicates no hit and
- * anything else is an error.
- */
- status = capture_command(&cp, &child_output, 0);
- if (status && (status != 1)) {
- /* flush the buffer */
- write_or_die(1, child_output.buf, child_output.len);
- die("process for submodule '%s' failed with exit code: %d",
- gs->name, status);
- }
+ if (!data)
+ die(_("unable to read tree (%s)"), oid_to_hex(&object->oid));
- opt->output(opt, child_output.buf, child_output.len);
- strbuf_release(&child_output);
- /* invert the return code to make a hit equal to 1 */
- return !status;
-}
+ strbuf_addstr(&base, filename);
+ strbuf_addch(&base, '/');
-/*
- * Prep grep structures for a submodule grep
- * oid: the oid of the submodule or NULL if using the working tree
- * filename: name of the submodule including tree name of parent
- * path: location of the submodule
- */
-static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
- const char *filename, const char *path)
-{
- if (!is_submodule_active(the_repository, path))
- return 0;
- if (!is_submodule_populated_gently(path, NULL)) {
- /*
- * If searching history, check for the presence of the
- * submodule's gitdir before skipping the submodule.
- */
- if (oid) {
- const struct submodule *sub =
- submodule_from_path(null_sha1, path);
- if (sub)
- path = git_path("modules/%s", sub->name);
-
- if (!(is_directory(path) && is_git_directory(path)))
- return 0;
- } else {
- return 0;
- }
+ init_tree_desc(&tree, data, size);
+ hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+ object->type == OBJ_COMMIT, &submodule);
+ strbuf_release(&base);
+ free(data);
+ } else {
+ hit = grep_cache(opt, &submodule, pathspec, 1);
}
-#ifndef NO_PTHREADS
- if (num_threads) {
- add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid);
- return 0;
- } else
-#endif
- {
- struct grep_source gs;
- int hit;
-
- grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
- filename, path, oid);
- hit = grep_submodule_launch(opt, &gs);
-
- grep_source_clear(&gs);
- return hit;
- }
+ repo_clear(&submodule);
+ return hit;
}
-static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
- int cached)
+static int grep_cache(struct grep_opt *opt, struct repository *repo,
+ const struct pathspec *pathspec, int cached)
{
int hit = 0;
int nr;
struct strbuf name = STRBUF_INIT;
int name_base_len = 0;
- if (super_prefix) {
- name_base_len = strlen(super_prefix);
- strbuf_addstr(&name, super_prefix);
+ if (repo->submodule_prefix) {
+ name_base_len = strlen(repo->submodule_prefix);
+ strbuf_addstr(&name, repo->submodule_prefix);
}
- read_cache();
+ repo_read_index(repo);
- for (nr = 0; nr < active_nr; nr++) {
- const struct cache_entry *ce = active_cache[nr];
+ for (nr = 0; nr < repo->index->cache_nr; nr++) {
+ const struct cache_entry *ce = repo->index->cache[nr];
strbuf_setlen(&name, name_base_len);
strbuf_addstr(&name, ce->name);
@@ -715,14 +500,14 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
ce_skip_worktree(ce)) {
if (ce_stage(ce) || ce_intent_to_add(ce))
continue;
- hit |= grep_oid(opt, &ce->oid, ce->name,
- 0, ce->name);
+ hit |= grep_oid(opt, &ce->oid, name.buf,
+ 0, name.buf);
} else {
- hit |= grep_file(opt, ce->name);
+ hit |= grep_file(opt, name.buf);
}
} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
submodule_path_match(pathspec, name.buf, NULL)) {
- hit |= grep_submodule(opt, NULL, ce->name, ce->name);
+ hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);
} else {
continue;
}
@@ -730,8 +515,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
if (ce_stage(ce)) {
do {
nr++;
- } while (nr < active_nr &&
- !strcmp(ce->name, active_cache[nr]->name));
+ } while (nr < repo->index->cache_nr &&
+ !strcmp(ce->name, repo->index->cache[nr]->name));
nr--; /* compensate for loop control */
}
if (hit && opt->status_only)
@@ -744,7 +529,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
struct tree_desc *tree, struct strbuf *base, int tn_len,
- int check_attr)
+ int check_attr, struct repository *repo)
{
int hit = 0;
enum interesting match = entry_not_interesting;
@@ -752,8 +537,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
int old_baselen = base->len;
struct strbuf name = STRBUF_INIT;
int name_base_len = 0;
- if (super_prefix) {
- strbuf_addstr(&name, super_prefix);
+ if (repo->submodule_prefix) {
+ strbuf_addstr(&name, repo->submodule_prefix);
name_base_len = name.len;
}
@@ -791,11 +576,11 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_addch(base, '/');
init_tree_desc(&sub, data, size);
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
- check_attr);
+ check_attr, repo);
free(data);
} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
- hit |= grep_submodule(opt, entry.oid, base->buf,
- base->buf + tn_len);
+ hit |= grep_submodule(opt, repo, pathspec, entry.oid,
+ base->buf, base->buf + tn_len);
}
strbuf_setlen(base, old_baselen);
@@ -809,7 +594,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
}
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
- struct object *obj, const char *name, const char *path)
+ struct object *obj, const char *name, const char *path,
+ struct repository *repo)
{
if (obj->type == OBJ_BLOB)
return grep_oid(opt, &obj->oid, name, 0, path);
@@ -828,10 +614,6 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
- /* Use parent's name as base when recursing submodules */
- if (recurse_submodules && parent_basename)
- name = parent_basename;
-
len = name ? strlen(name) : 0;
strbuf_init(&base, PATH_MAX + len + 1);
if (len) {
@@ -840,7 +622,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
}
init_tree_desc(&tree, data, size);
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
- obj->type == OBJ_COMMIT);
+ obj->type == OBJ_COMMIT, repo);
strbuf_release(&base);
free(data);
return hit;
@@ -849,6 +631,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
}
static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
+ struct repository *repo,
const struct object_array *list)
{
unsigned int i;
@@ -862,9 +645,10 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
/* load the gitmodules file for this rev */
if (recurse_submodules) {
submodule_free();
- gitmodules_config_sha1(real_obj->oid.hash);
+ gitmodules_config_oid(&real_obj->oid);
}
- if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
+ if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
+ repo)) {
hit = 1;
if (opt->status_only)
break;
@@ -1005,9 +789,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("ignore files specified via '.gitignore'"), 1),
OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
N_("recursively search in each submodule")),
- OPT_STRING(0, "parent-basename", &parent_basename,
- N_("basename"),
- N_("prepend parent project's basename to output")),
OPT_GROUP(""),
OPT_BOOL('v', "invert-match", &opt.invert,
N_("show non-matching lines")),
@@ -1112,7 +893,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
init_grep_defaults();
git_config(grep_cmd_config, NULL);
grep_init(&opt, prefix);
- super_prefix = get_super_prefix();
/*
* If there is no -- then the paths must exist in the working
@@ -1205,8 +985,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
break;
}
- if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
- oid.hash, &oc)) {
+ if (get_oid_with_context(arg, GET_OID_RECORD_PATH,
+ &oid, &oc)) {
if (seen_dashdash)
die(_("unable to resolve revision: %s"), arg);
break;
@@ -1235,6 +1015,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
prefix, argv + i);
pathspec.max_depth = opt.max_depth;
pathspec.recursive = 1;
+ pathspec.recurse_submodules = !!recurse_submodules;
#ifndef NO_PTHREADS
if (list.nr || cached || show_in_pager)
@@ -1270,13 +1051,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
}
#endif
- if (recurse_submodules) {
- gitmodules_config();
- compile_submodule_options(&opt, argv + i, cached, untracked,
- opt_exclude, use_index,
- pattern_type_arg);
- }
-
if (show_in_pager && (cached || list.nr))
die(_("--open-files-in-pager only works on the worktree"));
@@ -1318,11 +1092,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!cached)
setup_work_tree();
- hit = grep_cache(&opt, &pathspec, cached);
+ hit = grep_cache(&opt, the_repository, &pathspec, cached);
} else {
if (cached)
die(_("both --cached and trees are given."));
- hit = grep_objects(&opt, &pathspec, &list);
+
+ hit = grep_objects(&opt, &pathspec, the_repository, &list);
}
if (num_threads)
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index d04baf9..c532ff9 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -16,7 +16,7 @@
* needs to bypass the data conversion performed by, and the type
* limitation imposed by, index_fd() and its callees.
*/
-static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigned flags)
+static int hash_literally(struct object_id *oid, int fd, const char *type, unsigned flags)
{
struct strbuf buf = STRBUF_INIT;
int ret;
@@ -24,7 +24,7 @@ static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigne
if (strbuf_read(&buf, fd, 4096) < 0)
ret = -1;
else
- ret = hash_sha1_file_literally(buf.buf, buf.len, type, sha1, flags);
+ ret = hash_sha1_file_literally(buf.buf, buf.len, type, oid, flags);
strbuf_release(&buf);
return ret;
}
@@ -33,16 +33,16 @@ static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
int literally)
{
struct stat st;
- unsigned char sha1[20];
+ struct object_id oid;
if (fstat(fd, &st) < 0 ||
(literally
- ? hash_literally(sha1, fd, type, flags)
- : index_fd(sha1, fd, &st, type_from_string(type), path, flags)))
+ ? hash_literally(&oid, fd, type, flags)
+ : index_fd(&oid, fd, &st, type_from_string(type), path, flags)))
die((flags & HASH_WRITE_OBJECT)
? "Unable to add %s to database"
: "Unable to hash %s", path);
- printf("%s\n", sha1_to_hex(sha1));
+ printf("%s\n", oid_to_hex(&oid));
maybe_flush_or_die(stdout, "hash to stdout");
}
diff --git a/builtin/help.c b/builtin/help.c
index 334a849..d3c8fc4 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -131,6 +131,7 @@ static void exec_woman_emacs(const char *path, const char *page)
strbuf_addf(&man_page, "(woman \"%s\")", page);
execlp(path, "emacsclient", "-e", man_page.buf, (char *)NULL);
warning_errno(_("failed to exec '%s'"), path);
+ strbuf_release(&man_page);
}
}
@@ -152,6 +153,7 @@ static void exec_man_konqueror(const char *path, const char *page)
strbuf_addf(&man_page, "man:%s(1)", page);
execlp(path, filename, "newTab", man_page.buf, (char *)NULL);
warning_errno(_("failed to exec '%s'"), path);
+ strbuf_release(&man_page);
}
}
@@ -169,6 +171,7 @@ static void exec_man_cmd(const char *cmd, const char *page)
strbuf_addf(&shell_cmd, "%s %s", cmd, page);
execl(SHELL_PATH, SHELL_PATH, "-c", shell_cmd.buf, (char *)NULL);
warning(_("failed to exec '%s'"), cmd);
+ strbuf_release(&shell_cmd);
}
static void add_man_viewer(const char *name)
@@ -438,7 +441,7 @@ static const char *check_git_cmd(const char* cmd)
alias = alias_lookup(cmd);
if (alias) {
- printf_ln(_("`git %s' is aliased to `%s'"), cmd, alias);
+ printf_ln(_("'%s' is aliased to '%s'"), cmd, alias);
free(alias);
exit(0);
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 26828c1..4c51aec 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -12,6 +12,7 @@
#include "exec_cmd.h"
#include "streaming.h"
#include "thread-utils.h"
+#include "packfile.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -632,7 +633,7 @@ static int find_ofs_delta(const off_t offset, enum object_type type)
int first = 0, last = nr_ofs_deltas;
while (first < last) {
- int next = (first + last) / 2;
+ int next = first + (last - first) / 2;
struct ofs_delta_entry *delta = &ofs_deltas[next];
int cmp;
@@ -686,7 +687,7 @@ static int find_ref_delta(const unsigned char *sha1, enum object_type type)
int first = 0, last = nr_ref_deltas;
while (first < last) {
- int next = (first + last) / 2;
+ int next = first + (last - first) / 2;
struct ref_delta_entry *delta = &ref_deltas[next];
int cmp;
@@ -1659,10 +1660,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
from_stdin = 1;
} else if (!strcmp(arg, "--fix-thin")) {
fix_thin_pack = 1;
- } else if (!strcmp(arg, "--strict")) {
- strict = 1;
- do_fsck_object = 1;
- } else if (skip_prefix(arg, "--strict=", &arg)) {
+ } else if (skip_to_optional_arg(arg, "--strict", &arg)) {
strict = 1;
do_fsck_object = 1;
fsck_set_msg_types(&fsck_options, arg);
@@ -1678,10 +1676,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
verify = 1;
show_stat = 1;
stat_only = 1;
- } else if (!strcmp(arg, "--keep")) {
- keep_msg = "";
- } else if (starts_with(arg, "--keep=")) {
- keep_msg = arg + 7;
+ } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
+ ; /* nothing to do */
} else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 47823f9..c9b7946 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -579,6 +579,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
set_git_work_tree(work_tree);
}
+ UNLEAK(real_git_dir);
+
flags |= INIT_DB_EXIST_OK;
return init_db(git_dir, real_git_dir, template_dir, flags);
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 175f147..b742539 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -16,34 +16,119 @@ static const char * const git_interpret_trailers_usage[] = {
NULL
};
+static enum trailer_where where;
+static enum trailer_if_exists if_exists;
+static enum trailer_if_missing if_missing;
+
+static int option_parse_where(const struct option *opt,
+ const char *arg, int unset)
+{
+ return trailer_set_where(&where, arg);
+}
+
+static int option_parse_if_exists(const struct option *opt,
+ const char *arg, int unset)
+{
+ return trailer_set_if_exists(&if_exists, arg);
+}
+
+static int option_parse_if_missing(const struct option *opt,
+ const char *arg, int unset)
+{
+ return trailer_set_if_missing(&if_missing, arg);
+}
+
+static void new_trailers_clear(struct list_head *trailers)
+{
+ struct list_head *pos, *tmp;
+ struct new_trailer_item *item;
+
+ list_for_each_safe(pos, tmp, trailers) {
+ item = list_entry(pos, struct new_trailer_item, list);
+ list_del(pos);
+ free(item);
+ }
+}
+
+static int option_parse_trailer(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct list_head *trailers = opt->value;
+ struct new_trailer_item *item;
+
+ if (unset) {
+ new_trailers_clear(trailers);
+ return 0;
+ }
+
+ if (!arg)
+ return -1;
+
+ item = xmalloc(sizeof(*item));
+ item->text = arg;
+ item->where = where;
+ item->if_exists = if_exists;
+ item->if_missing = if_missing;
+ list_add_tail(&item->list, trailers);
+ return 0;
+}
+
+static int parse_opt_parse(const struct option *opt, const char *arg,
+ int unset)
+{
+ struct process_trailer_options *v = opt->value;
+ v->only_trailers = 1;
+ v->only_input = 1;
+ v->unfold = 1;
+ return 0;
+}
+
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
{
- int in_place = 0;
- int trim_empty = 0;
- struct string_list trailers = STRING_LIST_INIT_NODUP;
+ struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
+ LIST_HEAD(trailers);
struct option options[] = {
- OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
- OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
- OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
- N_("trailer(s) to add")),
+ OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
+ OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
+
+ OPT_CALLBACK(0, "where", NULL, N_("action"),
+ N_("where to place the new trailer"), option_parse_where),
+ OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
+ N_("action if trailer already exists"), option_parse_if_exists),
+ OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
+ N_("action if trailer is missing"), option_parse_if_missing),
+
+ OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
+ OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
+ OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
+ { OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse },
+ OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
+ N_("trailer(s) to add"), option_parse_trailer),
OPT_END()
};
argc = parse_options(argc, argv, prefix, options,
git_interpret_trailers_usage, 0);
+ if (opts.only_input && !list_empty(&trailers))
+ usage_msg_opt(
+ _("--trailer with --only-input does not make sense"),
+ git_interpret_trailers_usage,
+ options);
+
if (argc) {
int i;
for (i = 0; i < argc; i++)
- process_trailers(argv[i], in_place, trim_empty, &trailers);
+ process_trailers(argv[i], &opts, &trailers);
} else {
- if (in_place)
+ if (opts.in_place)
die(_("no input file given for in-place editing"));
- process_trailers(NULL, in_place, trim_empty, &trailers);
+ process_trailers(NULL, &opts, &trailers);
}
- string_list_clear(&trailers, 0);
+ new_trailers_clear(&trailers);
return 0;
}
diff --git a/builtin/log.c b/builtin/log.c
index 5ffc380..14fdf39 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -27,6 +27,7 @@
#include "version.h"
#include "mailmap.h"
#include "gpg-interface.h"
+#include "progress.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -58,9 +59,9 @@ static int auto_decoration_style(void)
return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0;
}
-static int parse_decoration_style(const char *var, const char *value)
+static int parse_decoration_style(const char *value)
{
- switch (git_config_maybe_bool(var, value)) {
+ switch (git_parse_maybe_bool(value)) {
case 1:
return DECORATE_SHORT_REFS;
case 0:
@@ -82,7 +83,7 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
if (unset)
decoration_style = 0;
else if (arg)
- decoration_style = parse_decoration_style("command line", arg);
+ decoration_style = parse_decoration_style(arg);
else
decoration_style = DECORATE_SHORT_REFS;
@@ -120,20 +121,19 @@ static void cmd_log_init_defaults(struct rev_info *rev)
if (fmt_pretty)
get_commit_format(fmt_pretty, rev);
if (default_follow)
- DIFF_OPT_SET(&rev->diffopt, DEFAULT_FOLLOW_RENAMES);
+ rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
- DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+ rev->diffopt.flags.recursive = 1;
rev->diffopt.stat_width = -1; /* use full terminal width */
rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->show_signature = default_show_signature;
- DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
+ rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
parse_date_format(default_date_mode, &rev->date_mode);
- rev->diffopt.touched_flags = 0;
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
@@ -142,11 +142,19 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
struct userformat_want w;
int quiet = 0, source = 0, mailmap = 0;
static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
+ static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+ static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+ struct decoration_filter decoration_filter = {&decorate_refs_include,
+ &decorate_refs_exclude};
const struct option builtin_log_options[] = {
OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")),
OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+ OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
+ N_("pattern"), N_("only decorate refs that match <pattern>")),
+ OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
+ N_("pattern"), N_("do not decorate refs that match <pattern>")),
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback},
OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
@@ -181,7 +189,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
init_display_notes(&rev->notes_opt);
if (rev->diffopt.pickaxe || rev->diffopt.filter ||
- DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES))
+ rev->diffopt.flags.follow_renames)
rev->always_show_header = 0;
if (source)
@@ -205,7 +213,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
if (decoration_style) {
rev->show_decorations = 1;
- load_ref_decorations(decoration_style);
+ load_ref_decorations(&decoration_filter, decoration_style);
}
if (rev->line_level_traverse)
@@ -391,7 +399,7 @@ static int cmd_log_walk(struct rev_info *rev)
fclose(rev->diffopt.file);
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
- DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
+ rev->diffopt.flags.check_failed) {
return 02;
}
return diff_result_code(&rev->diffopt, 0);
@@ -412,7 +420,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "log.date"))
return git_config_string(&default_date_mode, var, value);
if (!strcmp(var, "log.decorate")) {
- decoration_style = parse_decoration_style(var, value);
+ decoration_style = parse_decoration_style(value);
if (decoration_style < 0)
decoration_style = 0; /* maybe warn? */
return 0;
@@ -483,12 +491,12 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
unsigned long size;
fflush(rev->diffopt.file);
- if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
- !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
+ if (!rev->diffopt.flags.textconv_set_via_cmdline ||
+ !rev->diffopt.flags.allow_textconv)
return stream_blob_to_fd(1, oid, NULL, 0);
- if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
- oidc.hash, &obj_context))
+ if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+ &oidc, &obj_context))
die(_("Not a valid object name %s"), obj_name);
if (!obj_context.path ||
!textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
@@ -666,9 +674,9 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
static void log_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
- if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
+ if (rev->diffopt.flags.default_follow_renames &&
rev->prune_data.nr == 1)
- DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
+ 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)
@@ -824,7 +832,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
return 0;
}
if (!strcmp(var, "format.from")) {
- int b = git_config_maybe_bool(var, value);
+ int b = git_parse_maybe_bool(value);
free(from);
if (b < 0)
from = xstrdup(value);
@@ -974,7 +982,7 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), branch_oid.hash, &full_ref) &&
+ if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
!oidcmp(tip_oid, &branch_oid))
branch = xstrdup(v);
@@ -1340,7 +1348,7 @@ static void prepare_bases(struct base_tree_info *bases,
return;
diff_setup(&diffopt);
- DIFF_OPT_SET(&diffopt, RECURSIVE);
+ diffopt.flags.recursive = 1;
diff_setup_done(&diffopt);
oidcpy(&bases->base_commit, &base->object.oid);
@@ -1422,6 +1430,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
+ int show_progress = 0;
+ struct progress *progress = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1493,6 +1503,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_FILENAME(0, "signature-file", &signature_file,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
+ OPT_BOOL(0, "progress", &show_progress,
+ N_("show progress while generating patches")),
OPT_END()
};
@@ -1507,7 +1519,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.verbose_header = 1;
rev.diff = 1;
rev.max_parents = 1;
- DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+ rev.diffopt.flags.recursive = 1;
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
@@ -1608,8 +1620,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.zero_commit = zero_commit;
- if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
- DIFF_OPT_SET(&rev.diffopt, BINARY);
+ if (!rev.diffopt.flags.text && !no_binary_diff)
+ rev.diffopt.flags.binary = 1;
if (rev.show_notes)
init_display_notes(&rev.notes_opt);
@@ -1655,10 +1667,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
check_head = 1;
if (check_head) {
- struct object_id oid;
const char *ref, *v;
ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- oid.hash, NULL);
+ NULL, NULL);
if (ref && skip_prefix(ref, "refs/heads/", &v))
branch_name = xstrdup(v);
else
@@ -1752,8 +1763,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
start_number--;
}
rev.add_signoff = do_signoff;
+
+ if (show_progress)
+ progress = start_delayed_progress(_("Generating patches"), total);
while (0 <= --nr) {
int shown;
+ display_progress(progress, total - nr);
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
@@ -1818,6 +1833,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (!use_stdout)
fclose(rev.diffopt.file);
}
+ stop_progress(&progress);
free(list);
free(branch_name);
string_list_clear(&extra_to, 0);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c6126ea..2fc836e 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -19,6 +19,7 @@
#include "pathspec.h"
#include "run-command.h"
#include "submodule.h"
+#include "submodule-config.h"
static int abbrev;
static int show_deleted;
@@ -30,6 +31,7 @@ static int show_resolve_undo;
static int show_modified;
static int show_killed;
static int show_valid_bit;
+static int show_fsmonitor_bit;
static int line_terminator = '\n';
static int debug_mode;
static int show_eol;
@@ -85,7 +87,8 @@ static const char *get_tag(const struct cache_entry *ce, const char *tag)
{
static char alttag[4];
- if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) {
+ if (tag && *tag && ((show_valid_bit && (ce->ce_flags & CE_VALID)) ||
+ (show_fsmonitor_bit && (ce->ce_flags & CE_FSMONITOR_VALID)))) {
memcpy(alttag, tag, 3);
if (isalpha(tag[0])) {
@@ -210,8 +213,6 @@ static void show_submodule(struct repository *superproject,
if (repo_read_index(&submodule) < 0)
die("index file corrupt");
- repo_read_gitmodules(&submodule);
-
show_files(&submodule, dir);
repo_clear(&submodule);
@@ -516,6 +517,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
N_("identify the file status with tags")),
OPT_BOOL('v', NULL, &show_valid_bit,
N_("use lowercase letters for 'assume unchanged' files")),
+ OPT_BOOL('f', NULL, &show_fsmonitor_bit,
+ N_("use lowercase letters for 'fsmonitor clean' files")),
OPT_BOOL('c', "cached", &show_cached,
N_("show cached files in the output (default)")),
OPT_BOOL('d', "deleted", &show_deleted,
@@ -585,7 +588,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
for (i = 0; i < exclude_list.nr; i++) {
add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
}
- if (show_tag || show_valid_bit) {
+ if (show_tag || show_valid_bit || show_fsmonitor_bit) {
tag_cached = "H ";
tag_unmerged = "M ";
tag_removed = "R ";
@@ -609,9 +612,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
- if (recurse_submodules)
- repo_read_gitmodules(the_repository);
-
if (recurse_submodules &&
(show_stage || show_deleted || show_others || show_unmerged ||
show_killed || show_modified || show_resolve_undo || with_tree))
@@ -677,5 +677,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
return bad ? 1 : 0;
}
+ UNLEAK(dir);
return 0;
}
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 6dbd167..3b76001 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -9,20 +9,20 @@
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
- struct commit_list *result;
+ struct commit_list *result, *r;
result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
if (!result)
return 1;
- while (result) {
- printf("%s\n", oid_to_hex(&result->item->object.oid));
+ for (r = result; r; r = r->next) {
+ printf("%s\n", oid_to_hex(&r->item->object.oid));
if (!show_all)
- return 0;
- result = result->next;
+ break;
}
+ free_commit_list(result);
return 0;
}
@@ -51,45 +51,47 @@ static struct commit *get_commit_reference(const char *arg)
static int handle_independent(int count, const char **args)
{
- struct commit_list *revs = NULL;
- struct commit_list *result;
+ struct commit_list *revs = NULL, *rev;
int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = reduce_heads(revs);
- if (!result)
+ reduce_heads_replace(&revs);
+
+ if (!revs)
return 1;
- while (result) {
- printf("%s\n", oid_to_hex(&result->item->object.oid));
- result = result->next;
- }
+ for (rev = revs; rev; rev = rev->next)
+ printf("%s\n", oid_to_hex(&rev->item->object.oid));
+
+ free_commit_list(revs);
return 0;
}
static int handle_octopus(int count, const char **args, int show_all)
{
struct commit_list *revs = NULL;
- struct commit_list *result;
+ struct commit_list *result, *rev;
int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = reduce_heads(get_octopus_merge_bases(revs));
+ result = get_octopus_merge_bases(revs);
+ free_commit_list(revs);
+ reduce_heads_replace(&result);
if (!result)
return 1;
- while (result) {
- printf("%s\n", oid_to_hex(&result->item->object.oid));
+ for (rev = result; rev; rev = rev->next) {
+ printf("%s\n", oid_to_hex(&rev->item->object.oid));
if (!show_all)
- return 0;
- result = result->next;
+ break;
}
+ free_commit_list(result);
return 0;
}
@@ -156,7 +158,7 @@ static int handle_fork_point(int argc, const char **argv)
struct commit_list *bases;
int i, ret = 0;
- switch (dwim_ref(argv[0], strlen(argv[0]), oid.hash, &refname)) {
+ switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
case 0:
die("No such ref: '%s'", argv[0]);
case 1:
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 6844116..c84c6e0 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -9,26 +9,24 @@
*/
#include "git-compat-util.h"
#include "builtin.h"
+#include "diff.h"
static const char builtin_merge_ours_usage[] =
"git merge-ours <base>... -- HEAD <remote>...";
-static const char *diff_index_args[] = {
- "diff-index", "--quiet", "--cached", "HEAD", "--", NULL
-};
-#define NARGS (ARRAY_SIZE(diff_index_args) - 1)
-
int cmd_merge_ours(int argc, const char **argv, const char *prefix)
{
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_merge_ours_usage);
/*
- * We need to exit with 2 if the index does not match our HEAD tree,
- * because the current index is what we will be committing as the
- * merge result.
+ * The contents of the current index becomes the tree we
+ * commit. The index must match HEAD, or this merge cannot go
+ * through.
*/
- if (cmd_diff_index(NARGS, diff_index_args, prefix))
+ if (read_cache() < 0)
+ die_errno("read_cache failed");
+ if (index_differs_from("HEAD", NULL, 0))
exit(2);
exit(0);
}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index bad6735..d01ddec 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -213,11 +213,11 @@ static void unresolved_directory(const struct traverse_info *info,
newbase = traverse_path(info, p);
-#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->oid->hash : NULL)
- buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
- buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
- buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
-#undef ENTRY_SHA1
+#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->oid : NULL)
+ buf0 = fill_tree_descriptor(t + 0, ENTRY_OID(n + 0));
+ buf1 = fill_tree_descriptor(t + 1, ENTRY_OID(n + 1));
+ buf2 = fill_tree_descriptor(t + 2, ENTRY_OID(n + 2));
+#undef ENTRY_OID
merge_trees(t, newbase);
@@ -347,12 +347,12 @@ static void merge_trees(struct tree_desc t[3], const char *base)
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
{
- unsigned char sha1[20];
+ struct object_id oid;
void *buf;
- if (get_sha1(rev, sha1))
+ if (get_oid(rev, &oid))
die("unknown rev %s", rev);
- buf = fill_tree_descriptor(desc, sha1);
+ buf = fill_tree_descriptor(desc, &oid);
if (!buf)
die("%s is not a tree", rev);
return buf;
diff --git a/builtin/merge.c b/builtin/merge.c
index 23c53a3..30264cf 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -32,6 +32,7 @@
#include "gpg-interface.h"
#include "sequencer.h"
#include "string-list.h"
+#include "packfile.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -70,7 +71,9 @@ static int continue_current_merge;
static int allow_unrelated_histories;
static int show_progress = -1;
static int default_to_upstream = 1;
+static int signoff;
static const char *sign_commit;
+static int verify_msg = 1;
static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
@@ -233,6 +236,8 @@ static struct option builtin_merge_options[] = {
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
+ OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
+ OPT_BOOL(0, "verify", &verify_msg, N_("verify commit-msg hook")),
OPT_END()
};
@@ -250,6 +255,7 @@ static int save_state(struct object_id *stash)
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf buffer = STRBUF_INIT;
const char *argv[] = {"stash", "create", NULL};
+ int rc = -1;
cp.argv = argv;
cp.out = -1;
@@ -263,11 +269,14 @@ static int save_state(struct object_id *stash)
if (finish_command(&cp) || len < 0)
die(_("stash failed"));
else if (!len) /* no changes */
- return -1;
+ goto out;
strbuf_setlen(&buffer, buffer.len-1);
if (get_oid(buffer.buf, stash))
die(_("not a valid object: %s"), buffer.buf);
- return 0;
+ rc = 0;
+out:
+ strbuf_release(&buffer);
+ return rc;
}
static void read_empty(unsigned const char *sha1, int verbose)
@@ -396,9 +405,8 @@ static void finish(struct commit *head_commit,
printf(_("No merge message -- not updating HEAD\n"));
else {
const char *argv_gc_auto[] = { "gc", "--auto", NULL };
- update_ref(reflog_message.buf, "HEAD",
- new_head->hash, head->hash, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref(reflog_message.buf, "HEAD", new_head, head,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/*
* We ignore errors in 'gc --auto', since the
* user should see them.
@@ -446,7 +454,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), branch_head.hash, &found_ref) > 0) {
+ if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
@@ -559,6 +567,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
show_diffstat = git_config_bool(k, v);
+ else if (!strcmp(k, "merge.verifysignatures"))
+ verify_signatures = git_config_bool(k, v);
else if (!strcmp(k, "pull.twohead"))
return git_config_string(&pull_twohead, k, v);
else if (!strcmp(k, "pull.octopus"))
@@ -566,7 +576,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)
else if (!strcmp(k, "merge.renormalize"))
option_renormalize = git_config_bool(k, v);
else if (!strcmp(k, "merge.ff")) {
- int boolval = git_config_maybe_bool(k, v);
+ int boolval = git_parse_maybe_bool(v);
if (0 <= boolval) {
fast_forward = boolval ? FF_ALLOW : FF_NO;
} else if (v && !strcmp(v, "only")) {
@@ -766,6 +776,8 @@ static void prepare_to_commit(struct commit_list *remoteheads)
BUG("the control must not reach here under --squash");
if (0 < option_edit)
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+ if (signoff)
+ append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
@@ -775,6 +787,12 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (launch_editor(git_path_merge_msg(), NULL, NULL))
abort_commit(remoteheads, NULL);
}
+
+ if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(),
+ "commit-msg",
+ git_path_merge_msg(), NULL))
+ abort_commit(remoteheads, NULL);
+
read_merge_msg(&msg);
strbuf_stripspace(&msg, 0 < option_edit);
if (!msg.len)
@@ -929,6 +947,7 @@ static void write_merge_heads(struct commit_list *remoteheads)
if (fast_forward == FF_NO)
strbuf_addstr(&buf, "no-ff");
write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
+ strbuf_release(&buf);
}
static void write_merge_state(struct commit_list *remoteheads)
@@ -949,7 +968,7 @@ static int default_edit_option(void)
return 0;
if (e) {
- int v = git_config_maybe_bool(name, e);
+ int v = git_parse_maybe_bool(e);
if (v < 0)
die(_("Bad value '%s' in environment '%s'"), e, name);
return v;
@@ -981,6 +1000,7 @@ static struct commit_list *reduce_parents(struct commit *head_commit,
/* Find what parents to record by checking independent ones. */
parents = reduce_heads(remoteheads);
+ free_commit_list(remoteheads);
remoteheads = NULL;
remotes = &remoteheads;
@@ -1125,7 +1145,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* Check if we are _not_ on a detached HEAD, i.e. if there is a
* current branch.
*/
- branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (branch)
skip_prefix(branch, "refs/heads/", &branch);
if (!branch || is_null_oid(&head_oid))
@@ -1243,8 +1263,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("Can merge only exactly one commit into empty head"));
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid->hash, 0);
- update_ref("initial pull", "HEAD", remote_head_oid->hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
goto done;
}
@@ -1339,8 +1359,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
free(list);
}
- update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref("updating ORIG_HEAD", "ORIG_HEAD",
+ &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
if (remoteheads && !common) {
/* No common ancestors found. */
@@ -1354,7 +1374,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* If head can reach all the merge then we are up to date.
* but first the most common case of merging one remote.
*/
- finish_up_to_date(_("Already up-to-date."));
+ finish_up_to_date(_("Already up to date."));
goto done;
} else if (fast_forward != FF_NO && !remoteheads->next &&
!common->next &&
@@ -1437,7 +1457,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
}
if (up_to_date) {
- finish_up_to_date(_("Already up-to-date. Yeeah!"));
+ finish_up_to_date(_("Already up to date. Yeeah!"));
goto done;
}
}
diff --git a/builtin/mv.c b/builtin/mv.c
index dcf6736..cf3684d 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -81,7 +81,7 @@ static void prepare_move_submodule(const char *src, int first,
struct strbuf submodule_dotgit = STRBUF_INIT;
if (!S_ISGITLINK(active_cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
- if (!is_staging_gitmodules_ok())
+ if (!is_staging_gitmodules_ok(&the_index))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
strbuf_addf(&submodule_dotgit, "%s/.git", src);
*submodule_gitfile = read_gitfile(submodule_dotgit.buf);
@@ -131,7 +131,6 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
- gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
@@ -292,7 +291,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
if (gitmodules_modified)
- stage_updated_gitmodules();
+ stage_updated_gitmodules(&the_index);
if (active_cache_changed &&
write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index c41ea7c..9e088eb 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -253,7 +253,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
struct commit *commit = (struct commit *)o;
int from_tag = starts_with(path, "refs/tags/");
- if (taggerdate == ULONG_MAX)
+ if (taggerdate == TIME_MAX)
taggerdate = ((struct commit *)o)->date;
path = name_ref_abbrev(path, can_abbreviate_output);
name_rev(commit, xstrdup(path), taggerdate, 0, 0,
@@ -494,5 +494,6 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
always, allow_undefined, data.name_only);
}
+ UNLEAK(revs);
return 0;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 77573cf..7c81761 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -12,7 +12,7 @@
#include "builtin.h"
#include "notes.h"
#include "blob.h"
-#include "commit.h"
+#include "pretty.h"
#include "refs.h"
#include "exec_cmd.h"
#include "run-command.h"
@@ -33,7 +33,7 @@ static const char * const git_notes_usage[] = {
N_("git notes merge --commit [-v | -q]"),
N_("git notes merge --abort [-v | -q]"),
N_("git notes [--ref <notes-ref>] remove [<object>...]"),
- N_("git notes [--ref <notes-ref>] prune [-n | -v]"),
+ N_("git notes [--ref <notes-ref>] prune [-n] [-v]"),
N_("git notes [--ref <notes-ref>] get-ref"),
NULL
};
@@ -328,6 +328,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
} else {
finish_copy_notes_for_rewrite(c, msg);
}
+ strbuf_release(&buf);
return ret;
}
@@ -456,7 +457,7 @@ static int add(int argc, const char **argv, const char *prefix)
oid_to_hex(&object));
}
- prepare_note_data(&object, &d, note->hash);
+ prepare_note_data(&object, &d, note ? note->hash : NULL);
if (d.buf.len || allow_empty) {
write_note_data(&d, new_note.hash);
if (add_note(t, &object, &new_note, combine_notes_overwrite))
@@ -685,7 +686,7 @@ static int merge_abort(struct notes_merge_options *o)
if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
- if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NODEREF))
+ if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
ret += error(_("failed to delete ref NOTES_MERGE_REF"));
if (notes_merge_abort(o))
ret += error(_("failed to remove 'git notes merge' worktree"));
@@ -723,7 +724,7 @@ static int merge_commit(struct notes_merge_options *o)
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
- resolve_refdup("NOTES_MERGE_REF", 0, oid.hash, NULL);
+ resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL);
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
@@ -735,8 +736,8 @@ static int merge_commit(struct notes_merge_options *o)
format_commit_message(partial, "%s", &msg, &pretty_ctx);
strbuf_trim(&msg);
strbuf_insert(&msg, 0, "notes: ", 7);
- update_ref(msg.buf, o->local_ref, oid.hash,
- is_null_oid(&parent_oid) ? NULL : parent_oid.hash,
+ update_ref(msg.buf, o->local_ref, &oid,
+ is_null_oid(&parent_oid) ? NULL : &parent_oid,
0, UPDATE_REFS_DIE_ON_ERR);
free_notes(t);
@@ -849,12 +850,12 @@ static int merge(int argc, const char **argv, const char *prefix)
if (result >= 0) /* Merge resulted (trivially) in result_oid */
/* Update default notes ref with new commit */
- update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
const struct worktree *wt;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
- update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL,
+ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
@@ -864,10 +865,10 @@ static int merge(int argc, const char **argv, const char *prefix)
if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
die(_("failed to store link to current notes ref (%s)"),
default_notes_ref());
- printf(_("Automatic notes merge failed. Fix conflicts in %s and "
- "commit the result with 'git notes merge --commit', or "
- "abort the merge with 'git notes merge --abort'.\n"),
- git_path(NOTES_MERGE_WORKTREE));
+ fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
+ "and commit the result with 'git notes merge --commit', "
+ "or abort the merge with 'git notes merge --abort'.\n"),
+ git_path(NOTES_MERGE_WORKTREE));
}
free_notes(t);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index c753e92..6b9cfc2 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -15,6 +15,8 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
+#include "list-objects-filter.h"
+#include "list-objects-filter-options.h"
#include "pack-objects.h"
#include "progress.h"
#include "refs.h"
@@ -25,6 +27,7 @@
#include "sha1-array.h"
#include "argv-array.h"
#include "mru.h"
+#include "packfile.h"
static const char *pack_usage[] = {
N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
@@ -78,6 +81,15 @@ static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_limit = 0;
+static struct list_objects_filter_options filter_options;
+
+enum missing_action {
+ MA_ERROR = 0, /* fail if any missing objects are encountered */
+ MA_ALLOW_ANY, /* silently allow ALL missing objects */
+};
+static enum missing_action arg_missing_action;
+static show_object_fn fn_show_object;
+
/*
* stats
*/
@@ -150,7 +162,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)
}
static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
git_zstream stream;
unsigned char ibuf[1024 * 16];
@@ -164,7 +176,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
int zret = Z_OK;
readlen = read_istream(st, ibuf, sizeof(ibuf));
if (readlen == -1)
- die(_("unable to read %s"), sha1_to_hex(sha1));
+ die(_("unable to read %s"), oid_to_hex(oid));
stream.next_in = ibuf;
stream.avail_in = readlen;
@@ -338,7 +350,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
sha1write(f, header, hdrlen);
}
if (st) {
- datalen = write_large_blob_data(st, f, entry->idx.oid.hash);
+ datalen = write_large_blob_data(st, f, &entry->idx.oid);
close_istream(st);
} else {
sha1write(f, buf, datalen);
@@ -556,13 +568,13 @@ static enum write_one_status write_one(struct sha1file *f,
static int mark_tagged(const char *path, const struct object_id *oid, int flag,
void *cb_data)
{
- unsigned char peeled[20];
+ struct object_id peeled;
struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL);
if (entry)
entry->tagged = 1;
- if (!peel_ref(path, peeled)) {
- entry = packlist_find(&to_pack, peeled, NULL);
+ if (!peel_ref(path, &peeled)) {
+ entry = packlist_find(&to_pack, peeled.hash, NULL);
if (entry)
entry->tagged = 1;
}
@@ -791,7 +803,7 @@ static void write_pack_file(void)
write_order = compute_write_order();
do {
- unsigned char sha1[20];
+ struct object_id oid;
char *pack_tmp_name = NULL;
if (pack_to_stdout)
@@ -822,13 +834,13 @@ static void write_pack_file(void)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout) {
- sha1close(f, sha1, CSUM_CLOSE);
+ sha1close(f, oid.hash, CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
- sha1close(f, sha1, CSUM_FSYNC);
+ sha1close(f, oid.hash, CSUM_FSYNC);
} else {
- int fd = sha1close(f, sha1, 0);
- fixup_pack_header_footer(fd, sha1, pack_tmp_name,
- nr_written, sha1, offset);
+ int fd = sha1close(f, oid.hash, 0);
+ fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
+ nr_written, oid.hash, offset);
close(fd);
if (write_bitmap_index) {
warning(_(no_split_warning));
@@ -862,16 +874,16 @@ static void write_pack_file(void)
strbuf_addf(&tmpname, "%s-", base_name);
if (write_bitmap_index) {
- bitmap_writer_set_checksum(sha1);
+ bitmap_writer_set_checksum(oid.hash);
bitmap_writer_build_type_index(written_list, nr_written);
}
finish_tmp_packfile(&tmpname, pack_tmp_name,
written_list, nr_written,
- &pack_idx_opts, sha1);
+ &pack_idx_opts, oid.hash);
if (write_bitmap_index) {
- strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1));
+ strbuf_addf(&tmpname, "%s.bitmap", oid_to_hex(&oid));
stop_progress(&progress_state);
@@ -886,7 +898,7 @@ static void write_pack_file(void)
strbuf_release(&tmpname);
free(pack_tmp_name);
- puts(sha1_to_hex(sha1));
+ puts(oid_to_hex(&oid));
}
/* mark written objects as written to previous pack */
@@ -927,13 +939,13 @@ static int no_try_delta(const char *path)
* found the item, since that saves us from having to look it up again a
* few lines later when we want to add the new entry.
*/
-static int have_duplicate_entry(const unsigned char *sha1,
+static int have_duplicate_entry(const struct object_id *oid,
int exclude,
uint32_t *index_pos)
{
struct object_entry *entry;
- entry = packlist_find(&to_pack, sha1, index_pos);
+ entry = packlist_find(&to_pack, oid->hash, index_pos);
if (!entry)
return 0;
@@ -989,7 +1001,7 @@ static int want_found_object(int exclude, struct packed_git *p)
* function finds if there is any pack that has the object and returns the pack
* and its offset in these variables.
*/
-static int want_object_in_pack(const unsigned char *sha1,
+static int want_object_in_pack(const struct object_id *oid,
int exclude,
struct packed_git **found_pack,
off_t *found_offset)
@@ -997,7 +1009,7 @@ static int want_object_in_pack(const unsigned char *sha1,
struct mru_entry *entry;
int want;
- if (!exclude && local && has_loose_object_nonlocal(sha1))
+ if (!exclude && local && has_loose_object_nonlocal(oid->hash))
return 0;
/*
@@ -1011,14 +1023,14 @@ static int want_object_in_pack(const unsigned char *sha1,
return want;
}
- for (entry = packed_git_mru->head; entry; entry = entry->next) {
+ for (entry = packed_git_mru.head; entry; entry = entry->next) {
struct packed_git *p = entry->item;
off_t offset;
if (p == *found_pack)
offset = *found_offset;
else
- offset = find_pack_entry_one(sha1, p);
+ offset = find_pack_entry_one(oid->hash, p);
if (offset) {
if (!*found_pack) {
@@ -1029,7 +1041,7 @@ static int want_object_in_pack(const unsigned char *sha1,
}
want = want_found_object(exclude, p);
if (!exclude && want > 0)
- mru_mark(packed_git_mru, entry);
+ mru_mark(&packed_git_mru, entry);
if (want != -1)
return want;
}
@@ -1038,7 +1050,7 @@ static int want_object_in_pack(const unsigned char *sha1,
return 1;
}
-static void create_object_entry(const unsigned char *sha1,
+static void create_object_entry(const struct object_id *oid,
enum object_type type,
uint32_t hash,
int exclude,
@@ -1049,7 +1061,7 @@ static void create_object_entry(const unsigned char *sha1,
{
struct object_entry *entry;
- entry = packlist_alloc(&to_pack, sha1, index_pos);
+ entry = packlist_alloc(&to_pack, oid->hash, index_pos);
entry->hash = hash;
if (type)
entry->type = type;
@@ -1069,17 +1081,17 @@ static const char no_closure_warning[] = N_(
"disabling bitmap writing, as some objects are not being packed"
);
-static int add_object_entry(const unsigned char *sha1, enum object_type type,
+static int add_object_entry(const struct object_id *oid, enum object_type type,
const char *name, int exclude)
{
struct packed_git *found_pack = NULL;
off_t found_offset = 0;
uint32_t index_pos;
- if (have_duplicate_entry(sha1, exclude, &index_pos))
+ if (have_duplicate_entry(oid, exclude, &index_pos))
return 0;
- if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset)) {
+ if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
/* The pack is missing an object, so it will not have closure */
if (write_bitmap_index) {
warning(_(no_closure_warning));
@@ -1088,7 +1100,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
return 0;
}
- create_object_entry(sha1, type, pack_name_hash(name),
+ create_object_entry(oid, type, pack_name_hash(name),
exclude, name && no_try_delta(name),
index_pos, found_pack, found_offset);
@@ -1096,27 +1108,27 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
return 1;
}
-static int add_object_entry_from_bitmap(const unsigned char *sha1,
+static int add_object_entry_from_bitmap(const struct object_id *oid,
enum object_type type,
int flags, uint32_t name_hash,
struct packed_git *pack, off_t offset)
{
uint32_t index_pos;
- if (have_duplicate_entry(sha1, 0, &index_pos))
+ if (have_duplicate_entry(oid, 0, &index_pos))
return 0;
- if (!want_object_in_pack(sha1, 0, &pack, &offset))
+ if (!want_object_in_pack(oid, 0, &pack, &offset))
return 0;
- create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
+ create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
display_progress(progress_state, nr_result);
return 1;
}
struct pbase_tree_cache {
- unsigned char sha1[20];
+ struct object_id oid;
int ref;
int temporary;
void *tree_data;
@@ -1124,9 +1136,9 @@ struct pbase_tree_cache {
};
static struct pbase_tree_cache *(pbase_tree_cache[256]);
-static int pbase_tree_cache_ix(const unsigned char *sha1)
+static int pbase_tree_cache_ix(const struct object_id *oid)
{
- return sha1[0] % ARRAY_SIZE(pbase_tree_cache);
+ return oid->hash[0] % ARRAY_SIZE(pbase_tree_cache);
}
static int pbase_tree_cache_ix_incr(int ix)
{
@@ -1143,14 +1155,14 @@ static struct pbase_tree {
struct pbase_tree_cache pcache;
} *pbase_tree;
-static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
+static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
{
struct pbase_tree_cache *ent, *nent;
void *data;
unsigned long size;
enum object_type type;
int neigh;
- int my_ix = pbase_tree_cache_ix(sha1);
+ int my_ix = pbase_tree_cache_ix(oid);
int available_ix = -1;
/* pbase-tree-cache acts as a limited hashtable.
@@ -1159,7 +1171,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
*/
for (neigh = 0; neigh < 8; neigh++) {
ent = pbase_tree_cache[my_ix];
- if (ent && !hashcmp(ent->sha1, sha1)) {
+ if (ent && !oidcmp(&ent->oid, oid)) {
ent->ref++;
return ent;
}
@@ -1175,7 +1187,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_sha1_file(sha1, &type, &size);
+ data = read_sha1_file(oid->hash, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
@@ -1201,7 +1213,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
free(ent->tree_data);
nent = ent;
}
- hashcpy(nent->sha1, sha1);
+ oidcpy(&nent->oid, oid);
nent->tree_data = data;
nent->tree_size = size;
nent->ref = 1;
@@ -1246,7 +1258,7 @@ static void add_pbase_object(struct tree_desc *tree,
if (cmp < 0)
return;
if (name[cmplen] != '/') {
- add_object_entry(entry.oid->hash,
+ add_object_entry(entry.oid,
object_type(entry.mode),
fullname, 1);
return;
@@ -1257,7 +1269,7 @@ static void add_pbase_object(struct tree_desc *tree,
const char *down = name+cmplen+1;
int downlen = name_cmp_len(down);
- tree = pbase_tree_get(entry.oid->hash);
+ tree = pbase_tree_get(entry.oid);
if (!tree)
return;
init_tree_desc(&sub, tree->tree_data, tree->tree_size);
@@ -1276,7 +1288,7 @@ static int done_pbase_path_pos(unsigned hash)
int lo = 0;
int hi = done_pbase_paths_num;
while (lo < hi) {
- int mi = (hi + lo) / 2;
+ int mi = lo + (hi - lo) / 2;
if (done_pbase_paths[mi] == hash)
return mi;
if (done_pbase_paths[mi] < hash)
@@ -1316,7 +1328,7 @@ static void add_preferred_base_object(const char *name)
cmplen = name_cmp_len(name);
for (it = pbase_tree; it; it = it->next) {
if (cmplen == 0) {
- add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1);
+ add_object_entry(&it->pcache.oid, OBJ_TREE, NULL, 1);
}
else {
struct tree_desc tree;
@@ -1326,22 +1338,22 @@ static void add_preferred_base_object(const char *name)
}
}
-static void add_preferred_base(unsigned char *sha1)
+static void add_preferred_base(struct object_id *oid)
{
struct pbase_tree *it;
void *data;
unsigned long size;
- unsigned char tree_sha1[20];
+ struct object_id tree_oid;
if (window <= num_preferred_base++)
return;
- data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
+ data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash);
if (!data)
return;
for (it = pbase_tree; it; it = it->next) {
- if (!hashcmp(it->pcache.sha1, tree_sha1)) {
+ if (!oidcmp(&it->pcache.oid, &tree_oid)) {
free(data);
return;
}
@@ -1351,7 +1363,7 @@ static void add_preferred_base(unsigned char *sha1)
it->next = pbase_tree;
pbase_tree = it;
- hashcpy(it->pcache.sha1, tree_sha1);
+ oidcpy(&it->pcache.oid, &tree_oid);
it->pcache.tree_data = data;
it->pcache.tree_size = size;
}
@@ -2170,7 +2182,10 @@ static void *threaded_find_deltas(void *arg)
{
struct thread_params *me = arg;
+ progress_lock();
while (me->remaining) {
+ progress_unlock();
+
find_deltas(me->list, &me->remaining,
me->window, me->depth, me->processed);
@@ -2192,7 +2207,10 @@ static void *threaded_find_deltas(void *arg)
pthread_cond_wait(&me->cond, &me->mutex);
me->data_ready = 0;
pthread_mutex_unlock(&me->mutex);
+
+ progress_lock();
}
+ progress_unlock();
/* leave ->working 1 so that this doesn't get more work assigned */
return NULL;
}
@@ -2350,7 +2368,7 @@ static void add_tag_chain(const struct object_id *oid)
die("unable to pack objects reachable from tag %s",
oid_to_hex(oid));
- add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0);
+ add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
if (tag->tagged->type != OBJ_TAG)
return;
@@ -2364,7 +2382,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
struct object_id peeled;
if (starts_with(path, "refs/tags/") && /* is a tag? */
- !peel_ref(path, peeled.hash) && /* peelable? */
+ !peel_ref(path, &peeled) && /* peelable? */
packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */
add_tag_chain(oid);
return 0;
@@ -2498,8 +2516,9 @@ static int git_pack_config(const char *k, const char *v, void *cb)
static void read_object_list_from_stdin(void)
{
- char line[40 + 1 + PATH_MAX + 2];
- unsigned char sha1[20];
+ char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2];
+ struct object_id oid;
+ const char *p;
for (;;) {
if (!fgets(line, sizeof(line), stdin)) {
@@ -2513,17 +2532,17 @@ static void read_object_list_from_stdin(void)
continue;
}
if (line[0] == '-') {
- if (get_sha1_hex(line+1, sha1))
- die("expected edge sha1, got garbage:\n %s",
+ if (get_oid_hex(line+1, &oid))
+ die("expected edge object ID, got garbage:\n %s",
line);
- add_preferred_base(sha1);
+ add_preferred_base(&oid);
continue;
}
- if (get_sha1_hex(line, sha1))
- die("expected sha1, got garbage:\n %s", line);
+ if (parse_oid_hex(line, &oid, &p))
+ die("expected object ID, got garbage:\n %s", line);
- add_preferred_base_object(line+41);
- add_object_entry(sha1, 0, line+41, 0);
+ add_preferred_base_object(p + 1);
+ add_object_entry(&oid, 0, p + 1, 0);
}
}
@@ -2531,7 +2550,7 @@ static void read_object_list_from_stdin(void)
static void show_commit(struct commit *commit, void *data)
{
- add_object_entry(commit->object.oid.hash, OBJ_COMMIT, NULL, 0);
+ add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
commit->object.flags |= OBJECT_ADDED;
if (write_bitmap_index)
@@ -2541,13 +2560,49 @@ static void show_commit(struct commit *commit, void *data)
static void show_object(struct object *obj, const char *name, void *data)
{
add_preferred_base_object(name);
- add_object_entry(obj->oid.hash, obj->type, name, 0);
+ add_object_entry(&obj->oid, obj->type, name, 0);
obj->flags |= OBJECT_ADDED;
}
+static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
+{
+ assert(arg_missing_action == MA_ALLOW_ANY);
+
+ /*
+ * Quietly ignore ALL missing objects. This avoids problems with
+ * staging them now and getting an odd error later.
+ */
+ if (!has_object_file(&obj->oid))
+ return;
+
+ show_object(obj, name, data);
+}
+
+static int option_parse_missing_action(const struct option *opt,
+ const char *arg, int unset)
+{
+ assert(arg);
+ assert(!unset);
+
+ if (!strcmp(arg, "error")) {
+ arg_missing_action = MA_ERROR;
+ fn_show_object = show_object;
+ return 0;
+ }
+
+ if (!strcmp(arg, "allow-any")) {
+ arg_missing_action = MA_ALLOW_ANY;
+ fn_show_object = show_object__ma_allow_any;
+ return 0;
+ }
+
+ die(_("invalid value for --missing"));
+ return 0;
+}
+
static void show_edge(struct commit *commit)
{
- add_preferred_base(commit->object.oid.hash);
+ add_preferred_base(&commit->object.oid);
}
struct in_pack_object {
@@ -2556,8 +2611,8 @@ struct in_pack_object {
};
struct in_pack {
- int alloc;
- int nr;
+ unsigned int alloc;
+ unsigned int nr;
struct in_pack_object *array;
};
@@ -2594,7 +2649,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
memset(&in_pack, 0, sizeof(in_pack));
for (p = packed_git; p; p = p->next) {
- const unsigned char *sha1;
+ struct object_id oid;
struct object *o;
if (!p->pack_local || p->pack_keep)
@@ -2607,8 +2662,8 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
in_pack.alloc);
for (i = 0; i < p->num_objects; i++) {
- sha1 = nth_packed_object_sha1(p, i);
- o = lookup_unknown_object(sha1);
+ nth_packed_object_oid(&oid, p, i);
+ o = lookup_unknown_object(oid.hash);
if (!(o->flags & OBJECT_ADDED))
mark_in_pack_object(o, p, &in_pack);
o->flags |= OBJECT_ADDED;
@@ -2619,7 +2674,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
QSORT(in_pack.array, in_pack.nr, ofscmp);
for (i = 0; i < in_pack.nr; i++) {
struct object *o = in_pack.array[i].object;
- add_object_entry(o->oid.hash, o->type, "", 0);
+ add_object_entry(&o->oid, o->type, "", 0);
}
}
free(in_pack.array);
@@ -2635,7 +2690,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
return 0;
}
- add_object_entry(oid->hash, type, "", 0);
+ add_object_entry(oid, type, "", 0);
return 0;
}
@@ -2651,7 +2706,7 @@ static void add_unreachable_loose_objects(void)
NULL, NULL, NULL);
}
-static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
+static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
{
static struct packed_git *last_found = (void *)1;
struct packed_git *p;
@@ -2660,7 +2715,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
while (p) {
if ((!p->pack_local || p->pack_keep) &&
- find_pack_entry_one(sha1, p)) {
+ find_pack_entry_one(oid->hash, p)) {
last_found = p;
return 1;
}
@@ -2711,7 +2766,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
for (i = 0; i < p->num_objects; i++) {
nth_packed_object_oid(&oid, p, i);
if (!packlist_find(&to_pack, oid.hash, NULL) &&
- !has_sha1_pack_kept_or_nonlocal(oid.hash) &&
+ !has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime))
if (force_object_loose(oid.hash, p->mtime))
die("unable to force loose object");
@@ -2809,7 +2864,12 @@ static void get_object_list(int ac, const char **av)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(&revs, show_edge);
- traverse_commit_list(&revs, show_commit, show_object, NULL);
+
+ if (!fn_show_object)
+ fn_show_object = show_object;
+ traverse_commit_list_filtered(&filter_options, &revs,
+ show_commit, fn_show_object, NULL,
+ NULL);
if (unpack_unreachable_expiration) {
revs.ignore_missing_links = 1;
@@ -2945,6 +3005,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("use a bitmap index if available to speed up counting objects")),
OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
N_("write a bitmap index together with the pack index")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
+ N_("handling for missing objects"), PARSE_OPT_NONEG,
+ option_parse_missing_action },
OPT_END(),
};
@@ -3021,6 +3085,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
+ if (filter_options.choice) {
+ if (!pack_to_stdout)
+ die("cannot use --filter without --stdout.");
+ use_bitmap_index = 0;
+ }
+
/*
* "soft" reasons not to use bitmaps - for on-disk repack by default we want
*
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index cb1df1c..aaa8136 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -7,6 +7,7 @@
*/
#include "builtin.h"
+#include "packfile.h"
#define BLKSIZE 512
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index ac978ad..4192381 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "progress.h"
#include "parse-options.h"
+#include "packfile.h"
static const char * const prune_packed_usage[] = {
N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
@@ -37,8 +38,7 @@ static int prune_object(const struct object_id *oid, const char *path,
void prune_packed_objects(int opts)
{
if (opts & PRUNE_PACKED_VERBOSE)
- progress = start_progress_delay(_("Removing duplicate objects"),
- 256, 95, 2);
+ progress = start_delayed_progress(_("Removing duplicate objects"), 256);
for_each_loose_file_in_objdir(get_object_directory(),
prune_object, NULL, prune_subdir, &opts);
diff --git a/builtin/prune.c b/builtin/prune.c
index c378690..d2fdae6 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -8,7 +8,7 @@
#include "progress.h"
static const char * const prune_usage[] = {
- N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"),
+ N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"),
NULL
};
static int show_only;
@@ -138,7 +138,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
if (show_progress == -1)
show_progress = isatty(2);
if (show_progress)
- progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2);
+ progress = start_delayed_progress(_("Checking connectivity"), 0);
mark_reachable_objects(&revs, 1, expire, progress);
stop_progress(&progress);
diff --git a/builtin/pull.c b/builtin/pull.c
index 9b86e51..511dbbe 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -39,7 +39,7 @@ enum rebase_type {
static enum rebase_type parse_config_rebase(const char *key, const char *value,
int fatal)
{
- int v = git_config_maybe_bool("pull.rebase", value);
+ int v = git_parse_maybe_bool(value);
if (!v)
return REBASE_FALSE;
@@ -86,6 +86,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static enum rebase_type opt_rebase = -1;
static char *opt_diffstat;
static char *opt_log;
+static char *opt_signoff;
static char *opt_squash;
static char *opt_commit;
static char *opt_edit;
@@ -112,6 +113,8 @@ static char *opt_depth;
static char *opt_unshallow;
static char *opt_update_shallow;
static char *opt_refmap;
+static char *opt_ipv4;
+static char *opt_ipv6;
static struct option pull_options[] = {
/* Shared options */
@@ -142,6 +145,9 @@ static struct option pull_options[] = {
OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG),
+ OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
+ N_("add Signed-off-by:"),
+ PARSE_OPT_OPTARG),
OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
N_("create a single commit instead of doing a merge"),
PARSE_OPT_NOARG),
@@ -214,6 +220,12 @@ static struct option pull_options[] = {
OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"),
N_("specify fetch refmap"),
PARSE_OPT_NONEG),
+ OPT_PASSTHRU('4', "ipv4", &opt_ipv4, NULL,
+ N_("use IPv4 addresses only"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU('6', "ipv6", &opt_ipv6, NULL,
+ N_("use IPv6 addresses only"),
+ PARSE_OPT_NOARG),
OPT_END()
};
@@ -274,7 +286,7 @@ static const char *config_get_ff(void)
if (git_config_get_value("pull.ff", &value))
return NULL;
- switch (git_config_maybe_bool("pull.ff", value)) {
+ switch (git_parse_maybe_bool(value)) {
case 0:
return "--no-ff";
case 1:
@@ -325,6 +337,10 @@ static int git_pull_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "rebase.autostash")) {
config_autostash = git_config_bool(var, value);
return 0;
+ } else if (!strcmp(var, "submodule.recurse")) {
+ recurse_submodules = git_config_bool(var, value) ?
+ RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+ return 0;
}
return git_default_config(var, value, cb);
}
@@ -514,6 +530,10 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, opt_update_shallow);
if (opt_refmap)
argv_array_push(&args, opt_refmap);
+ if (opt_ipv4)
+ argv_array_push(&args, opt_ipv4);
+ if (opt_ipv6)
+ argv_array_push(&args, opt_ipv6);
if (repo) {
argv_array_push(&args, repo);
@@ -537,10 +557,10 @@ static int pull_into_void(const struct object_id *merge_head,
* index/worktree changes that the user already made on the unborn
* branch.
*/
- if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
+ if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
return 1;
- if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
+ if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
@@ -590,6 +610,8 @@ static int run_merge(void)
argv_array_push(&args, opt_diffstat);
if (opt_log)
argv_array_push(&args, opt_log);
+ if (opt_signoff)
+ argv_array_push(&args, opt_signoff);
if (opt_squash)
argv_array_push(&args, opt_squash);
if (opt_commit)
@@ -741,12 +763,15 @@ static int get_octopus_merge_base(struct object_id *merge_base,
if (!is_null_oid(fork_point))
commit_list_insert(lookup_commit_reference(fork_point), &revs);
- result = reduce_heads(get_octopus_merge_bases(revs));
+ result = get_octopus_merge_bases(revs);
free_commit_list(revs);
+ reduce_heads_replace(&result);
+
if (!result)
return 1;
oidcpy(merge_base, &result->item->object.oid);
+ free_commit_list(result);
return 0;
}
@@ -815,6 +840,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
+ git_config(git_pull_config, NULL);
+
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
parse_repo_refspecs(argc, argv, &repo, &refspecs);
@@ -825,8 +852,6 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_rebase < 0)
opt_rebase = config_get_rebase();
- git_config(git_pull_config, NULL);
-
if (read_cache_unmerged())
die_resolve_conflict("pull");
diff --git a/builtin/push.c b/builtin/push.c
index 03846e8..1c28427 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -32,6 +32,8 @@ static const char **refspec;
static int refspec_nr;
static int refspec_alloc;
+static struct string_list push_options_config = STRING_LIST_INIT_DUP;
+
static void add_refspec(const char *ref)
{
refspec_nr++;
@@ -481,7 +483,7 @@ static int git_push_config(const char *k, const char *v, void *cb)
} else if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_config_maybe_bool("push.gpgsign", value)) {
+ switch (git_parse_maybe_bool(value)) {
case 0:
set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
break;
@@ -503,6 +505,15 @@ static int git_push_config(const char *k, const char *v, void *cb)
int val = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
recurse_submodules = val;
+ } else if (!strcmp(k, "push.pushoption")) {
+ if (!v)
+ return config_error_nonbool(k);
+ else
+ if (!*v)
+ string_list_clear(&push_options_config, 0);
+ else
+ string_list_append(&push_options_config, v);
+ return 0;
}
return git_default_config(k, v, NULL);
@@ -515,7 +526,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
int push_cert = -1;
int rc;
const char *repo = NULL; /* default repository */
- struct string_list push_options = STRING_LIST_INIT_DUP;
+ struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
+ struct string_list *push_options;
const struct string_list_item *item;
struct option options[] = {
@@ -551,7 +563,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
- OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
+ OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@@ -562,6 +574,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
packet_trace_identity("push");
git_config(git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
+ push_options = (push_options_cmdline.nr
+ ? &push_options_cmdline
+ : &push_options_config);
set_push_cert_flags(&flags, push_cert);
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
@@ -584,12 +599,13 @@ int cmd_push(int argc, const char **argv, const char *prefix)
set_refspecs(argv + 1, argc - 1, repo);
}
- for_each_string_list_item(item, &push_options)
+ for_each_string_list_item(item, push_options)
if (strchr(item->string, '\n'))
die(_("push options must not have new line characters"));
- rc = do_push(repo, flags, &push_options);
- string_list_clear(&push_options, 0);
+ rc = do_push(repo, flags, push_options);
+ string_list_clear(&push_options_cmdline, 0);
+ string_list_clear(&push_options_config, 0);
if (rc == -1)
usage_with_options(push_usage, options);
else
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index d5f618d..bf87a27 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -164,8 +164,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
argc = parse_options(argc, argv, unused_prefix, read_tree_options,
read_tree_usage, 0);
- load_submodule_cache();
-
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
prefix_set = opts.prefix ? 1 : 0;
diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c
index c82b4dc..7daee54 100644
--- a/builtin/rebase--helper.c
+++ b/builtin/rebase--helper.c
@@ -12,19 +12,39 @@ static const char * const builtin_rebase_helper_usage[] = {
int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
{
struct replay_opts opts = REPLAY_OPTS_INIT;
+ unsigned flags = 0, keep_empty = 0;
+ int abbreviate_commands = 0;
enum {
- CONTINUE = 1, ABORT
+ CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,
+ CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,
+ ADD_EXEC
} command = 0;
struct option options[] = {
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
+ OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
CONTINUE),
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
ABORT),
+ OPT_CMDMODE(0, "make-script", &command,
+ N_("make rebase script"), MAKE_SCRIPT),
+ OPT_CMDMODE(0, "shorten-ids", &command,
+ N_("shorten commit ids in the todo list"), SHORTEN_OIDS),
+ OPT_CMDMODE(0, "expand-ids", &command,
+ N_("expand commit ids in the todo list"), EXPAND_OIDS),
+ OPT_CMDMODE(0, "check-todo-list", &command,
+ N_("check the todo list"), CHECK_TODO_LIST),
+ OPT_CMDMODE(0, "skip-unnecessary-picks", &command,
+ N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS),
+ OPT_CMDMODE(0, "rearrange-squash", &command,
+ N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
+ OPT_CMDMODE(0, "add-exec-commands", &command,
+ N_("insert exec commands in todo list"), ADD_EXEC),
OPT_END()
};
git_config(git_default_config, NULL);
+ git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
opts.action = REPLAY_INTERACTIVE_REBASE;
opts.allow_ff = 1;
@@ -33,9 +53,25 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, NULL, options,
builtin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);
+ flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
+ flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
+ flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
+
if (command == CONTINUE && argc == 1)
return !!sequencer_continue(&opts);
if (command == ABORT && argc == 1)
return !!sequencer_remove_state(&opts);
+ if (command == MAKE_SCRIPT && argc > 1)
+ return !!sequencer_make_script(stdout, argc, argv, flags);
+ if ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)
+ return !!transform_todos(flags);
+ if (command == CHECK_TODO_LIST && argc == 1)
+ return !!check_todo_list();
+ if (command == SKIP_UNNECESSARY_PICKS && argc == 1)
+ return !!skip_unnecessary_picks();
+ if (command == REARRANGE_SQUASH && argc == 1)
+ return !!rearrange_squash();
+ if (command == ADD_EXEC && argc == 2)
+ return !!sequencer_add_exec_commands(argv[1]);
usage_with_options(builtin_rebase_helper_usage, options);
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index cabdc55..b7ce7c7 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -23,6 +23,8 @@
#include "fsck.h"
#include "tmp-objdir.h"
#include "oidset.h"
+#include "packfile.h"
+#include "protocol.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -742,7 +744,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
size_t n;
if (feed(feed_state, &buf, &n))
break;
- if (write_in_full(proc.in, buf, n) != n)
+ if (write_in_full(proc.in, buf, n) < 0)
break;
}
close(proc.in);
@@ -869,7 +871,7 @@ static void refuse_unconfigured_deny_delete_current(void)
rp_error("%s", _(refuse_unconfigured_deny_delete_current_msg));
}
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]);
+static int command_singleton_iterator(void *cb_data, struct object_id *oid);
static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
{
static struct lock_file shallow_lock;
@@ -919,9 +921,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
*/
static int head_has_history(void)
{
- unsigned char sha1[20];
+ struct object_id oid;
- return !get_sha1("HEAD", sha1);
+ return !get_oid("HEAD", &oid);
}
static const char *push_to_deploy(unsigned char *sha1,
@@ -1138,7 +1140,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (ref_transaction_delete(transaction,
namespaced_name,
- old_oid->hash,
+ old_oid,
0, "push", &err)) {
rp_error("%s", err.buf);
strbuf_release(&err);
@@ -1155,7 +1157,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (ref_transaction_update(transaction,
namespaced_name,
- new_oid->hash, old_oid->hash,
+ new_oid, old_oid,
0, "push",
&err)) {
rp_error("%s", err.buf);
@@ -1206,11 +1208,10 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
const char *dst_name;
struct string_list_item *item;
struct command *dst_cmd;
- unsigned char sha1[GIT_MAX_RAWSZ];
int flag;
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
- dst_name = resolve_ref_unsafe(buf.buf, 0, sha1, &flag);
+ dst_name = resolve_ref_unsafe(buf.buf, 0, NULL, &flag);
strbuf_release(&buf);
if (!(flag & REF_ISSYMREF))
@@ -1270,7 +1271,7 @@ static void check_aliased_updates(struct command *commands)
string_list_clear(&ref_list, 0);
}
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
+static int command_singleton_iterator(void *cb_data, struct object_id *oid)
{
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
@@ -1278,7 +1279,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
if (!cmd || is_null_oid(&cmd->new_oid))
return -1; /* end of list */
*cmd_list = NULL; /* this returns only one */
- hashcpy(sha1, cmd->new_oid.hash);
+ oidcpy(oid, &cmd->new_oid);
return 0;
}
@@ -1309,7 +1310,7 @@ struct iterate_data {
struct shallow_info *si;
};
-static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
+static int iterate_receive_command_list(void *cb_data, struct object_id *oid)
{
struct iterate_data *data = cb_data;
struct command **cmd_list = &data->cmds;
@@ -1320,7 +1321,7 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
/* to be checked in update_shallow_ref() */
continue;
if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) {
- hashcpy(sha1, cmd->new_oid.hash);
+ oidcpy(oid, &cmd->new_oid);
*cmd_list = cmd->next;
return 0;
}
@@ -1458,7 +1459,6 @@ static void execute_commands(struct command *commands,
{
struct check_connected_options opt = CHECK_CONNECTED_INIT;
struct command *cmd;
- struct object_id oid;
struct iterate_data data;
struct async muxer;
int err_fd = 0;
@@ -1515,7 +1515,7 @@ static void execute_commands(struct command *commands,
check_aliased_updates(commands);
free(head_name_to_free);
- head_name = head_name_to_free = resolve_refdup("HEAD", 0, oid.hash, NULL);
+ head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
if (use_atomic)
execute_commands_atomic(commands, si);
@@ -1962,6 +1962,22 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
+ switch (determine_protocol_version_server()) {
+ case protocol_v1:
+ /*
+ * v1 is just the original protocol with a version string,
+ * so just fall through after writing the version string.
+ */
+ if (advertise_refs || !stateless_rpc)
+ packet_write_fmt(1, "version 1\n");
+
+ /* fallthrough */
+ case protocol_v0:
+ break;
+ case protocol_unknown_version:
+ BUG("unknown protocol version");
+ }
+
if (advertise_refs || !stateless_rpc) {
write_head_info();
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index e237d92..2233725 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -42,7 +42,7 @@ struct expire_reflog_policy_cb {
};
struct collected_reflog {
- unsigned char sha1[20];
+ struct object_id oid;
char reflog[FLEX_ARRAY];
};
@@ -126,7 +126,7 @@ static int commit_is_complete(struct commit *commit)
struct commit *c;
struct commit_list *parent;
- c = (struct commit *)study.objects[--study.nr].item;
+ c = (struct commit *)object_array_pop(&study);
if (!c->object.parsed && !parse_object(&c->object.oid))
c->object.flags |= INCOMPLETE;
@@ -182,8 +182,8 @@ static int commit_is_complete(struct commit *commit)
found.objects[i].item->flags |= SEEN;
}
/* free object arrays */
- free(study.objects);
- free(found.objects);
+ object_array_clear(&study);
+ object_array_clear(&found);
return !is_incomplete;
}
@@ -385,7 +385,7 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
struct collect_reflog_cb *cb = cb_data;
FLEX_ALLOC_STR(e, reflog, ref);
- hashcpy(e->sha1, oid->hash);
+ oidcpy(&e->oid, oid);
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
cb->e[cb->nr++] = e;
return 0;
@@ -416,16 +416,6 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
return ent;
}
-static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)
-{
- if (!value)
- return config_error_nonbool(var);
- if (parse_expiry_date(value, expire))
- return error(_("'%s' for '%s' is not a valid timestamp"),
- value, var);
- return 0;
-}
-
/* expiry timer slot */
#define EXPIRE_TOTAL 01
#define EXPIRE_UNREACH 02
@@ -443,11 +433,11 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
if (!strcmp(key, "reflogexpire")) {
slot = EXPIRE_TOTAL;
- if (parse_expire_cfg_value(var, value, &expire))
+ if (git_config_expiry_date(&expire, var, value))
return -1;
} else if (!strcmp(key, "reflogexpireunreachable")) {
slot = EXPIRE_UNREACH;
- if (parse_expire_cfg_value(var, value, &expire))
+ if (git_config_expiry_date(&expire, var, value))
return -1;
} else
return git_default_config(var, value, cb);
@@ -589,7 +579,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
- status |= reflog_expire(e->reflog, e->sha1, flags,
+ status |= reflog_expire(e->reflog, &e->oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
@@ -601,13 +591,13 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
for (; i < argc; i++) {
char *ref;
- unsigned char sha1[20];
- if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) {
+ struct object_id oid;
+ if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
status |= error("%s points nowhere!", argv[i]);
continue;
}
set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
- status |= reflog_expire(ref, sha1, flags,
+ status |= reflog_expire(ref, &oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
@@ -659,7 +649,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
for ( ; i < argc; i++) {
const char *spec = strstr(argv[i], "@{");
- unsigned char sha1[20];
+ struct object_id oid;
char *ep, *ref;
int recno;
@@ -668,7 +658,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
continue;
}
- if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+ if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
status |= error("no reflog for '%s'", argv[i]);
continue;
}
@@ -683,7 +673,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
cb.cmd.expire_total = 0;
}
- status |= reflog_expire(ref, sha1, flags,
+ status |= reflog_expire(ref, &oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index bfb21ba..6a9127a 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -57,7 +57,7 @@ static char *strip_escapes(const char *str, const char *service,
special = str[rpos];
if (rpos == 1)
break;
- /* Fall-through to error. */
+ /* fallthrough */
default:
die("Bad remote-ext placeholder '%%%c'.",
str[rpos]);
diff --git a/builtin/remote.c b/builtin/remote.c
index 6273c0c..d95bf90 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -301,7 +301,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)
}
string_list_append(&info->merge, xstrdup(value));
} else {
- int v = git_config_maybe_bool(orig_key, value);
+ int v = git_parse_maybe_bool(value);
if (v >= 0)
info->rebase = v;
else if (!strcmp(value, "preserve"))
@@ -558,19 +558,19 @@ static int read_remote_branches(const char *refname,
struct strbuf buf = STRBUF_INIT;
struct string_list_item *item;
int flag;
- 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_oid.hash, &flag);
- if (flag & REF_ISSYMREF)
+ NULL, &flag);
+ if (symref && (flag & REF_ISSYMREF))
item->util = xstrdup(symref);
else
item->util = NULL;
}
+ strbuf_release(&buf);
return 0;
}
@@ -595,6 +595,7 @@ static int migrate_file(struct remote *remote)
unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES)
unlink_or_warn(git_path("branches/%s", remote->name));
+ strbuf_release(&buf);
return 0;
}
@@ -689,10 +690,10 @@ static int mv(int argc, const char **argv)
int flag = 0;
struct object_id oid;
- read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
+ read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
if (!(flag & REF_ISSYMREF))
continue;
- if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
+ if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);
}
for (i = 0; i < remote_branches.nr; i++) {
@@ -787,7 +788,7 @@ static int rm(int argc, const char **argv)
strbuf_release(&buf);
if (!result)
- result = delete_refs("remote: remove", &branches, REF_NODEREF);
+ result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
string_list_clear(&branches, 0);
if (skipped.nr) {
@@ -1254,7 +1255,7 @@ static int set_head(int argc, const char **argv)
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (delete_ref(NULL, buf.buf, NULL, REF_NODEREF))
+ if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
result |= error(_("Could not delete %s"), buf.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
@@ -1563,9 +1564,7 @@ static int set_url(int argc, const char **argv)
"^$", 0);
else
git_config_set(name_buf.buf, newurl);
- strbuf_release(&name_buf);
-
- return 0;
+ goto out;
}
/* Old URL specified. Demand that one matches. */
@@ -1588,6 +1587,8 @@ static int set_url(int argc, const char **argv)
git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
else
git_config_set_multivar(name_buf.buf, NULL, oldurl, 1);
+out:
+ strbuf_release(&name_buf);
return 0;
}
diff --git a/builtin/replace.c b/builtin/replace.c
index fba336a..10078ae 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -50,7 +50,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
struct object_id object;
enum object_type obj_type, repl_type;
- if (get_sha1(refname, object.hash))
+ if (get_oid(refname, &object))
return error("Failed to resolve '%s' as a valid ref.", refname);
obj_type = sha1_object_info(object.hash, NULL);
@@ -113,7 +113,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
strbuf_addstr(&ref, oid_to_hex(&oid));
full_hex = ref.buf + base_len;
- if (read_ref(ref.buf, oid.hash)) {
+ if (read_ref(ref.buf, &oid)) {
error("replace ref '%s' not found.", full_hex);
had_error = 1;
continue;
@@ -128,7 +128,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
static int delete_replace_ref(const char *name, const char *ref,
const struct object_id *oid)
{
- if (delete_ref(NULL, ref, oid->hash, 0))
+ if (delete_ref(NULL, ref, oid, 0))
return 1;
printf("Deleted replace ref '%s'\n", name);
return 0;
@@ -144,7 +144,7 @@ static void check_ref_valid(struct object_id *object,
if (check_refname_format(ref->buf, 0))
die("'%s' is not a valid ref name.", ref->buf);
- if (read_ref(ref->buf, prev->hash))
+ if (read_ref(ref->buf, prev))
oidclr(prev);
else if (!force)
die("replace ref '%s' already exists", ref->buf);
@@ -175,7 +175,7 @@ static int replace_object_oid(const char *object_ref,
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash,
+ ref_transaction_update(transaction, ref.buf, repl, &prev,
0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
@@ -269,7 +269,7 @@ static void import_object(struct object_id *oid, enum object_type type,
if (fstat(fd, &st) < 0)
die_errno("unable to fstat %s", filename);
- if (index_fd(oid->hash, fd, &st, type, NULL, flags) < 0)
+ if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
die("unable to write object to database");
/* index_fd close()s fd for us */
}
@@ -365,7 +365,7 @@ static void check_one_mergetag(struct commit *commit,
/* iterate over new parents */
for (i = 1; i < mergetag_data->argc; i++) {
struct object_id oid;
- if (get_sha1(mergetag_data->argv[i], oid.hash) < 0)
+ if (get_oid(mergetag_data->argv[i], &oid) < 0)
die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]);
if (!oidcmp(&tag->tagged->oid, &oid))
return; /* found */
diff --git a/builtin/rerere.c b/builtin/rerere.c
index ffb66e2..0bc4029 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -18,7 +18,7 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
{
int i;
for (i = 0; i < nbuf; i++)
- if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
+ if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
return -1;
return 0;
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 7aeaea2..e15f595 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -12,7 +12,7 @@
#include "lockfile.h"
#include "tag.h"
#include "object.h"
-#include "commit.h"
+#include "pretty.h"
#include "run-command.h"
#include "refs.h"
#include "diff.h"
@@ -44,10 +44,11 @@ static inline int is_merge(void)
static int reset_index(const struct object_id *oid, int reset_type, int quiet)
{
- int nr = 1;
+ int i, nr = 0;
struct tree_desc desc[2];
struct tree *tree;
struct unpack_trees_options opts;
+ int ret = -1;
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
@@ -75,23 +76,32 @@ static int reset_index(const struct object_id *oid, int reset_type, int quiet)
struct object_id head_oid;
if (get_oid("HEAD", &head_oid))
return error(_("You do not have a valid HEAD."));
- if (!fill_tree_descriptor(desc, head_oid.hash))
+ if (!fill_tree_descriptor(desc + nr, &head_oid))
return error(_("Failed to find tree of HEAD."));
nr++;
opts.fn = twoway_merge;
}
- if (!fill_tree_descriptor(desc + nr - 1, oid->hash))
- return error(_("Failed to find tree of %s."), oid_to_hex(oid));
+ if (!fill_tree_descriptor(desc + nr, oid)) {
+ error(_("Failed to find tree of %s."), oid_to_hex(oid));
+ goto out;
+ }
+ nr++;
+
if (unpack_trees(nr, desc, &opts))
- return -1;
+ goto out;
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
prime_cache_tree(&the_index, tree);
}
- return 0;
+ ret = 0;
+
+out:
+ for (i = 0; i < nr; i++)
+ free((void *)desc[i].buffer);
+ return ret;
}
static void print_new_head_line(struct commit *commit)
@@ -156,6 +166,7 @@ static int read_from_tree(const struct pathspec *pathspec,
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
opt.format_callback_data = &intent_to_add;
+ opt.flags.override_submodule_config = 1;
if (do_diff_cache(tree_oid, &opt))
return 1;
@@ -219,8 +230,8 @@ static void parse_args(struct pathspec *pathspec,
* has to be unambiguous. If there is a single argument, it
* can not be a tree
*/
- else if ((!argv[1] && !get_sha1_committish(argv[0], unused.hash)) ||
- (argv[1] && !get_sha1_treeish(argv[0], unused.hash))) {
+ else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
+ (argv[1] && !get_oid_treeish(argv[0], &unused))) {
/*
* Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
@@ -255,12 +266,12 @@ static int reset_refs(const char *rev, const struct object_id *oid)
if (!get_oid("HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
- update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
+ update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref(NULL, "ORIG_HEAD", old_orig->hash, 0);
+ delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
set_reflog_message(&msg, "updating HEAD", rev);
- update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0,
+ update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0,
UPDATE_REFS_MSG_ON_ERR);
strbuf_release(&msg);
return update_ref_status;
@@ -308,15 +319,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH);
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
- load_submodule_cache();
-
- unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
+ unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
} else if (!pathspec.nr) {
struct commit *commit;
- if (get_sha1_committish(rev, oid.hash))
+ if (get_oid_committish(rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
commit = lookup_commit_reference(&oid);
if (!commit)
@@ -324,7 +333,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
oidcpy(&oid, &commit->object.oid);
} else {
struct tree *tree;
- if (get_sha1_treeish(rev, oid.hash))
+ if (get_oid_treeish(rev, &oid))
die(_("Failed to resolve '%s' as a valid tree."), rev);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -368,8 +377,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die_if_unmerged_cache(reset_type);
if (reset_type != SOFT) {
- struct lock_file *lock = xcalloc(1, sizeof(*lock));
- hold_locked_index(lock, LOCK_DIE_ON_ERROR);
+ struct lock_file lock = LOCK_INIT;
+ hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
if (read_from_tree(&pathspec, &oid, intent_to_add))
@@ -385,7 +394,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("Could not reset index file to revision '%s'."), rev);
}
- if (write_locked_index(&the_index, lock, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
die(_("Could not write new index file."));
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 95b4128..d5345b6 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -4,6 +4,8 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
+#include "list-objects-filter.h"
+#include "list-objects-filter-options.h"
#include "pack.h"
#include "pack-bitmap.h"
#include "builtin.h"
@@ -12,6 +14,7 @@
#include "bisect.h"
#include "progress.h"
#include "reflog-walk.h"
+#include "oidset.h"
static const char rev_list_usage[] =
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -55,6 +58,20 @@ static const char rev_list_usage[] =
static struct progress *progress;
static unsigned progress_counter;
+static struct list_objects_filter_options filter_options;
+static struct oidset omitted_objects;
+static int arg_print_omitted; /* print objects omitted by filter */
+
+static struct oidset missing_objects;
+enum missing_action {
+ MA_ERROR = 0, /* fail if any missing objects are encountered */
+ MA_ALLOW_ANY, /* silently allow ALL missing objects */
+ MA_PRINT, /* print ALL missing objects in special section */
+};
+static enum missing_action arg_missing_action;
+
+#define DEFAULT_OIDSET_SIZE (16*1024)
+
static void finish_commit(struct commit *commit, void *data);
static void show_commit(struct commit *commit, void *data)
{
@@ -178,11 +195,31 @@ static void finish_commit(struct commit *commit, void *data)
free_commit_buffer(commit);
}
+static inline void finish_object__ma(struct object *obj)
+{
+ switch (arg_missing_action) {
+ case MA_ERROR:
+ die("missing blob object '%s'", oid_to_hex(&obj->oid));
+ return;
+
+ case MA_ALLOW_ANY:
+ return;
+
+ case MA_PRINT:
+ oidset_insert(&missing_objects, &obj->oid);
+ return;
+
+ default:
+ BUG("unhandled missing_action");
+ return;
+ }
+}
+
static void finish_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
- die("missing blob object '%s'", oid_to_hex(&obj->oid));
+ finish_object__ma(obj);
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
parse_object(&obj->oid);
}
@@ -258,17 +295,37 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
}
static int show_object_fast(
- const unsigned char *sha1,
+ const struct object_id *oid,
enum object_type type,
int exclude,
uint32_t name_hash,
struct packed_git *found_pack,
off_t found_offset)
{
- fprintf(stdout, "%s\n", sha1_to_hex(sha1));
+ fprintf(stdout, "%s\n", oid_to_hex(oid));
return 1;
}
+static inline int parse_missing_action_value(const char *value)
+{
+ if (!strcmp(value, "error")) {
+ arg_missing_action = MA_ERROR;
+ return 1;
+ }
+
+ if (!strcmp(value, "allow-any")) {
+ arg_missing_action = MA_ALLOW_ANY;
+ return 1;
+ }
+
+ if (!strcmp(value, "print")) {
+ arg_missing_action = MA_PRINT;
+ return 1;
+ }
+
+ return 0;
+}
+
int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -294,7 +351,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.bisect)
bisect_list = 1;
- if (DIFF_OPT_TST(&revs.diffopt, QUICK))
+ if (revs.diffopt.flags.quick)
info.flags |= REV_LIST_QUIET;
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];
@@ -335,6 +392,30 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
show_progress = arg;
continue;
}
+
+ if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
+ parse_list_objects_filter(&filter_options, arg);
+ if (filter_options.choice && !revs.blob_objects)
+ die(_("object filtering requires --objects"));
+ if (filter_options.choice == LOFC_SPARSE_OID &&
+ !filter_options.sparse_oid_value)
+ die(_("invalid sparse value '%s'"),
+ filter_options.filter_spec);
+ continue;
+ }
+ if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
+ list_objects_filter_release(&filter_options);
+ continue;
+ }
+ if (!strcmp(arg, "--filter-print-omitted")) {
+ arg_print_omitted = 1;
+ continue;
+ }
+
+ if (skip_prefix(arg, "--missing=", &arg) &&
+ parse_missing_action_value(arg))
+ continue;
+
usage(rev_list_usage);
}
@@ -360,6 +441,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.show_notes)
die(_("rev-list does not support display of notes"));
+ if (filter_options.choice && use_bitmap_index)
+ die(_("cannot combine --use-bitmap-index with object filtering"));
+
save_commit_buffer = (revs.verbose_header ||
revs.grep_filter.pattern_list ||
revs.grep_filter.header_list);
@@ -367,7 +451,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
revs.limited = 1;
if (show_progress)
- progress = start_progress_delay(show_progress, 0, 0, 2);
+ progress = start_delayed_progress(show_progress, 0);
if (use_bitmap_index && !revs.prune) {
if (revs.count && !revs.left_right && !revs.cherry_mark) {
@@ -397,14 +481,37 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (bisect_list) {
int reaches = reaches, all = all;
- revs.commits = find_bisection(revs.commits, &reaches, &all,
- bisect_find_all);
+ find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
if (bisect_show_vars)
return show_bisect_vars(&info, reaches, all);
}
- traverse_commit_list(&revs, show_commit, show_object, &info);
+ if (arg_print_omitted)
+ oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
+ if (arg_missing_action == MA_PRINT)
+ oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+
+ traverse_commit_list_filtered(
+ &filter_options, &revs, show_commit, show_object, &info,
+ (arg_print_omitted ? &omitted_objects : NULL));
+
+ if (arg_print_omitted) {
+ struct oidset_iter iter;
+ struct object_id *oid;
+ oidset_iter_init(&omitted_objects, &iter);
+ while ((oid = oidset_iter_next(&iter)))
+ printf("~%s\n", oid_to_hex(oid));
+ oidset_clear(&omitted_objects);
+ }
+ if (arg_missing_action == MA_PRINT) {
+ struct oidset_iter iter;
+ struct object_id *oid;
+ oidset_iter_init(&missing_objects, &iter);
+ while ((oid = oidset_iter_next(&iter)))
+ printf("?%s\n", oid_to_hex(oid));
+ oidset_clear(&missing_objects);
+ }
stop_progress(&progress);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c78b7b3..74aa644 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -133,7 +133,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), discard.hash, &full)) {
+ switch (dwim_ref(name, strlen(name), &discard, &full)) {
case 0:
/*
* Not found -- not a ref. We could
@@ -274,7 +274,7 @@ static int try_difference(const char *arg)
return 0;
}
- if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) {
+ if (!get_oid_committish(this, &oid) && !get_oid_committish(next, &end)) {
show_rev(NORMAL, &end, next);
show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
if (symmetric) {
@@ -328,7 +328,7 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_sha1_committish(arg, oid.hash)) {
+ if (get_oid_committish(arg, &oid)) {
*dotdot = '^';
return 0;
}
@@ -387,6 +387,14 @@ static const char *skipspaces(const char *s)
return s;
}
+static char *findspace(const char *s)
+{
+ for (; *s; s++)
+ if (isspace(*s))
+ return (char*)s;
+ return NULL;
+}
+
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
static int keep_dashdash = 0, stop_at_non_option = 0;
@@ -434,7 +442,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
while (strbuf_getline(&sb, stdin) != EOF) {
const char *s;
- const char *help;
+ char *help;
struct option *o;
if (!sb.len)
@@ -444,15 +452,17 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
memset(opts + onb, 0, sizeof(opts[onb]));
o = &opts[onb++];
- help = strchr(sb.buf, ' ');
- if (!help || *sb.buf == ' ') {
+ help = findspace(sb.buf);
+ if (!help || sb.buf == help) {
o->type = OPTION_GROUP;
o->help = xstrdup(skipspaces(sb.buf));
continue;
}
+ *help = '\0';
+
o->type = OPTION_CALLBACK;
- o->help = xstrdup(skipspaces(help));
+ o->help = xstrdup(skipspaces(help+1));
o->value = &parsed;
o->flags = PARSE_OPT_NOARG;
o->callback = &parseopt_dump;
@@ -702,7 +712,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
quiet = 1;
- flags |= GET_SHA1_QUIETLY;
+ flags |= GET_OID_QUIETLY;
continue;
}
if (opt_with_value(arg, "--short", &arg)) {
@@ -757,8 +767,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--bisect")) {
- for_each_ref_in("refs/bisect/bad", show_reference, NULL);
- for_each_ref_in("refs/bisect/good", anti_reference, NULL);
+ for_each_fullref_in("refs/bisect/bad", show_reference, NULL, 0);
+ for_each_fullref_in("refs/bisect/good", anti_reference, NULL, 0);
continue;
}
if (opt_with_value(arg, "--branches", &arg)) {
@@ -868,6 +878,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
+ if (!strcmp(arg, "--is-shallow-repository")) {
+ printf("%s\n", is_repository_shallow() ? "true"
+ : "false");
+ continue;
+ }
if (!strcmp(arg, "--shared-index-path")) {
if (read_cache() < 0)
die(_("Could not read the index"));
@@ -911,7 +926,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
name++;
type = REVERSED;
}
- if (!get_sha1_with_context(name, flags, oid.hash, &unused)) {
+ if (!get_oid_with_context(name, flags, &oid, &unused)) {
if (verify)
revs_count++;
else
diff --git a/builtin/rm.c b/builtin/rm.c
index 52826d1..4a2fcca 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -255,7 +255,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
struct pathspec pathspec;
char *seen;
- gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_rm_options,
@@ -286,7 +285,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
- !is_staging_gitmodules_ok())
+ !is_staging_gitmodules_ok(&the_index))
die (_("Please stage your changes to .gitmodules or stash them to proceed"));
}
@@ -383,7 +382,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}
strbuf_release(&buf);
if (gitmodules_modified)
- stage_updated_gitmodules();
+ stage_updated_gitmodules(&the_index);
}
if (active_cache_changed) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 633e0c3..fc4f0bb 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -105,7 +105,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_config_maybe_bool("push.gpgsign", value)) {
+ switch (git_parse_maybe_bool(value)) {
case 0:
args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
break;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 43c4799..e29875b 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -52,26 +52,8 @@ static void insert_one_record(struct shortlog *log,
const char *oneline)
{
struct string_list_item *item;
- const char *mailbuf, *namebuf;
- size_t namelen, maillen;
- struct strbuf namemailbuf = STRBUF_INIT;
- struct ident_split ident;
- if (split_ident_line(&ident, author, strlen(author)))
- return;
-
- namebuf = ident.name_begin;
- mailbuf = ident.mail_begin;
- namelen = ident.name_end - ident.name_begin;
- maillen = ident.mail_end - ident.mail_begin;
-
- map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
- strbuf_add(&namemailbuf, namebuf, namelen);
-
- if (log->email)
- strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf);
-
- item = string_list_insert(&log->list, namemailbuf.buf);
+ item = string_list_insert(&log->list, author);
if (log->summary)
item->util = (void *)(UTIL_TO_INT(item) + 1);
@@ -114,9 +96,33 @@ static void insert_one_record(struct shortlog *log,
}
}
+static int parse_stdin_author(struct shortlog *log,
+ struct strbuf *out, const char *in)
+{
+ const char *mailbuf, *namebuf;
+ size_t namelen, maillen;
+ struct ident_split ident;
+
+ if (split_ident_line(&ident, in, strlen(in)))
+ return -1;
+
+ namebuf = ident.name_begin;
+ mailbuf = ident.mail_begin;
+ namelen = ident.name_end - ident.name_begin;
+ maillen = ident.mail_end - ident.mail_begin;
+
+ map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
+ strbuf_add(out, namebuf, namelen);
+ if (log->email)
+ strbuf_addf(out, " <%.*s>", (int)maillen, mailbuf);
+
+ return 0;
+}
+
static void read_from_stdin(struct shortlog *log)
{
struct strbuf author = STRBUF_INIT;
+ struct strbuf mapped_author = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
static const char *author_match[2] = { "Author: ", "author " };
static const char *committer_match[2] = { "Commit: ", "committer " };
@@ -134,9 +140,15 @@ static void read_from_stdin(struct shortlog *log)
while (strbuf_getline_lf(&oneline, stdin) != EOF &&
!oneline.len)
; /* discard blanks */
- insert_one_record(log, v, oneline.buf);
+
+ strbuf_reset(&mapped_author);
+ if (parse_stdin_author(log, &mapped_author, v) < 0)
+ continue;
+
+ insert_one_record(log, mapped_author.buf, oneline.buf);
}
strbuf_release(&author);
+ strbuf_release(&mapped_author);
strbuf_release(&oneline);
}
@@ -153,7 +165,9 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.date_mode.type = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
- fmt = log->committer ? "%cn <%ce>" : "%an <%ae>";
+ fmt = log->committer ?
+ (log->email ? "%cN <%cE>" : "%cN") :
+ (log->email ? "%aN <%aE>" : "%aN");
format_commit_message(commit, fmt, &author, &ctx);
if (!log->summary) {
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 28f245c..e8a4aa4 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -1,6 +1,6 @@
#include "cache.h"
#include "config.h"
-#include "commit.h"
+#include "pretty.h"
#include "refs.h"
#include "builtin.h"
#include "color.h"
@@ -393,7 +393,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+ if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -408,7 +408,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+ if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -514,7 +514,7 @@ static int show_independent(struct commit **rev,
static void append_one_rev(const char *av)
{
struct object_id revkey;
- if (!get_sha1(av, revkey.hash)) {
+ if (!get_oid(av, &revkey)) {
append_ref(av, &revkey, 0);
return;
}
@@ -554,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ return git_color_default_config(var, value, cb);
}
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -705,8 +705,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
static const char *fake_av[2];
fake_av[0] = resolve_refdup("HEAD",
- RESOLVE_REF_READING,
- oid.hash, NULL);
+ RESOLVE_REF_READING, &oid,
+ NULL);
fake_av[1] = NULL;
av = fake_av;
ac = 1;
@@ -720,7 +720,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), oid.hash, &ref))
+ if (!dwim_ref(*av, strlen(*av), &oid, &ref))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
@@ -731,7 +731,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
/* Ah, that is a date spec... */
timestamp_t at;
at = approxidate(reflog_base);
- read_ref_at(ref, flags, at, -1, oid.hash, NULL,
+ read_ref_at(ref, flags, at, -1, &oid, NULL,
NULL, NULL, &base);
}
}
@@ -743,7 +743,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
timestamp_t timestamp;
int tz;
- if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
+ if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg,
&timestamp, &tz, NULL)) {
reflog = i;
break;
@@ -775,7 +775,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
}
head = resolve_refdup("HEAD", RESOLVE_REF_READING,
- head_oid.hash, NULL);
+ &head_oid, NULL);
if (with_current_branch && head) {
int has_head = 0;
@@ -808,7 +808,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("cannot handle more than %d rev.",
"cannot handle more than %d revs.",
MAX_REVS), MAX_REVS);
- if (get_sha1(ref_name[num_rev], revkey.hash))
+ if (get_oid(ref_name[num_rev], &revkey))
die(_("'%s' is not a valid ref."), ref_name[num_rev]);
commit = lookup_commit_reference(&revkey);
if (!commit)
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 013d241..41e5e71 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -38,7 +38,7 @@ static void show_one(const char *refname, const struct object_id *oid)
if (!deref_tags)
return;
- if (!peel_ref(refname, peeled.hash)) {
+ if (!peel_ref(refname, &peeled)) {
hex = find_unique_abbrev(peeled.hash, abbrev);
printf("%s %s^{}\n", hex, refname);
}
@@ -197,7 +197,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
struct object_id oid;
if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
- !read_ref(*pattern, oid.hash)) {
+ !read_ref(*pattern, &oid)) {
show_one(*pattern, &oid);
}
else if (!quiet)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 895555c..a5c4a8a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -13,13 +13,22 @@
#include "remote.h"
#include "refs.h"
#include "connect.h"
+#include "revision.h"
+#include "diffcore.h"
+#include "diff.h"
+
+#define OPT_QUIET (1 << 0)
+#define OPT_CACHED (1 << 1)
+#define OPT_RECURSIVE (1 << 2)
+
+typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
+ void *cb_data);
static char *get_default_remote(void)
{
char *dest = NULL, *ret;
- unsigned char sha1[20];
struct strbuf sb = STRBUF_INIT;
- const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+ const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
if (!refname)
die(_("No such ref: %s"), "HEAD");
@@ -220,6 +229,64 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+ const char *super_prefix = get_super_prefix();
+
+ if (prefix && super_prefix) {
+ BUG("cannot have prefix '%s' and superprefix '%s'",
+ prefix, super_prefix);
+ } else if (prefix) {
+ struct strbuf sb = STRBUF_INIT;
+ char *displaypath = xstrdup(relative_path(path, prefix, &sb));
+ strbuf_release(&sb);
+ return displaypath;
+ } else if (super_prefix) {
+ return xstrfmt("%s%s", super_prefix, path);
+ } else {
+ return xstrdup(path);
+ }
+}
+
+static char *compute_rev_name(const char *sub_path, const char* object_id)
+{
+ struct strbuf sb = STRBUF_INIT;
+ const char ***d;
+
+ static const char *describe_bare[] = { NULL };
+
+ static const char *describe_tags[] = { "--tags", NULL };
+
+ static const char *describe_contains[] = { "--contains", NULL };
+
+ static const char *describe_all_always[] = { "--all", "--always", NULL };
+
+ static const char **describe_argv[] = { describe_bare, describe_tags,
+ describe_contains,
+ describe_all_always, NULL };
+
+ for (d = describe_argv; *d; d++) {
+ struct child_process cp = CHILD_PROCESS_INIT;
+ prepare_submodule_repo_env(&cp.env_array);
+ cp.dir = sub_path;
+ cp.git_cmd = 1;
+ cp.no_stderr = 1;
+
+ argv_array_push(&cp.args, "describe");
+ argv_array_pushv(&cp.args, *d);
+ argv_array_push(&cp.args, object_id);
+
+ if (!capture_command(&cp, &sb, 0)) {
+ strbuf_strip_suffix(&sb, "\n");
+ return strbuf_detach(&sb, NULL);
+ }
+ }
+
+ strbuf_release(&sb);
+ return NULL;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -275,8 +342,6 @@ static void module_list_active(struct module_list *list)
int i;
struct module_list active_modules = MODULE_LIST_INIT;
- gitmodules_config();
-
for (i = 0; i < list->nr; i++) {
const struct cache_entry *ce = list->entries[i];
@@ -331,26 +396,31 @@ static int module_list(int argc, const char **argv, const char *prefix)
return 0;
}
-static void init_submodule(const char *path, const char *prefix, int quiet)
+static void for_each_listed_submodule(const struct module_list *list,
+ each_submodule_fn fn, void *cb_data)
+{
+ int i;
+ for (i = 0; i < list->nr; i++)
+ fn(list->entries[i], cb_data);
+}
+
+struct init_cb {
+ const char *prefix;
+ unsigned int flags;
+};
+
+#define INIT_CB_INIT { NULL, 0 }
+
+static void init_submodule(const char *path, const char *prefix,
+ unsigned int flags)
{
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
char *upd = NULL, *url = NULL, *displaypath;
- /* Only loads from .gitmodules, no overlay with .git/config */
- gitmodules_config();
-
- if (prefix && get_super_prefix())
- die("BUG: cannot have prefix and superprefix");
- else if (prefix)
- displaypath = xstrdup(relative_path(path, prefix, &sb));
- else if (get_super_prefix()) {
- strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
- displaypath = strbuf_detach(&sb, NULL);
- } else
- displaypath = xstrdup(path);
+ displaypath = get_submodule_displaypath(path, prefix);
- sub = submodule_from_path(null_sha1, path);
+ sub = submodule_from_path(&null_oid, path);
if (!sub)
die(_("No url found for submodule path '%s' in .gitmodules"),
@@ -363,9 +433,9 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
* Set active flag for the submodule being initialized
*/
if (!is_submodule_active(the_repository, path)) {
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.active", sub->name);
git_config_set_gently(sb.buf, "true");
+ strbuf_reset(&sb);
}
/*
@@ -373,7 +443,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
* To look up the url in .git/config, we must not fall back to
* .gitmodules, so look it up directly.
*/
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
if (git_config_get_string(sb.buf, &url)) {
if (!sub->url)
@@ -405,14 +474,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
if (git_config_set_gently(sb.buf, url))
die(_("Failed to register url for submodule path '%s'"),
displaypath);
- if (!quiet)
+ if (!(flags & OPT_QUIET))
fprintf(stderr,
_("Submodule '%s' (%s) registered for path '%s'\n"),
sub->name, url, displaypath);
}
+ strbuf_reset(&sb);
/* Copy "update" setting when it is not set yet */
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.update", sub->name);
if (git_config_get_string(sb.buf, &upd) &&
sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
@@ -432,12 +501,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
free(upd);
}
+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+ struct init_cb *info = cb_data;
+ init_submodule(list_item->name, info->prefix, info->flags);
+}
+
static int module_init(int argc, const char **argv, const char *prefix)
{
+ struct init_cb info = INIT_CB_INIT;
struct pathspec pathspec;
struct module_list list = MODULE_LIST_INIT;
int quiet = 0;
- int i;
struct option module_init_options[] = {
OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
@@ -462,8 +537,165 @@ static int module_init(int argc, const char **argv, const char *prefix)
if (!argc && git_config_get_value_multi("submodule.active"))
module_list_active(&list);
- for (i = 0; i < list.nr; i++)
- init_submodule(list.entries[i]->name, prefix, quiet);
+ info.prefix = prefix;
+ if (quiet)
+ info.flags |= OPT_QUIET;
+
+ for_each_listed_submodule(&list, init_submodule_cb, &info);
+
+ return 0;
+}
+
+struct status_cb {
+ const char *prefix;
+ unsigned int flags;
+};
+
+#define STATUS_CB_INIT { NULL, 0 }
+
+static void print_status(unsigned int flags, char state, const char *path,
+ const struct object_id *oid, const char *displaypath)
+{
+ if (flags & OPT_QUIET)
+ return;
+
+ printf("%c%s %s", state, oid_to_hex(oid), displaypath);
+
+ if (state == ' ' || state == '+')
+ printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
+
+ printf("\n");
+}
+
+static int handle_submodule_head_ref(const char *refname,
+ const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct object_id *output = cb_data;
+ if (oid)
+ oidcpy(output, oid);
+
+ return 0;
+}
+
+static void status_submodule(const char *path, const struct object_id *ce_oid,
+ unsigned int ce_flags, const char *prefix,
+ unsigned int flags)
+{
+ char *displaypath;
+ struct argv_array diff_files_args = ARGV_ARRAY_INIT;
+ struct rev_info rev;
+ int diff_files_result;
+
+ if (!submodule_from_path(&null_oid, path))
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
+
+ displaypath = get_submodule_displaypath(path, prefix);
+
+ if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
+ print_status(flags, 'U', path, &null_oid, displaypath);
+ goto cleanup;
+ }
+
+ if (!is_submodule_active(the_repository, path)) {
+ print_status(flags, '-', path, ce_oid, displaypath);
+ goto cleanup;
+ }
+
+ argv_array_pushl(&diff_files_args, "diff-files",
+ "--ignore-submodules=dirty", "--quiet", "--",
+ path, NULL);
+
+ git_config(git_diff_basic_config, NULL);
+ init_revisions(&rev, prefix);
+ rev.abbrev = 0;
+ diff_files_args.argc = setup_revisions(diff_files_args.argc,
+ diff_files_args.argv,
+ &rev, NULL);
+ diff_files_result = run_diff_files(&rev, 0);
+
+ if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+ print_status(flags, ' ', path, ce_oid,
+ displaypath);
+ } else if (!(flags & OPT_CACHED)) {
+ struct object_id oid;
+
+ if (refs_head_ref(get_submodule_ref_store(path),
+ handle_submodule_head_ref, &oid))
+ die(_("could not resolve HEAD ref inside the "
+ "submodule '%s'"), path);
+
+ print_status(flags, '+', path, &oid, displaypath);
+ } else {
+ print_status(flags, '+', path, ce_oid, displaypath);
+ }
+
+ if (flags & OPT_RECURSIVE) {
+ struct child_process cpr = CHILD_PROCESS_INIT;
+
+ cpr.git_cmd = 1;
+ cpr.dir = path;
+ prepare_submodule_repo_env(&cpr.env_array);
+
+ argv_array_push(&cpr.args, "--super-prefix");
+ argv_array_pushf(&cpr.args, "%s/", displaypath);
+ argv_array_pushl(&cpr.args, "submodule--helper", "status",
+ "--recursive", NULL);
+
+ if (flags & OPT_CACHED)
+ argv_array_push(&cpr.args, "--cached");
+
+ if (flags & OPT_QUIET)
+ argv_array_push(&cpr.args, "--quiet");
+
+ if (run_command(&cpr))
+ die(_("failed to recurse into submodule '%s'"), path);
+ }
+
+cleanup:
+ argv_array_clear(&diff_files_args);
+ free(displaypath);
+}
+
+static void status_submodule_cb(const struct cache_entry *list_item,
+ void *cb_data)
+{
+ struct status_cb *info = cb_data;
+ status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
+ info->prefix, info->flags);
+}
+
+static int module_status(int argc, const char **argv, const char *prefix)
+{
+ struct status_cb info = STATUS_CB_INIT;
+ struct pathspec pathspec;
+ struct module_list list = MODULE_LIST_INIT;
+ int quiet = 0;
+
+ struct option module_status_options[] = {
+ OPT__QUIET(&quiet, N_("Suppress submodule status output")),
+ OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+ OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_status_options,
+ git_submodule_helper_usage, 0);
+
+ if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ return 1;
+
+ info.prefix = prefix;
+ if (quiet)
+ info.flags |= OPT_QUIET;
+
+ for_each_listed_submodule(&list, status_submodule_cb, &info);
return 0;
}
@@ -475,8 +707,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
if (argc != 2)
usage(_("git submodule--helper name <path>"));
- gitmodules_config();
- sub = submodule_from_path(null_sha1, argv[1]);
+ sub = submodule_from_path(&null_oid, argv[1]);
if (!sub)
die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@ -780,6 +1011,10 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
struct strbuf *out)
{
const struct submodule *sub = NULL;
+ const char *url = NULL;
+ const char *update_string;
+ enum submodule_update_type update_type;
+ char *key;
struct strbuf displaypath_sb = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
const char *displaypath = NULL;
@@ -795,7 +1030,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
goto cleanup;
}
- sub = submodule_from_path(null_sha1, ce->name);
+ sub = submodule_from_path(&null_oid, ce->name);
if (suc->recursive_prefix)
displaypath = relative_path(suc->recursive_prefix,
@@ -808,9 +1043,17 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
goto cleanup;
}
+ key = xstrfmt("submodule.%s.update", sub->name);
+ if (!repo_config_get_string_const(the_repository, key, &update_string)) {
+ update_type = parse_submodule_update_type(update_string);
+ } else {
+ update_type = sub->update_strategy.type;
+ }
+ free(key);
+
if (suc->update.type == SM_UPDATE_NONE
|| (suc->update.type == SM_UPDATE_UNSPECIFIED
- && sub->update_strategy.type == SM_UPDATE_NONE)) {
+ && update_type == SM_UPDATE_NONE)) {
strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
strbuf_addch(out, '\n');
goto cleanup;
@@ -823,6 +1066,11 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
}
strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (repo_config_get_string_const(the_repository, sb.buf, &url))
+ url = sub->url;
+
+ strbuf_reset(&sb);
strbuf_addf(&sb, "%s/.git", ce->name);
needs_cloning = !file_exists(sb.buf);
@@ -851,7 +1099,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_push(&child->args, "--depth=1");
argv_array_pushl(&child->args, "--path", sub->path, NULL);
argv_array_pushl(&child->args, "--name", sub->name, NULL);
- argv_array_pushl(&child->args, "--url", sub->url, NULL);
+ argv_array_pushl(&child->args, "--url", url, NULL);
if (suc->references.nr) {
struct string_list_item *item;
for_each_string_list_item(item, &suc->references)
@@ -960,10 +1208,19 @@ static int update_clone_task_finished(int result,
return 0;
}
+static int gitmodules_update_clone_config(const char *var, const char *value,
+ void *cb)
+{
+ int *max_jobs = cb;
+ if (!strcmp(var, "submodule.fetchjobs"))
+ *max_jobs = parse_submodule_fetchjobs(var, value);
+ return 0;
+}
+
static int update_clone(int argc, const char **argv, const char *prefix)
{
const char *update = NULL;
- int max_jobs = -1;
+ int max_jobs = 1;
struct string_list_item *item;
struct pathspec pathspec;
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
@@ -1000,6 +1257,9 @@ static int update_clone(int argc, const char **argv, const char *prefix)
};
suc.prefix = prefix;
+ config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
+ git_config(gitmodules_update_clone_config, &max_jobs);
+
argc = parse_options(argc, argv, prefix, module_update_clone_options,
git_submodule_helper_usage, 0);
@@ -1013,13 +1273,6 @@ static int update_clone(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
suc.warn_if_uninitialized = 1;
- /* Overlay the parsed .gitmodules file with .git/config */
- gitmodules_config();
- git_config(submodule_config, NULL);
-
- if (max_jobs < 0)
- max_jobs = parallel_submodules();
-
run_processes_parallel(max_jobs,
update_clone_get_next_task,
update_clone_start_failure,
@@ -1057,19 +1310,23 @@ static int resolve_relative_path(int argc, const char **argv, const char *prefix
static const char *remote_submodule_branch(const char *path)
{
const struct submodule *sub;
- gitmodules_config();
- git_config(submodule_config, NULL);
+ const char *branch = NULL;
+ char *key;
- sub = submodule_from_path(null_sha1, path);
+ sub = submodule_from_path(&null_oid, path);
if (!sub)
return NULL;
- if (!sub->branch)
+ key = xstrfmt("submodule.%s.branch", sub->name);
+ if (repo_config_get_string_const(the_repository, key, &branch))
+ branch = sub->branch;
+ free(key);
+
+ if (!branch)
return "master";
- if (!strcmp(sub->branch, ".")) {
- unsigned char sha1[20];
- const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+ if (!strcmp(branch, ".")) {
+ const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
if (!refname)
die(_("No such ref: %s"), "HEAD");
@@ -1085,7 +1342,7 @@ static const char *remote_submodule_branch(const char *path)
return refname;
}
- return sub->branch;
+ return branch;
}
static int resolve_remote_submodule_branch(int argc, const char **argv,
@@ -1125,7 +1382,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
argv++;
argc--;
/* Get the submodule's head ref and determine if it is detached */
- head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ head = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
@@ -1168,6 +1425,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
break;
die("HEAD does not match the named branch in the superproject");
}
+ /* fallthrough */
default:
die("src refspec '%s' must name a ref",
rs->src);
@@ -1204,9 +1462,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, embed_gitdir_options,
git_submodule_helper_usage, 0);
- gitmodules_config();
- git_config(submodule_config, NULL);
-
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
return 1;
@@ -1222,8 +1477,6 @@ static int is_active(int argc, const char **argv, const char *prefix)
if (argc != 2)
die("submodule--helper is-active takes exactly 1 argument");
- gitmodules_config();
-
return !is_submodule_active(the_repository, argv[1]);
}
@@ -1244,6 +1497,7 @@ static struct cmd_struct commands[] = {
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"init", module_init, SUPPORT_SUPER_PREFIX},
+ {"status", module_status, SUPPORT_SUPER_PREFIX},
{"remote-branch", resolve_remote_submodule_branch, 0},
{"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index df75cb9..80237f0 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -12,9 +12,8 @@ static const char * const git_symbolic_ref_usage[] = {
static int check_symref(const char *HEAD, int quiet, int shorten, int print)
{
- unsigned char sha1[20];
int flag;
- const char *refname = resolve_ref_unsafe(HEAD, 0, sha1, &flag);
+ const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
if (!refname)
die("No such ref: %s", HEAD);
@@ -59,7 +58,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
die("deleting '%s' is not allowed", argv[0]);
- return delete_ref(NULL, argv[0], NULL, REF_NODEREF);
+ return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
}
switch (argc) {
diff --git a/builtin/tag.c b/builtin/tag.c
index 7a70d5a..a7e6a5b 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -82,7 +82,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
for (p = argv; *p; p++) {
strbuf_reset(&ref);
strbuf_addf(&ref, "refs/tags/%s", *p);
- if (read_ref(ref.buf, oid.hash)) {
+ if (read_ref(ref.buf, &oid)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
@@ -97,7 +97,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
static int delete_tag(const char *name, const char *ref,
const struct object_id *oid, const void *cb_data)
{
- if (delete_ref(NULL, ref, oid->hash, 0))
+ if (delete_ref(NULL, ref, oid, 0))
return 1;
printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
return 0;
@@ -113,7 +113,7 @@ static int verify_tag(const char *name, const char *ref,
if (format->format)
flags = GPG_VERIFY_OMIT_STATUS;
- if (gpg_verify_tag(oid->hash, name, flags))
+ if (gpg_verify_tag(oid, name, flags))
return -1;
if (format->format)
@@ -158,7 +158,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
if (starts_with(var, "column."))
return git_column_config(var, value, "tag", &colopts);
- return git_default_config(var, value, cb);
+ return git_color_default_config(var, value, cb);
}
static void write_tag_body(int fd, const struct object_id *oid)
@@ -411,6 +411,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
},
OPT_STRING( 0 , "format", &format.format, N_("format"),
N_("format to use for the output")),
+ OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_END()
};
@@ -517,7 +518,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (strbuf_check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
- if (read_ref(ref.buf, prev.hash))
+ if (read_ref(ref.buf, &prev))
oidclr(&prev);
else if (!force)
die(_("tag '%s' already exists"), tag);
@@ -543,7 +544,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
+ ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err))
@@ -552,9 +553,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV));
- strbuf_release(&err);
- strbuf_release(&buf);
- strbuf_release(&ref);
- strbuf_release(&reflog_msg);
+ UNLEAK(buf);
+ UNLEAK(ref);
+ UNLEAK(reflog_msg);
+ UNLEAK(msg);
+ UNLEAK(err);
return 0;
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 73f1334..32e0155 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,7 +1,7 @@
#include "builtin.h"
#include "config.h"
-static char *create_temp_file(unsigned char *sha1)
+static char *create_temp_file(struct object_id *oid)
{
static char path[50];
void *buf;
@@ -9,13 +9,13 @@ static char *create_temp_file(unsigned char *sha1)
unsigned long size;
int fd;
- buf = read_sha1_file(sha1, &type, &size);
+ buf = read_sha1_file(oid->hash, &type, &size);
if (!buf || type != OBJ_BLOB)
- die("unable to read blob object %s", sha1_to_hex(sha1));
+ die("unable to read blob object %s", oid_to_hex(oid));
xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
fd = xmkstemp(path);
- if (write_in_full(fd, buf, size) != size)
+ if (write_in_full(fd, buf, size) < 0)
die_errno("unable to write temp-file");
close(fd);
return path;
@@ -23,15 +23,15 @@ static char *create_temp_file(unsigned char *sha1)
int cmd_unpack_file(int argc, const char **argv, const char *prefix)
{
- unsigned char sha1[20];
+ struct object_id oid;
if (argc != 2 || !strcmp(argv[1], "-h"))
usage("git unpack-file <sha1>");
- if (get_sha1(argv[1], sha1))
+ if (get_oid(argv[1], &oid))
die("Not a valid object name %s", argv[1]);
git_config(git_default_config, NULL);
- puts(create_temp_file(sha1));
+ puts(create_temp_file(&oid));
return 0;
}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 689a29f..62ea264 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -394,7 +394,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
lo = 0;
hi = nr;
while (lo < hi) {
- mid = (lo + hi)/2;
+ mid = lo + (hi - lo) / 2;
if (base_offset < obj_list[mid].offset) {
hi = mid;
} else if (base_offset > obj_list[mid].offset) {
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 56721cf..58d1c2d 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -16,6 +16,7 @@
#include "pathspec.h"
#include "dir.h"
#include "split-index.h"
+#include "fsmonitor.h"
/*
* Default to not allowing changes to the list of files. The
@@ -32,6 +33,7 @@ static int force_remove;
static int verbose;
static int mark_valid_only;
static int mark_skip_worktree_only;
+static int mark_fsmonitor_only;
#define MARK_FLAG 1
#define UNMARK_FLAG 2
static struct strbuf mtime_dir = STRBUF_INIT;
@@ -228,6 +230,7 @@ static int mark_ce_flags(const char *path, int flag, int mark)
int namelen = strlen(path);
int pos = cache_name_pos(path, namelen);
if (0 <= pos) {
+ mark_fsmonitor_invalid(&the_index, active_cache[pos]);
if (mark)
active_cache[pos]->ce_flags |= flag;
else
@@ -280,15 +283,17 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
fill_stat_cache_info(ce, st);
ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
- if (index_path(ce->oid.hash, path, st,
+ if (index_path(&ce->oid, path, st,
info_only ? 0 : HASH_WRITE_OBJECT)) {
free(ce);
return -1;
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option))
+ if (add_cache_entry(ce, option)) {
+ free(ce);
return error("%s: cannot add to the index - missing --add option?", path);
+ }
return 0;
}
@@ -326,7 +331,7 @@ static int process_directory(const char *path, int len, struct stat *st)
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
- if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0)
+ if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
return 0;
return add_one_path(ce, path, len, st);
@@ -352,7 +357,7 @@ static int process_directory(const char *path, int len, struct stat *st)
}
/* No match - should we add it as a gitlink? */
- if (!resolve_gitlink_ref(path, "HEAD", oid.hash))
+ if (!resolve_gitlink_ref(path, "HEAD", &oid))
return add_one_path(NULL, path, len, st);
/* Error out. */
@@ -458,6 +463,11 @@ static void update_one(const char *path)
die("Unable to mark file %s", path);
return;
}
+ if (mark_fsmonitor_only) {
+ if (mark_ce_flags(path, CE_FSMONITOR_VALID, mark_fsmonitor_only == MARK_FLAG))
+ die("Unable to mark file %s", path);
+ return;
+ }
if (force_remove) {
if (remove_file_from_cache(path))
@@ -677,9 +687,9 @@ static int unresolve_one(const char *path)
static void read_head_pointers(void)
{
- if (read_ref("HEAD", head_oid.hash))
+ if (read_ref("HEAD", &head_oid))
die("No HEAD -- no initial commit yet?");
- if (read_ref("MERGE_HEAD", merge_head_oid.hash)) {
+ if (read_ref("MERGE_HEAD", &merge_head_oid)) {
fprintf(stderr, "Not in the middle of a merge.\n");
exit(0);
}
@@ -719,7 +729,7 @@ static int do_reupdate(int ac, const char **av,
PATHSPEC_PREFER_CWD,
prefix, av + 1);
- if (read_ref("HEAD", head_oid.hash))
+ if (read_ref("HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
* commit. Update everything in the index.
*/
@@ -915,7 +925,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
struct refresh_params refresh_args = {0, &has_errors};
int lock_error = 0;
int split_index = -1;
- struct lock_file *lock_file;
+ int force_write = 0;
+ int fsmonitor = -1;
+ struct lock_file lock_file = LOCK_INIT;
struct parse_opt_ctx_t ctx;
strbuf_getline_fn getline_fn;
int parseopt_state = PARSE_OPT_UNKNOWN;
@@ -1006,6 +1018,16 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
N_("test if the filesystem supports untracked cache"), UC_TEST),
OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
N_("enable untracked cache without testing the filesystem"), UC_FORCE),
+ OPT_SET_INT(0, "force-write-index", &force_write,
+ N_("write out the index even if is not flagged as changed"), 1),
+ OPT_BOOL(0, "fsmonitor", &fsmonitor,
+ N_("enable or disable file system monitor")),
+ {OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL,
+ N_("mark files as fsmonitor valid"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
+ {OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL,
+ N_("clear fsmonitor valid bit"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
OPT_END()
};
@@ -1014,11 +1036,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
- /* We can't free this memory, it becomes part of a linked list parsed atexit() */
- lock_file = xcalloc(1, sizeof(struct lock_file));
-
/* we will diagnose later if it turns out that we need to update it */
- newfd = hold_locked_index(lock_file, 0);
+ newfd = hold_locked_index(&lock_file, 0);
if (newfd < 0)
lock_error = errno;
@@ -1147,17 +1166,33 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
die("BUG: bad untracked_cache value: %d", untracked_cache);
}
- if (active_cache_changed) {
+ if (fsmonitor > 0) {
+ if (git_config_get_fsmonitor() == 0)
+ warning(_("core.fsmonitor is unset; "
+ "set it if you really want to "
+ "enable fsmonitor"));
+ add_fsmonitor(&the_index);
+ report(_("fsmonitor enabled"));
+ } else if (!fsmonitor) {
+ if (git_config_get_fsmonitor() == 1)
+ warning(_("core.fsmonitor is set; "
+ "remove it if you really want to "
+ "disable fsmonitor"));
+ remove_fsmonitor(&the_index);
+ report(_("fsmonitor disabled"));
+ }
+
+ if (active_cache_changed || force_write) {
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);
unable_to_lock_die(get_index_file(), lock_error);
}
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
}
- rollback_lock_file(lock_file);
+ rollback_lock_file(&lock_file);
return has_errors ? 1 : 0;
}
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 40ccfc1..4b4714b 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -94,10 +94,10 @@ static char *parse_refname(struct strbuf *input, const char **next)
* provided but cannot be converted to a SHA-1, die. flags can
* include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
*/
-static int parse_next_sha1(struct strbuf *input, const char **next,
- unsigned char *sha1,
- const char *command, const char *refname,
- int flags)
+static int parse_next_oid(struct strbuf *input, const char **next,
+ struct object_id *oid,
+ const char *command, const char *refname,
+ int flags)
{
struct strbuf arg = STRBUF_INIT;
int ret = 0;
@@ -115,11 +115,11 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
(*next)++;
*next = parse_arg(*next, &arg);
if (arg.len) {
- if (get_sha1(arg.buf, sha1))
+ if (get_oid(arg.buf, oid))
goto invalid;
} else {
/* Without -z, an empty value means all zeros: */
- hashclr(sha1);
+ oidclr(oid);
}
} else {
/* With -z, read the next NUL-terminated line */
@@ -133,13 +133,13 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
*next += arg.len;
if (arg.len) {
- if (get_sha1(arg.buf, sha1))
+ if (get_oid(arg.buf, oid))
goto invalid;
} else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
/* With -z, treat an empty value as all zeros: */
warning("%s %s: missing <newvalue>, treating as zero",
command, refname);
- hashclr(sha1);
+ oidclr(oid);
} else {
/*
* With -z, an empty non-required value means
@@ -182,26 +182,25 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
{
struct strbuf err = STRBUF_INIT;
char *refname;
- unsigned char new_sha1[20];
- unsigned char old_sha1[20];
+ struct object_id new_oid, old_oid;
int have_old;
refname = parse_refname(input, &next);
if (!refname)
die("update: missing <ref>");
- if (parse_next_sha1(input, &next, new_sha1, "update", refname,
- PARSE_SHA1_ALLOW_EMPTY))
+ if (parse_next_oid(input, &next, &new_oid, "update", refname,
+ PARSE_SHA1_ALLOW_EMPTY))
die("update %s: missing <newvalue>", refname);
- have_old = !parse_next_sha1(input, &next, old_sha1, "update", refname,
- PARSE_SHA1_OLD);
+ have_old = !parse_next_oid(input, &next, &old_oid, "update", refname,
+ PARSE_SHA1_OLD);
if (*next != line_termination)
die("update %s: extra input: %s", refname, next);
if (ref_transaction_update(transaction, refname,
- new_sha1, have_old ? old_sha1 : NULL,
+ &new_oid, have_old ? &old_oid : NULL,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
@@ -218,22 +217,22 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
{
struct strbuf err = STRBUF_INIT;
char *refname;
- unsigned char new_sha1[20];
+ struct object_id new_oid;
refname = parse_refname(input, &next);
if (!refname)
die("create: missing <ref>");
- if (parse_next_sha1(input, &next, new_sha1, "create", refname, 0))
+ if (parse_next_oid(input, &next, &new_oid, "create", refname, 0))
die("create %s: missing <newvalue>", refname);
- if (is_null_sha1(new_sha1))
+ if (is_null_oid(&new_oid))
die("create %s: zero <newvalue>", refname);
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- if (ref_transaction_create(transaction, refname, new_sha1,
+ if (ref_transaction_create(transaction, refname, &new_oid,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
@@ -250,18 +249,18 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
{
struct strbuf err = STRBUF_INIT;
char *refname;
- unsigned char old_sha1[20];
+ struct object_id old_oid;
int have_old;
refname = parse_refname(input, &next);
if (!refname)
die("delete: missing <ref>");
- if (parse_next_sha1(input, &next, old_sha1, "delete", refname,
- PARSE_SHA1_OLD)) {
+ if (parse_next_oid(input, &next, &old_oid, "delete", refname,
+ PARSE_SHA1_OLD)) {
have_old = 0;
} else {
- if (is_null_sha1(old_sha1))
+ if (is_null_oid(&old_oid))
die("delete %s: zero <oldvalue>", refname);
have_old = 1;
}
@@ -270,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
die("delete %s: extra input: %s", refname, next);
if (ref_transaction_delete(transaction, refname,
- have_old ? old_sha1 : NULL,
+ have_old ? &old_oid : NULL,
update_flags, msg, &err))
die("%s", err.buf);
@@ -286,20 +285,20 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
{
struct strbuf err = STRBUF_INIT;
char *refname;
- unsigned char old_sha1[20];
+ struct object_id old_oid;
refname = parse_refname(input, &next);
if (!refname)
die("verify: missing <ref>");
- if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
- PARSE_SHA1_OLD))
- hashclr(old_sha1);
+ if (parse_next_oid(input, &next, &old_oid, "verify", refname,
+ PARSE_SHA1_OLD))
+ oidclr(&old_oid);
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
- if (ref_transaction_verify(transaction, refname, old_sha1,
+ if (ref_transaction_verify(transaction, refname, &old_oid,
update_flags, &err))
die("%s", err.buf);
@@ -313,7 +312,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
static const char *parse_cmd_option(struct strbuf *input, const char *next)
{
if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
- update_flags |= REF_NODEREF;
+ update_flags |= REF_NO_DEREF;
else
die("option unknown: %s", next);
return next + 8;
@@ -355,7 +354,7 @@ static void update_refs_stdin(struct ref_transaction *transaction)
int cmd_update_ref(int argc, const char **argv, const char *prefix)
{
const char *refname, *oldval;
- unsigned char sha1[20], oldsha1[20];
+ struct object_id oid, oldoid;
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
unsigned int flags = 0;
int create_reflog = 0;
@@ -412,7 +411,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
refname = argv[0];
value = argv[1];
oldval = argv[2];
- if (get_sha1(value, sha1))
+ if (get_oid(value, &oid))
die("%s: not a valid SHA1", value);
}
@@ -422,23 +421,23 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* The empty string implies that the reference
* must not already exist:
*/
- hashclr(oldsha1);
- else if (get_sha1(oldval, oldsha1))
+ oidclr(&oldoid);
+ else if (get_oid(oldval, &oldoid))
die("%s: not a valid old SHA1", oldval);
}
if (no_deref)
- flags = REF_NODEREF;
+ flags = REF_NO_DEREF;
if (delete)
/*
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
return delete_ref(msg, refname,
- (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
+ (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
flags);
else
- return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
+ return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
flags | create_reflog_flag,
UPDATE_REFS_DIE_ON_ERR);
}
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 87d73e8..ad7b79f 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -58,20 +58,21 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
}
while (i < argc) {
- unsigned char sha1[20];
+ struct object_id oid;
const char *name = argv[i++];
- if (get_sha1(name, sha1)) {
+
+ if (get_oid(name, &oid)) {
had_error = !!error("tag '%s' not found.", name);
continue;
}
- if (gpg_verify_tag(sha1, name, flags)) {
+ if (gpg_verify_tag(&oid, name, flags)) {
had_error = 1;
continue;
}
if (format.format)
- pretty_print_ref(name, sha1, &format);
+ pretty_print_ref(name, oid.hash, &format);
}
return had_error;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c98e2ce..7cef5b1 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "checkout.h"
#include "config.h"
#include "builtin.h"
#include "dir.h"
@@ -32,13 +33,26 @@ struct add_opts {
static int show_only;
static int verbose;
+static int guess_remote;
static timestamp_t expire;
+static int git_worktree_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "worktree.guessremote")) {
+ guess_remote = git_config_bool(var, value);
+ return 0;
+ }
+
+ return git_default_config(var, value, cb);
+}
+
static int prune_worktree(const char *id, struct strbuf *reason)
{
struct stat st;
char *path;
- int fd, len;
+ int fd;
+ size_t len;
+ ssize_t read_result;
if (!is_directory(git_path("worktrees/%s", id))) {
strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id);
@@ -56,10 +70,26 @@ static int prune_worktree(const char *id, struct strbuf *reason)
id, strerror(errno));
return 1;
}
- len = st.st_size;
+ len = xsize_t(st.st_size);
path = xmallocz(len);
- read_in_full(fd, path, len);
+
+ read_result = read_in_full(fd, path, len);
+ if (read_result < 0) {
+ strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
+ id, strerror(errno));
+ close(fd);
+ free(path);
+ return 1;
+ }
close(fd);
+
+ if (read_result != len) {
+ strbuf_addf(reason,
+ _("Removing worktrees/%s: short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
+ id, (uintmax_t)len, (uintmax_t)read_result);
+ free(path);
+ return 1;
+ }
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
len--;
if (!len) {
@@ -200,20 +230,21 @@ static int add_worktree(const char *path, const char *refname,
int counter = 0, len, ret;
struct strbuf symref = STRBUF_INIT;
struct commit *commit = NULL;
+ int is_branch = 0;
if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
/* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
- ref_exists(symref.buf)) { /* it's a branch */
+ ref_exists(symref.buf)) {
+ is_branch = 1;
if (!opts->force)
die_if_checked_out(symref.buf, 0);
- } else { /* must be a commit */
- commit = lookup_commit_reference_by_name(refname);
- if (!commit)
- die(_("invalid reference: %s"), refname);
}
+ commit = lookup_commit_reference_by_name(refname);
+ if (!commit)
+ die(_("invalid reference: %s"), refname);
name = worktree_basename(path, &len);
git_path_buf(&sb_repo, "worktrees/%.*s", (int)(path + len - name), name);
@@ -278,7 +309,7 @@ static int add_worktree(const char *path, const char *refname,
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
- if (commit)
+ if (!is_branch)
argv_array_pushl(&cp.args, "update-ref", "HEAD",
oid_to_hex(&commit->object.oid), NULL);
else
@@ -309,6 +340,15 @@ done:
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
unlink_or_warn(sb.buf);
}
+
+ /*
+ * Hook failure does not warrant worktree deletion, so run hook after
+ * is_junk is cleared, but do return appropriate code when hook fails.
+ */
+ if (!ret && opts->checkout)
+ ret = run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
+ oid_to_hex(&commit->object.oid), "1", NULL);
+
argv_array_clear(&child_env);
strbuf_release(&sb);
strbuf_release(&symref);
@@ -323,6 +363,7 @@ static int add(int ac, const char **av, const char *prefix)
const char *new_branch_force = NULL;
char *path;
const char *branch;
+ const char *opt_track = NULL;
struct option options[] = {
OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -332,6 +373,11 @@ static int add(int ac, const char **av, const char *prefix)
OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+ OPT_PASSTHRU(0, "track", &opt_track, NULL,
+ N_("set up tracking mode (see git-branch(1))"),
+ PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
+ OPT_BOOL(0, "guess-remote", &guess_remote,
+ N_("try to match the new branch name with a remote-tracking branch")),
OPT_END()
};
@@ -366,6 +412,28 @@ static int add(int ac, const char **av, const char *prefix)
int n;
const char *s = worktree_basename(path, &n);
opts.new_branch = xstrndup(s, n);
+ if (guess_remote) {
+ struct object_id oid;
+ const char *remote =
+ unique_tracking_name(opts.new_branch, &oid);
+ if (remote)
+ branch = remote;
+ }
+ }
+
+ if (ac == 2 && !opts.new_branch && !opts.detach) {
+ struct object_id oid;
+ struct commit *commit;
+ const char *remote;
+
+ commit = lookup_commit_reference_by_name(branch);
+ if (!commit) {
+ remote = unique_tracking_name(branch, &oid);
+ if (remote) {
+ opts.new_branch = branch;
+ branch = remote;
+ }
+ }
}
if (opts.new_branch) {
@@ -376,11 +444,17 @@ static int add(int ac, const char **av, const char *prefix)
argv_array_push(&cp.args, "--force");
argv_array_push(&cp.args, opts.new_branch);
argv_array_push(&cp.args, branch);
+ if (opt_track)
+ argv_array_push(&cp.args, opt_track);
if (run_command(&cp))
return -1;
branch = opts.new_branch;
+ } else if (opt_track) {
+ die(_("--[no-]track can only be used if a new branch is created"));
}
+ UNLEAK(path);
+ UNLEAK(opts);
return add_worktree(path, branch, &opts);
}
@@ -390,7 +464,7 @@ static void show_worktree_porcelain(struct worktree *wt)
if (wt->is_bare)
printf("bare\n");
else {
- printf("HEAD %s\n", sha1_to_hex(wt->head_sha1));
+ printf("HEAD %s\n", oid_to_hex(&wt->head_oid));
if (wt->is_detached)
printf("detached\n");
else if (wt->head_ref)
@@ -410,7 +484,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(bare)");
else {
strbuf_addf(&sb, "%-*s ", abbrev_len,
- find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
+ find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
@@ -435,7 +509,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
if (path_len > *maxlen)
*maxlen = path_len;
- sha1_len = strlen(find_unique_abbrev(wt[i]->head_sha1, *abbrev));
+ sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
@@ -537,7 +611,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
OPT_END()
};
- git_config(git_default_config, NULL);
+ git_config(git_worktree_config, NULL);
if (ac < 2)
usage_with_options(worktree_usage, options);