summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/cat-file.c5
-rw-r--r--builtin/checkout.c64
-rw-r--r--builtin/clone.c13
-rw-r--r--builtin/commit-graph.c5
-rw-r--r--builtin/commit.c42
-rw-r--r--builtin/describe.c15
-rw-r--r--builtin/fmt-merge-msg.c11
-rw-r--r--builtin/init-db.c79
-rw-r--r--builtin/merge-base.c12
-rw-r--r--builtin/pack-objects.c6
-rw-r--r--builtin/pull.c16
-rw-r--r--builtin/rebase.c1
-rw-r--r--builtin/reset.c16
-rw-r--r--builtin/rev-parse.c12
-rw-r--r--builtin/stash.c50
-rw-r--r--builtin/submodule--helper.c8
-rw-r--r--builtin/tag.c5
-rw-r--r--builtin/worktree.c9
18 files changed, 236 insertions, 133 deletions
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 272f9fc6d7..6ecc8ee6dc 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -42,7 +42,10 @@ static int filter_object(const char *path, unsigned mode,
oid_to_hex(oid), path);
if ((type == OBJ_BLOB) && S_ISREG(mode)) {
struct strbuf strbuf = STRBUF_INIT;
- if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) {
+ struct checkout_metadata meta;
+
+ init_checkout_metadata(&meta, NULL, NULL, oid);
+ if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) {
free(*buf);
*size = strbuf.len;
*buf = strbuf_detach(&strbuf, NULL);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d6773818b8..8bc94d392b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -88,6 +88,19 @@ struct checkout_opts {
struct tree *source_tree;
};
+struct branch_info {
+ const char *name; /* The short name used */
+ const char *path; /* The full name of a real branch */
+ struct commit *commit; /* The named commit */
+ char *refname; /* The full name of the ref being checked out. */
+ struct object_id oid; /* The object ID of the commit being checked out. */
+ /*
+ * if not null the branch is detached because it's already
+ * checked out in this checkout
+ */
+ char *checkout;
+};
+
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
@@ -337,7 +350,8 @@ static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
}
}
-static int checkout_worktree(const struct checkout_opts *opts)
+static int checkout_worktree(const struct checkout_opts *opts,
+ const struct branch_info *info)
{
struct checkout state = CHECKOUT_INIT;
int nr_checkouts = 0, nr_unmerged = 0;
@@ -348,6 +362,10 @@ static int checkout_worktree(const struct checkout_opts *opts)
state.refresh_cache = 1;
state.istate = &the_index;
+ init_checkout_metadata(&state.meta, info->refname,
+ info->commit ? &info->commit->object.oid : &info->oid,
+ NULL);
+
enable_delayed_checkout(&state);
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
@@ -396,7 +414,7 @@ static int checkout_worktree(const struct checkout_opts *opts)
}
static int checkout_paths(const struct checkout_opts *opts,
- const char *revision)
+ const struct branch_info *new_branch_info)
{
int pos;
static char *ps_matched;
@@ -462,7 +480,7 @@ static int checkout_paths(const struct checkout_opts *opts,
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return run_add_interactive(revision, patch_mode, &opts->pathspec);
+ return run_add_interactive(new_branch_info->name, patch_mode, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -523,7 +541,7 @@ static int checkout_paths(const struct checkout_opts *opts,
/* Now we are committed to check them out */
if (opts->checkout_worktree)
- errs |= checkout_worktree(opts);
+ errs |= checkout_worktree(opts, new_branch_info);
else
remove_marked_cache_entries(&the_index, 1);
@@ -586,7 +604,8 @@ static void describe_detached_head(const char *msg, struct commit *commit)
}
static int reset_tree(struct tree *tree, const struct checkout_opts *o,
- int worktree, int *writeout_error)
+ int worktree, int *writeout_error,
+ struct branch_info *info)
{
struct unpack_trees_options opts;
struct tree_desc tree_desc;
@@ -601,6 +620,11 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
opts.verbose_update = o->show_progress;
opts.src_index = &the_index;
opts.dst_index = &the_index;
+ init_checkout_metadata(&opts.meta, info->refname,
+ info->commit ? &info->commit->object.oid :
+ is_null_oid(&info->oid) ? &tree->object.oid :
+ &info->oid,
+ NULL);
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
@@ -620,21 +644,17 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
}
}
-struct branch_info {
- const char *name; /* The short name used */
- const char *path; /* The full name of a real branch */
- struct commit *commit; /* The named commit */
- /*
- * if not null the branch is detached because it's already
- * checked out in this checkout
- */
- char *checkout;
-};
-
static void setup_branch_path(struct branch_info *branch)
{
struct strbuf buf = STRBUF_INIT;
+ /*
+ * If this is a ref, resolve it; otherwise, look up the OID for our
+ * expression. Failure here is okay.
+ */
+ if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname))
+ repo_get_oid_committish(the_repository, branch->name, &branch->oid);
+
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
if (strcmp(buf.buf, branch->name))
branch->name = xstrdup(buf.buf);
@@ -663,7 +683,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
} else
new_tree = get_commit_tree(new_branch_info->commit);
if (opts->discard_changes) {
- ret = reset_tree(new_tree, opts, 1, writeout_error);
+ ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
return ret;
} else {
@@ -692,6 +712,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
topts.quiet = opts->merge && old_branch_info->commit;
topts.verbose_update = opts->show_progress;
topts.fn = twoway_merge;
+ init_checkout_metadata(&topts.meta, new_branch_info->refname,
+ new_branch_info->commit ?
+ &new_branch_info->commit->object.oid :
+ &new_branch_info->oid, NULL);
if (opts->overwrite_ignore) {
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->flags |= DIR_SHOW_IGNORED;
@@ -762,7 +786,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
ret = reset_tree(new_tree,
opts, 1,
- writeout_error);
+ writeout_error, new_branch_info);
if (ret)
return ret;
o.ancestor = old_branch_info->name;
@@ -782,7 +806,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
exit(128);
ret = reset_tree(new_tree,
opts, 0,
- writeout_error);
+ writeout_error, new_branch_info);
strbuf_release(&o.obuf);
strbuf_release(&old_commit_shortname);
if (ret)
@@ -1710,7 +1734,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
UNLEAK(opts);
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, new_branch_info.name);
+ return checkout_paths(opts, &new_branch_info);
else
return checkout_branch(opts, &new_branch_info);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index 1ad26f4d8c..d8b1f413aa 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
struct dir_iterator *iter;
int iter_status;
unsigned int flags;
+ struct strbuf realpath = STRBUF_INIT;
mkdir_if_missing(dest->buf, 0777);
@@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
- if (!link(real_path(src->buf), dest->buf))
+ strbuf_realpath(&realpath, src->buf, 1);
+ if (!link(realpath.buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
@@ -468,6 +470,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf);
}
+
+ strbuf_release(&realpath);
}
static void clone_local(const char *src_repo, const char *dest_repo)
@@ -780,11 +784,11 @@ static int checkout(int submodule_progress)
if (!strcmp(head, "HEAD")) {
if (advice_detached_head)
detach_advice(oid_to_hex(&oid));
+ FREE_AND_NULL(head);
} else {
if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
}
- free(head);
/* We need to be in the new work tree for the checkout */
setup_work_tree();
@@ -799,6 +803,7 @@ static int checkout(int submodule_progress)
opts.verbose_update = (option_verbosity >= 0);
opts.src_index = &the_index;
opts.dst_index = &the_index;
+ init_checkout_metadata(&opts.meta, head, &oid, NULL);
tree = parse_tree_indirect(&oid);
parse_tree(tree);
@@ -806,6 +811,8 @@ static int checkout(int submodule_progress)
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
+ free(head);
+
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
@@ -1102,7 +1109,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
+ init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
if (real_git_dir)
git_dir = real_git_dir;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4a70b33fb5..d1ab6625f6 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -39,14 +39,17 @@ static struct object_directory *find_odb(struct repository *r,
{
struct object_directory *odb;
char *obj_dir_real = real_pathdup(obj_dir, 1);
+ struct strbuf odb_path_real = STRBUF_INIT;
prepare_alt_odb(r);
for (odb = r->objects->odb; odb; odb = odb->next) {
- if (!strcmp(obj_dir_real, real_path(odb->path)))
+ strbuf_realpath(&odb_path_real, odb->path, 1);
+ if (!strcmp(obj_dir_real, odb_path_real.buf))
break;
}
free(obj_dir_real);
+ strbuf_release(&odb_path_real);
if (!odb)
die(_("could not find object directory matching %s"), obj_dir);
diff --git a/builtin/commit.c b/builtin/commit.c
index 7ba33a3bec..d3e7781e65 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -59,6 +59,9 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
" git commit --allow-empty\n"
"\n");
+static const char empty_rebase_pick_advice[] =
+N_("Otherwise, please use 'git rebase --skip'\n");
+
static const char empty_cherry_pick_advice_single[] =
N_("Otherwise, please use 'git cherry-pick --skip'\n");
@@ -122,7 +125,6 @@ static enum commit_msg_cleanup_mode cleanup_mode;
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 have_option_m;
static struct strbuf message = STRBUF_INIT;
@@ -179,12 +181,7 @@ static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path_merge_head(the_repository)))
whence = FROM_MERGE;
- else if (file_exists(git_path_cherry_pick_head(the_repository))) {
- whence = FROM_CHERRY_PICK;
- if (file_exists(git_path_seq_dir()))
- sequencer_in_use = 1;
- }
- else
+ else if (!sequencer_determine_whence(the_repository, &whence))
whence = FROM_COMMIT;
if (s)
s->whence = whence;
@@ -477,8 +474,10 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (whence != FROM_COMMIT) {
if (whence == FROM_MERGE)
die(_("cannot do a partial commit during a merge."));
- else if (whence == FROM_CHERRY_PICK)
+ else if (is_from_cherry_pick(whence))
die(_("cannot do a partial commit during a cherry-pick."));
+ else if (is_from_rebase(whence))
+ die(_("cannot do a partial commit during a rebase."));
}
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
@@ -795,7 +794,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
*/
else if (whence == FROM_MERGE)
hook_arg1 = "merge";
- else if (whence == FROM_CHERRY_PICK) {
+ else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) {
hook_arg1 = "commit";
hook_arg2 = "CHERRY_PICK_HEAD";
}
@@ -973,12 +972,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
run_status(stdout, index_file, prefix, 0, s);
if (amend)
fputs(_(empty_amend_advice), stderr);
- else if (whence == FROM_CHERRY_PICK) {
+ else if (is_from_cherry_pick(whence) ||
+ whence == FROM_REBASE_PICK) {
fputs(_(empty_cherry_pick_advice), stderr);
- if (!sequencer_in_use)
+ if (whence == FROM_CHERRY_PICK_SINGLE)
fputs(_(empty_cherry_pick_advice_single), stderr);
- else
+ else if (whence == FROM_CHERRY_PICK_MULTI)
fputs(_(empty_cherry_pick_advice_multi), stderr);
+ else
+ fputs(_(empty_rebase_pick_advice), stderr);
}
return 0;
}
@@ -1181,8 +1183,10 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (amend && whence != FROM_COMMIT) {
if (whence == FROM_MERGE)
die(_("You are in the middle of a merge -- cannot amend."));
- else if (whence == FROM_CHERRY_PICK)
+ else if (is_from_cherry_pick(whence))
die(_("You are in the middle of a cherry-pick -- cannot amend."));
+ else if (whence == FROM_REBASE_PICK)
+ die(_("You are in the middle of a rebase -- cannot amend."));
}
if (fixup_message && squash_message)
die(_("Options --squash and --fixup cannot be used together"));
@@ -1204,7 +1208,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
use_message = edit_message;
if (amend && !use_message && !fixup_message)
use_message = "HEAD";
- if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)
+ if (!use_message && !is_from_cherry_pick(whence) &&
+ !is_from_rebase(whence) && renew_authorship)
die(_("--reset-author can be used only with -C, -c or --amend."));
if (use_message) {
use_message_buffer = read_commit_message(use_message);
@@ -1213,7 +1218,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
author_message_buffer = use_message_buffer;
}
}
- if (whence == FROM_CHERRY_PICK && !renew_authorship) {
+ if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) &&
+ !renew_authorship) {
author_message = "CHERRY_PICK_HEAD";
author_message_buffer = read_commit_message(author_message);
}
@@ -1631,8 +1637,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
reduce_heads_replace(&parents);
} else {
if (!reflog_msg)
- reflog_msg = (whence == FROM_CHERRY_PICK)
+ reflog_msg = is_from_cherry_pick(whence)
? "commit (cherry-pick)"
+ : is_from_rebase(whence)
+ ? "commit (rebase)"
: "commit";
commit_list_insert(current_head, &parents);
}
@@ -1659,7 +1667,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
if (amend) {
- const char *exclude_gpgsig[2] = { "gpgsig", NULL };
+ const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
extra = read_commit_extra_headers(current_head, exclude_gpgsig);
} else {
struct commit_extra_header **tail = &extra;
diff --git a/builtin/describe.c b/builtin/describe.c
index 420f4c6401..21d2cb9e57 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -54,6 +54,7 @@ struct commit_name {
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
+ unsigned misnamed:1;
struct object_id oid;
char *path;
};
@@ -132,6 +133,7 @@ static void add_to_known_names(const char *path,
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
+ e->misnamed = 0;
oidcpy(&e->oid, oid);
free(e->path);
e->path = xstrdup(path);
@@ -275,10 +277,11 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
die(_("annotated tag %s not available"), n->path);
}
if (n->tag && !n->name_checked) {
- if (!n->tag->tag)
- die(_("annotated tag %s has no embedded name"), n->path);
- if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
- warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
+ if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) {
+ warning(_("tag '%s' is externally known as '%s'"),
+ n->path, n->tag->tag);
+ n->misnamed = 1;
+ }
n->name_checked = 1;
}
@@ -314,7 +317,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
* Exact match to an existing ref.
*/
append_name(n, dst);
- if (longformat)
+ if (n->misnamed || longformat)
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
@@ -463,7 +466,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
append_name(all_matches[0].name, dst);
- if (abbrev)
+ if (all_matches[0].name->misnamed || abbrev)
append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 736f666f64..172dfbd852 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -494,6 +494,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
enum object_type type;
unsigned long size, len;
char *buf = read_object_file(oid, &type, &size);
+ struct signature_check sigc = { 0 };
struct strbuf sig = STRBUF_INIT;
if (!buf || type != OBJ_TAG)
@@ -502,10 +503,12 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
if (size == len)
; /* merely annotated */
- else if (verify_signed_buffer(buf, len, buf + len, size - len, &sig, NULL)) {
- if (!sig.len)
- strbuf_addstr(&sig, "gpg verification failed.\n");
- }
+ else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
+ !sigc.gpg_output)
+ strbuf_addstr(&sig, "gpg verification failed.\n");
+ else
+ strbuf_addstr(&sig, sigc.gpg_output);
+ signature_check_clear(&sigc);
if (!tag_number++) {
fmt_tag_signature(&tagbuf, &sig, buf, len);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 944ec77fe1..0b7222e718 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -20,6 +20,8 @@
#define TEST_FILEMODE 1
#endif
+#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
+
static int init_is_bare_repository = 0;
static int init_shared_repository = -1;
static const char *init_db_template_dir;
@@ -176,13 +178,36 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
return 1;
}
+void initialize_repository_version(int hash_algo)
+{
+ char repo_version_string[10];
+ int repo_version = GIT_REPO_VERSION;
+
+#ifndef ENABLE_SHA256
+ if (hash_algo != GIT_HASH_SHA1)
+ die(_("The hash algorithm %s is not supported in this build."), hash_algos[hash_algo].name);
+#endif
+
+ if (hash_algo != GIT_HASH_SHA1)
+ repo_version = GIT_REPO_VERSION_READ;
+
+ /* This forces creation of new config file */
+ xsnprintf(repo_version_string, sizeof(repo_version_string),
+ "%d", repo_version);
+ git_config_set("core.repositoryformatversion", repo_version_string);
+
+ if (hash_algo != GIT_HASH_SHA1)
+ git_config_set("extensions.objectformat",
+ hash_algos[hash_algo].name);
+}
+
static int create_default_files(const char *template_path,
- const char *original_git_dir)
+ const char *original_git_dir,
+ const struct repository_format *fmt)
{
struct stat st1;
struct strbuf buf = STRBUF_INIT;
char *path;
- char repo_version_string[10];
char junk[2];
int reinit;
int filemode;
@@ -244,10 +269,7 @@ static int create_default_files(const char *template_path,
exit(1);
}
- /* This forces creation of new config file */
- xsnprintf(repo_version_string, sizeof(repo_version_string),
- "%d", GIT_REPO_VERSION);
- git_config_set("core.repositoryformatversion", repo_version_string);
+ initialize_repository_version(fmt->hash_algo);
/* Check filemode trustability */
path = git_path_buf(&buf, "config");
@@ -340,12 +362,33 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
write_file(git_link, "gitdir: %s", git_dir);
}
+static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+{
+ const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
+ /*
+ * If we already have an initialized repo, don't allow the user to
+ * specify a different algorithm, as that could cause corruption.
+ * Otherwise, if the user has specified one on the command line, use it.
+ */
+ if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
+ die(_("attempt to reinitialize repository with different hash"));
+ else if (hash != GIT_HASH_UNKNOWN)
+ repo_fmt->hash_algo = hash;
+ else if (env) {
+ int env_algo = hash_algo_by_name(env);
+ if (env_algo == GIT_HASH_UNKNOWN)
+ die(_("unknown hash algorithm '%s'"), env);
+ repo_fmt->hash_algo = env_algo;
+ }
+}
+
int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, unsigned int flags)
+ const char *template_dir, int hash, unsigned int flags)
{
int reinit;
int exist_ok = flags & INIT_DB_EXIST_OK;
char *original_git_dir = real_pathdup(git_dir, 1);
+ struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
if (real_git_dir) {
struct stat st;
@@ -356,12 +399,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
if (!exist_ok && !stat(real_git_dir, &st))
die(_("%s already exists"), real_git_dir);
- set_git_dir(real_path(real_git_dir));
+ set_git_dir(real_git_dir, 1);
git_dir = get_git_dir();
separate_git_dir(git_dir, original_git_dir);
}
else {
- set_git_dir(real_path(git_dir));
+ set_git_dir(git_dir, 1);
git_dir = get_git_dir();
}
startup_info->have_repository = 1;
@@ -378,9 +421,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
* config file, so this will not fail. What we are catching
* is an attempt to reinitialize new repository with an old tool.
*/
- check_repository_format();
+ check_repository_format(&repo_fmt);
- reinit = create_default_files(template_dir, original_git_dir);
+ validate_hash_algorithm(&repo_fmt, hash);
+
+ reinit = create_default_files(template_dir, original_git_dir, &repo_fmt);
create_object_directory();
@@ -482,6 +527,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *work_tree;
const char *template_dir = NULL;
unsigned int flags = 0;
+ const char *object_format = NULL;
+ int hash_algo = GIT_HASH_UNKNOWN;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
N_("directory from which templates will be used")),
@@ -494,6 +541,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
+ OPT_STRING(0, "object-format", &object_format, N_("hash"),
+ N_("specify the hash algorithm to use")),
OPT_END()
};
@@ -546,6 +595,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
free(cwd);
}
+ if (object_format) {
+ hash_algo = hash_algo_by_name(object_format);
+ if (hash_algo == GIT_HASH_UNKNOWN)
+ die(_("unknown hash algorithm '%s'"), object_format);
+ }
+
if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
@@ -597,5 +652,5 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
UNLEAK(work_tree);
flags |= INIT_DB_EXIST_OK;
- return init_db(git_dir, real_git_dir, template_dir, flags);
+ return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
}
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index e3f8da13b6..6719ac198d 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -114,26 +114,16 @@ static int handle_is_ancestor(int argc, const char **argv)
static int handle_fork_point(int argc, const char **argv)
{
struct object_id oid;
- char *refname;
struct commit *derived, *fork_point;
const char *commitname;
- switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
- case 0:
- die("No such ref: '%s'", argv[0]);
- case 1:
- break; /* good */
- default:
- die("Ambiguous refname: '%s'", argv[0]);
- }
-
commitname = (argc == 2) ? argv[1] : "HEAD";
if (get_oid(commitname, &oid))
die("Not a valid object name: '%s'", commitname);
derived = lookup_commit_reference(the_repository, &oid);
- fork_point = get_fork_point(refname, derived);
+ fork_point = get_fork_point(argv[0], derived);
if (!fork_point)
return 1;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 02aa6ee480..dc7c58ce3f 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -880,7 +880,7 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
len = encode_in_pack_object_header(header, sizeof(header),
OBJ_REF_DELTA, size);
hashwrite(out, header, len);
- hashwrite(out, base_oid.hash, 20);
+ hashwrite(out, base_oid.hash, the_hash_algo->rawsz);
copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
return;
}
@@ -3469,9 +3469,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
- sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0);
+ sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
prepare_repo_settings(the_repository);
- if (!sparse && the_repository->settings.pack_use_sparse != -1)
+ if (sparse < 0)
sparse = the_repository->settings.pack_use_sparse;
reset_pack_idx_option(&pack_idx_opts);
diff --git a/builtin/pull.c b/builtin/pull.c
index 3e624d1e00..e42665b681 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -327,6 +327,22 @@ static enum rebase_type config_get_rebase(void)
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
+ if (opt_verbosity >= 0 &&
+ (!opt_ff || strcmp(opt_ff, "--ff-only"))) {
+ warning(_("Pulling without specifying how to reconcile divergent branches is\n"
+ "discouraged. You can squelch this message by running one of the following\n"
+ "commands sometime before your next pull:\n"
+ "\n"
+ " git config pull.rebase false # merge (the default strategy)\n"
+ " git config pull.rebase true # rebase\n"
+ " git config pull.ff only # fast-forward only\n"
+ "\n"
+ "You can replace \"git config\" with \"git config --global\" to set a default\n"
+ "preference for all repositories. You can also pass --rebase, --no-rebase,\n"
+ "or --ff-only on the command line to override the configured default per\n"
+ "invocation.\n"));
+ }
+
return REBASE_FALSE;
}
diff --git a/builtin/rebase.c b/builtin/rebase.c
index bff53d5d16..27a07d4e78 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -868,6 +868,7 @@ static int reset_head(struct object_id *oid, const char *action,
unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
+ init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
if (!detach_head)
unpack_tree_opts.reset = 1;
diff --git a/builtin/reset.c b/builtin/reset.c
index 18228c312e..4c634111bd 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -46,7 +46,7 @@ static inline int is_merge(void)
return !access(git_path_merge_head(the_repository), F_OK);
}
-static int reset_index(const struct object_id *oid, int reset_type, int quiet)
+static int reset_index(const char *ref, const struct object_id *oid, int reset_type, int quiet)
{
int i, nr = 0;
struct tree_desc desc[2];
@@ -60,6 +60,7 @@ static int reset_index(const struct object_id *oid, int reset_type, int quiet)
opts.dst_index = &the_index;
opts.fn = oneway_merge;
opts.merge = 1;
+ init_checkout_metadata(&opts.meta, ref, oid, NULL);
if (!quiet)
opts.verbose_update = 1;
switch (reset_type) {
@@ -418,11 +419,20 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
}
}
} else {
- int err = reset_index(&oid, reset_type, quiet);
+ struct object_id dummy;
+ char *ref = NULL;
+ int err;
+
+ dwim_ref(rev, strlen(rev), &dummy, &ref);
+ if (ref && !starts_with(ref, "refs/"))
+ ref = NULL;
+
+ err = reset_index(ref, &oid, reset_type, quiet);
if (reset_type == KEEP && !err)
- err = reset_index(&oid, MIXED, quiet);
+ err = reset_index(ref, &oid, MIXED, quiet);
if (err)
die(_("Could not reset index file to revision '%s'."), rev);
+ free(ref);
}
if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 7a00da8203..06056434ed 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -808,9 +808,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--show-superproject-working-tree")) {
- const char *superproject = get_superproject_working_tree();
- if (superproject)
- puts(superproject);
+ struct strbuf superproject = STRBUF_INIT;
+ if (get_superproject_working_tree(&superproject))
+ puts(superproject.buf);
+ strbuf_release(&superproject);
continue;
}
if (!strcmp(arg, "--show-prefix")) {
@@ -857,7 +858,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!gitdir && !prefix)
gitdir = ".git";
if (gitdir) {
- puts(real_path(gitdir));
+ struct strbuf realpath = STRBUF_INIT;
+ strbuf_realpath(&realpath, gitdir, 1);
+ puts(realpath.buf);
+ strbuf_release(&realpath);
continue;
}
}
diff --git a/builtin/stash.c b/builtin/stash.c
index 78af6ce564..6d586ef06d 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -702,6 +702,7 @@ static int list_stash(int argc, const char **argv, const char *prefix)
static int show_stat = 1;
static int show_patch;
+static int use_legacy_stash;
static int git_stash_config(const char *var, const char *value, void *cb)
{
@@ -713,7 +714,11 @@ static int git_stash_config(const char *var, const char *value, void *cb)
show_patch = git_config_bool(var, value);
return 0;
}
- return git_default_config(var, value, cb);
+ if (!strcmp(var, "stash.usebuiltin")) {
+ use_legacy_stash = !git_config_bool(var, value);
+ return 0;
+ }
+ return git_diff_basic_config(var, value, cb);
}
static int show_stash(int argc, const char **argv, const char *prefix)
@@ -750,7 +755,6 @@ static int show_stash(int argc, const char **argv, const char *prefix)
* any options.
*/
if (revision_args.argc == 1) {
- git_config(git_stash_config, NULL);
if (show_stat)
rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
@@ -1559,29 +1563,6 @@ static int save_stash(int argc, const char **argv, const char *prefix)
return ret;
}
-static int use_builtin_stash(void)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
- struct strbuf out = STRBUF_INIT;
- int ret, env = git_env_bool("GIT_TEST_STASH_USE_BUILTIN", -1);
-
- if (env != -1)
- return env;
-
- argv_array_pushl(&cp.args,
- "config", "--bool", "stash.usebuiltin", NULL);
- cp.git_cmd = 1;
- if (capture_command(&cp, &out, 6)) {
- strbuf_release(&out);
- return 1;
- }
-
- strbuf_trim(&out);
- ret = !strcmp("true", out.buf);
- strbuf_release(&out);
- return ret;
-}
-
int cmd_stash(int argc, const char **argv, const char *prefix)
{
pid_t pid = getpid();
@@ -1592,21 +1573,12 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
OPT_END()
};
- if (!use_builtin_stash()) {
- const char *path = mkpath("%s/git-legacy-stash",
- git_exec_path());
-
- if (sane_execvp(path, (char **)argv) < 0)
- die_errno(_("could not exec %s"), path);
- else
- BUG("sane_execvp() returned???");
- }
-
- prefix = setup_git_directory();
- trace_repo_setup(prefix);
- setup_work_tree();
+ git_config(git_stash_config, NULL);
- git_config(git_diff_basic_config, NULL);
+ if (use_legacy_stash ||
+ !git_env_bool("GIT_TEST_STASH_USE_BUILTIN", -1))
+ warning(_("the stash.useBuiltin support has been removed!\n"
+ "See its entry in 'git help config' for details."));
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 86a608eec1..1a4b391c88 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -444,19 +444,19 @@ static void for_each_listed_submodule(const struct module_list *list,
fn(list->entries[i], cb_data);
}
-struct cb_foreach {
+struct foreach_cb {
int argc;
const char **argv;
const char *prefix;
int quiet;
int recursive;
};
-#define CB_FOREACH_INIT { 0 }
+#define FOREACH_CB_INIT { 0 }
static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
void *cb_data)
{
- struct cb_foreach *info = cb_data;
+ struct foreach_cb *info = cb_data;
const char *path = list_item->name;
const struct object_id *ce_oid = &list_item->oid;
@@ -557,7 +557,7 @@ cleanup:
static int module_foreach(int argc, const char **argv, const char *prefix)
{
- struct cb_foreach info = CB_FOREACH_INIT;
+ struct foreach_cb info = FOREACH_CB_INIT;
struct pathspec pathspec;
struct module_list list = MODULE_LIST_INIT;
diff --git a/builtin/tag.c b/builtin/tag.c
index e0a4c25382..cc30d346f5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -231,8 +231,9 @@ static void create_tag(const struct object_id *object, const char *object_ref,
if (type <= OBJ_NONE)
die(_("bad object type."));
- if (type == OBJ_TAG && advice_nested_tag)
- advise(_(message_advice_nested_tag), tag, object_ref);
+ if (type == OBJ_TAG)
+ advise_if_enabled(ADVICE_NESTED_TAG, _(message_advice_nested_tag),
+ tag, object_ref);
strbuf_addf(&header,
"object %s\n"
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 24f22800f3..d99db35668 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -258,7 +258,7 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
const char *name;
struct child_process cp = CHILD_PROCESS_INIT;
struct argv_array child_env = ARGV_ARRAY_INIT;
@@ -330,9 +330,11 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- write_file(sb.buf, "%s", real_path(sb_git.buf));
+ strbuf_realpath(&realpath, sb_git.buf, 1);
+ write_file(sb.buf, "%s", realpath.buf);
+ strbuf_realpath(&realpath, get_git_common_dir(), 1);
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
- real_path(get_git_common_dir()), name);
+ realpath.buf, name);
/*
* This is to keep resolve_ref() happy. We need a valid HEAD
* or is_git_directory() will reject the directory. Any value which
@@ -418,6 +420,7 @@ done:
strbuf_release(&sb_repo);
strbuf_release(&sb_git);
strbuf_release(&sb_name);
+ strbuf_release(&realpath);
return ret;
}