summaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-20 05:14:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-20 05:14:36 +0000
commit09f61306ecfdf0e532c58460d8d868d50021e7db (patch)
treeb6f46cb23ce41cddcb6e1320d5c1c4bd5d69e899 /builtin
parentAdding debian version 1:2.43.0-1. (diff)
downloadgit-09f61306ecfdf0e532c58460d8d868d50021e7db.tar.xz
git-09f61306ecfdf0e532c58460d8d868d50021e7db.zip
Merging upstream version 1:2.45.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c50
-rw-r--r--builtin/am.c26
-rw-r--r--builtin/apply.c1
-rw-r--r--builtin/archive.c1
-rw-r--r--builtin/bisect.c18
-rw-r--r--builtin/blame.c7
-rw-r--r--builtin/branch.c81
-rw-r--r--builtin/bugreport.c10
-rw-r--r--builtin/cat-file.c39
-rw-r--r--builtin/checkout-index.c1
-rw-r--r--builtin/checkout.c192
-rw-r--r--builtin/clean.c22
-rw-r--r--builtin/clone.c187
-rw-r--r--builtin/column.c4
-rw-r--r--builtin/commit-graph.c5
-rw-r--r--builtin/commit-tree.c3
-rw-r--r--builtin/commit.c114
-rw-r--r--builtin/config.c44
-rw-r--r--builtin/credential-cache--daemon.c2
-rw-r--r--builtin/credential-cache.c5
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-files.c1
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c1
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/difftool.c1
-rw-r--r--builtin/fast-export.c4
-rw-r--r--builtin/fast-import.c189
-rw-r--r--builtin/fetch.c41
-rw-r--r--builtin/for-each-ref.c48
-rw-r--r--builtin/fsck.c7
-rw-r--r--builtin/fsmonitor--daemon.c5
-rw-r--r--builtin/gc.c117
-rw-r--r--builtin/get-tar-commit-id.c1
-rw-r--r--builtin/grep.c14
-rw-r--r--builtin/hash-object.c1
-rw-r--r--builtin/hook.c1
-rw-r--r--builtin/index-pack.c26
-rw-r--r--builtin/init-db.c17
-rw-r--r--builtin/interpret-trailers.c103
-rw-r--r--builtin/log.c42
-rw-r--r--builtin/ls-files.c14
-rw-r--r--builtin/ls-remote.c12
-rw-r--r--builtin/ls-tree.c17
-rw-r--r--builtin/mailinfo.c1
-rw-r--r--builtin/merge-base.c26
-rw-r--r--builtin/merge-file.c28
-rw-r--r--builtin/merge-recursive.c3
-rw-r--r--builtin/merge-tree.c59
-rw-r--r--builtin/merge.c77
-rw-r--r--builtin/mktag.c1
-rw-r--r--builtin/mv.c1
-rw-r--r--builtin/name-rev.c39
-rw-r--r--builtin/notes.c20
-rw-r--r--builtin/pack-objects.c186
-rw-r--r--builtin/pack-refs.c31
-rw-r--r--builtin/pull.c14
-rw-r--r--builtin/push.c48
-rw-r--r--builtin/range-diff.c1
-rw-r--r--builtin/read-tree.c7
-rw-r--r--builtin/rebase.c88
-rw-r--r--builtin/receive-pack.c87
-rw-r--r--builtin/reflog.c44
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/repack.c20
-rw-r--r--builtin/replay.c446
-rw-r--r--builtin/rerere.c1
-rw-r--r--builtin/reset.c11
-rw-r--r--builtin/rev-list.c21
-rw-r--r--builtin/rev-parse.c43
-rw-r--r--builtin/revert.c40
-rw-r--r--builtin/rm.c1
-rw-r--r--builtin/send-pack.c35
-rw-r--r--builtin/shortlog.c1
-rw-r--r--builtin/show-ref.c11
-rw-r--r--builtin/sparse-checkout.c15
-rw-r--r--builtin/stash.c14
-rw-r--r--builtin/stripspace.c4
-rw-r--r--builtin/submodule--helper.c89
-rw-r--r--builtin/tag.c95
-rw-r--r--builtin/unpack-objects.c12
-rw-r--r--builtin/update-ref.c27
-rw-r--r--builtin/upload-pack.c4
-rw-r--r--builtin/var.c2
-rw-r--r--builtin/verify-commit.c2
-rw-r--r--builtin/verify-tag.c1
-rw-r--r--builtin/worktree.c96
87 files changed, 2116 insertions, 1118 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 5126d2e..b7d3ff1 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -12,14 +12,11 @@
#include "dir.h"
#include "gettext.h"
#include "pathspec.h"
-#include "exec-cmd.h"
-#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
#include "path.h"
#include "preload-index.h"
#include "diff.h"
-#include "diffcore.h"
#include "read-cache.h"
#include "repository.h"
#include "revision.h"
@@ -118,7 +115,7 @@ static int refresh(int verbose, const struct pathspec *pathspec)
int i, ret = 0;
char *skip_worktree_seen = NULL;
struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
- int flags = REFRESH_IGNORE_SKIP_WORKTREE |
+ unsigned int flags = REFRESH_IGNORE_SKIP_WORKTREE |
(verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
seen = xcalloc(pathspec->nr, 1);
@@ -153,7 +150,7 @@ static int refresh(int verbose, const struct pathspec *pathspec)
int interactive_add(const char **argv, const char *prefix, int patch)
{
struct pathspec pathspec;
- int unused;
+ int unused, ret;
if (!git_config_get_bool("add.interactive.usebuiltin", &unused))
warning(_("the add.interactive.useBuiltin setting has been removed!\n"
@@ -166,9 +163,12 @@ int interactive_add(const char **argv, const char *prefix, int patch)
prefix, argv);
if (patch)
- return !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+ ret = !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
else
- return !!run_add_i(the_repository, &pathspec);
+ ret = !!run_add_i(the_repository, &pathspec);
+
+ clear_pathspec(&pathspec);
+ return ret;
}
static int edit_patch(int argc, const char **argv, const char *prefix)
@@ -313,9 +313,9 @@ static void check_embedded_repo(const char *path)
strbuf_strip_suffix(&name, "/");
warning(_("adding embedded git repository: %s"), name.buf);
- if (!adviced_on_embedded_repo &&
- advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {
- advise(embedded_advice, name.buf, name.buf);
+ if (!adviced_on_embedded_repo) {
+ advise_if_enabled(ADVICE_ADD_EMBEDDED_REPO,
+ embedded_advice, name.buf, name.buf);
adviced_on_embedded_repo = 1;
}
@@ -331,10 +331,8 @@ static int add_files(struct dir_struct *dir, int flags)
fprintf(stderr, _(ignore_error));
for (i = 0; i < dir->ignored_nr; i++)
fprintf(stderr, "%s\n", dir->ignored[i]->name);
- if (advice_enabled(ADVICE_ADD_IGNORED_FILE))
- advise(_("Use -f if you really want to add them.\n"
- "Turn this message off by running\n"
- "\"git config advice.addIgnoredFile false\""));
+ advise_if_enabled(ADVICE_ADD_IGNORED_FILE,
+ _("Use -f if you really want to add them."));
exit_status = 1;
}
@@ -373,6 +371,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int add_new_files;
int require_pathspec;
char *seen = NULL;
+ char *ps_matched = NULL;
struct lock_file lock_file = LOCK_INIT;
git_config(add_config, NULL);
@@ -424,7 +423,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
*/
- parse_pathspec(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);
@@ -433,7 +432,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
- parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, pathspec_from_file, pathspec_file_nul);
@@ -443,10 +442,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (require_pathspec && pathspec.nr == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
- if (advice_enabled(ADVICE_ADD_EMPTY_PATHSPEC))
- advise( _("Maybe you wanted to say 'git add .'?\n"
- "Turn this message off by running\n"
- "\"git config advice.addEmptyPathspec false\""));
+ advise_if_enabled(ADVICE_ADD_EMPTY_PATHSPEC,
+ _("Maybe you wanted to say 'git add .'?"));
return 0;
}
@@ -504,7 +501,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
@@ -551,12 +549,17 @@ int cmd_add(int argc, const char **argv, const char *prefix)
begin_odb_transaction();
+ ps_matched = xcalloc(pathspec.nr, 1);
if (add_renormalize)
exit_status |= renormalize_tracked_files(&pathspec, flags);
else
exit_status |= add_files_to_cache(the_repository, prefix,
- &pathspec, include_sparse,
- flags);
+ &pathspec, ps_matched,
+ include_sparse, flags);
+
+ if (take_worktree_changes && !add_renormalize && !ignore_add_errors &&
+ report_path_error(ps_matched, &pathspec))
+ exit(128);
if (add_new_files)
exit_status |= add_files(&dir, flags);
@@ -570,6 +573,7 @@ finish:
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new index file"));
+ free(ps_matched);
dir_clear(&dir);
clear_pathspec(&pathspec);
return exit_status;
diff --git a/builtin/am.c b/builtin/am.c
index 9f084d5..022cae2 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -10,7 +10,6 @@
#include "config.h"
#include "editor.h"
#include "environment.h"
-#include "exec-cmd.h"
#include "gettext.h"
#include "hex.h"
#include "parse-options.h"
@@ -24,7 +23,6 @@
#include "refs.h"
#include "commit.h"
#include "diff.h"
-#include "diffcore.h"
#include "unpack-trees.h"
#include "branch.h"
#include "object-name.h"
@@ -35,11 +33,9 @@
#include "log-tree.h"
#include "notes-utils.h"
#include "rerere.h"
-#include "prompt.h"
#include "mailinfo.h"
#include "apply.h"
#include "string-list.h"
-#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "repository.h"
@@ -1154,19 +1150,23 @@ static const char *msgnum(const struct am_state *state)
static void NORETURN die_user_resolve(const struct am_state *state)
{
if (state->resolvemsg) {
- printf_ln("%s", state->resolvemsg);
+ advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", state->resolvemsg);
} else {
const char *cmdline = state->interactive ? "git am -i" : "git am";
+ struct strbuf sb = STRBUF_INIT;
- printf_ln(_("When you have resolved this problem, run \"%s --continue\"."), cmdline);
- printf_ln(_("If you prefer to skip this patch, run \"%s --skip\" instead."), cmdline);
+ strbuf_addf(&sb, _("When you have resolved this problem, run \"%s --continue\".\n"), cmdline);
+ strbuf_addf(&sb, _("If you prefer to skip this patch, run \"%s --skip\" instead.\n"), cmdline);
if (advice_enabled(ADVICE_AM_WORK_DIR) &&
is_empty_or_missing_file(am_path(state, "patch")) &&
!repo_index_has_changes(the_repository, NULL, NULL))
- printf_ln(_("To record the empty patch as an empty commit, run \"%s --allow-empty\"."), cmdline);
+ strbuf_addf(&sb, _("To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"), cmdline);
- printf_ln(_("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
+ strbuf_addf(&sb, _("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
+
+ advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", sb.buf);
+ strbuf_release(&sb);
}
exit(128);
@@ -1290,7 +1290,7 @@ static int parse_mail(struct am_state *state, const char *mail)
strbuf_addstr(&msg, "\n\n");
strbuf_addbuf(&msg, &mi.log_message);
- strbuf_stripspace(&msg, '\0');
+ strbuf_stripspace(&msg, NULL);
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
@@ -1998,8 +1998,8 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
opts.fn = twoway_merge;
- init_tree_desc(&t[0], head->buffer, head->size);
- init_tree_desc(&t[1], remote->buffer, remote->size);
+ init_tree_desc(&t[0], &head->object.oid, head->buffer, head->size);
+ init_tree_desc(&t[1], &remote->object.oid, remote->buffer, remote->size);
if (unpack_trees(2, t, &opts)) {
rollback_lock_file(&lock_file);
@@ -2033,7 +2033,7 @@ static int merge_tree(struct tree *tree)
opts.dst_index = &the_index;
opts.merge = 1;
opts.fn = oneway_merge;
- init_tree_desc(&t[0], tree->buffer, tree->size);
+ init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, t, &opts)) {
rollback_lock_file(&lock_file);
diff --git a/builtin/apply.c b/builtin/apply.c
index c18b7ea..861a019 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,6 +1,5 @@
#include "builtin.h"
#include "gettext.h"
-#include "parse-options.h"
#include "repository.h"
#include "apply.h"
diff --git a/builtin/archive.c b/builtin/archive.c
index 90761fd..15ee1ec 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -9,7 +9,6 @@
#include "parse-options.h"
#include "pkt-line.h"
#include "repository.h"
-#include "sideband.h"
static void create_output_file(const char *output_file)
{
diff --git a/builtin/bisect.c b/builtin/bisect.c
index 35938b0..f69c3f7 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -7,7 +7,6 @@
#include "parse-options.h"
#include "bisect.h"
#include "refs.h"
-#include "dir.h"
#include "strvec.h"
#include "run-command.h"
#include "oid-array.h"
@@ -17,7 +16,6 @@
#include "revision.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 GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
@@ -233,11 +231,10 @@ static int bisect_reset(const char *commit)
struct strbuf branch = STRBUF_INIT;
if (!commit) {
- if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
+ if (!strbuf_read_file(&branch, git_path_bisect_start(), 0))
printf(_("We are not bisecting.\n"));
- return 0;
- }
- strbuf_rtrim(&branch);
+ else
+ strbuf_rtrim(&branch);
} else {
struct object_id oid;
@@ -246,7 +243,7 @@ static int bisect_reset(const char *commit)
strbuf_addstr(&branch, commit);
}
- if (!ref_exists("BISECT_HEAD")) {
+ if (branch.len && !ref_exists("BISECT_HEAD")) {
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
@@ -921,7 +918,6 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
const char *state;
int i, verify_expected = 1;
struct object_id oid, expected;
- struct strbuf buf = STRBUF_INIT;
struct oid_array revs = OID_ARRAY_INIT;
if (!argc)
@@ -976,10 +972,8 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
oid_array_append(&revs, &commit->object.oid);
}
- if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
- get_oid_hex(buf.buf, &expected) < 0)
+ if (read_ref("BISECT_EXPECTED_REV", &expected))
verify_expected = 0; /* Ignore invalid file contents */
- strbuf_release(&buf);
for (i = 0; i < revs.nr; i++) {
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
@@ -988,7 +982,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
}
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
unlink_or_warn(git_path_bisect_ancestors_ok());
- unlink_or_warn(git_path_bisect_expected_rev());
+ delete_ref(NULL, "BISECT_EXPECTED_REV", NULL, REF_NO_DEREF);
verify_expected = 0;
}
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 9c987d6..9aa7468 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -25,7 +25,6 @@
#include "userdiff.h"
#include "line-range.h"
#include "line-log.h"
-#include "dir.h"
#include "progress.h"
#include "object-name.h"
#include "object-store-ll.h"
@@ -317,7 +316,7 @@ static const char *format_time(timestamp_t time, const char *tz_str,
size_t time_width;
int tz;
tz = atoi(tz_str);
- time_str = show_date(time, tz, &blame_date_mode);
+ time_str = show_date(time, tz, blame_date_mode);
strbuf_addstr(&time_buf, time_str);
/*
* Add space paddings to time_buf to display a fixed width
@@ -748,6 +747,8 @@ static int git_blame_config(const char *var, const char *value,
}
if (!strcmp(var, "blame.coloring")) {
+ if (!value)
+ return config_error_nonbool(var);
if (!strcmp(value, "repeatedLines")) {
coloring_mode |= OUTPUT_COLOR_LINE;
} else if (!strcmp(value, "highlightRecent")) {
@@ -1028,7 +1029,7 @@ parse_done:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
case DATE_STRFTIME:
- blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
+ blame_date_width = strlen(show_date(0, 0, blame_date_mode)) + 1; /* add the null */
break;
}
blame_date_width -= 1; /* strip the null */
diff --git a/builtin/branch.c b/builtin/branch.c
index e7ee9bd..dd3e3a7 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -17,16 +17,14 @@
#include "remote.h"
#include "parse-options.h"
#include "branch.h"
-#include "diff.h"
#include "path.h"
-#include "revision.h"
#include "string-list.h"
#include "column.h"
#include "utf8.h"
-#include "wt-status.h"
#include "ref-filter.h"
#include "worktree.h"
#include "help.h"
+#include "advice.h"
#include "commit-reach.h"
static const char * const builtin_branch_usage[] = {
@@ -45,7 +43,6 @@ static const char *head;
static struct object_id head_oid;
static int recurse_submodules = 0;
static int submodule_propagate_branches = 0;
-static int omit_empty = 0;
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
@@ -161,6 +158,8 @@ static int branch_merged(int kind, const char *name,
merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
reference_rev) : 0;
+ if (merged < 0)
+ exit(128);
/*
* After the safety valve is fully redefined to "check with
@@ -169,9 +168,13 @@ static int branch_merged(int kind, const char *name,
* any of the following code, but during the transition period,
* a gentle reminder is in order.
*/
- if ((head_rev != reference_rev) &&
- (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
- if (merged)
+ if (head_rev != reference_rev) {
+ int expect = head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0;
+ if (expect < 0)
+ exit(128);
+ if (expect == merged)
+ ; /* okay */
+ else if (merged)
warning(_("deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD"),
name, reference_name);
@@ -194,9 +197,10 @@ static int check_branch_commit(const char *branchname, const char *refname,
return -1;
}
if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
- error(_("the branch '%s' is not fully merged.\n"
- "If you are sure you want to delete it, "
- "run 'git branch -D %s'"), branchname, branchname);
+ error(_("the branch '%s' is not fully merged"), branchname);
+ advise_if_enabled(ADVICE_FORCE_DELETE_BRANCH,
+ _("If you are sure you want to delete it, "
+ "run 'git branch -D %s'"), branchname);
return -1;
}
return 0;
@@ -438,8 +442,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
{
int i;
struct ref_array array;
- struct strbuf out = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
int maxwidth = 0;
const char *remote_prefix = "";
char *to_free = NULL;
@@ -469,24 +471,27 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
filter_ahead_behind(the_repository, format, &array);
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&err);
- strbuf_reset(&out);
- if (format_ref_array_item(array.items[i], format, &out, &err))
- die("%s", err.buf);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- /* format to a string_list to let print_columns() do its job */
+ if (column_active(colopts)) {
+ struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
+
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+
+ for (i = 0; i < array.nr; i++) {
+ strbuf_reset(&err);
+ strbuf_reset(&out);
+ if (format_ref_array_item(array.items[i], format, &out, &err))
+ die("%s", err.buf);
+
+ /* format to a string_list to let print_columns() do its job */
string_list_append(output, out.buf);
- } else {
- fwrite(out.buf, 1, out.len, stdout);
- if (out.len || !omit_empty)
- putchar('\n');
}
+
+ strbuf_release(&err);
+ strbuf_release(&out);
+ } else {
+ print_formatted_ref_array(&array, format);
}
- strbuf_release(&err);
- strbuf_release(&out);
ref_array_clear(&array);
free(to_free);
}
@@ -577,8 +582,12 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
*/
if (ref_exists(oldref.buf))
recovery = 1;
- else
- die(_("invalid branch name: '%s'"), oldname);
+ else {
+ int code = die_message(_("invalid branch name: '%s'"), oldname);
+ advise_if_enabled(ADVICE_REF_SYNTAX,
+ _("See `man git check-ref-format`"));
+ exit(code);
+ }
}
for (int i = 0; worktrees[i]; i++) {
@@ -668,18 +677,18 @@ static int edit_branch_description(const char *branch_name)
exists = !read_branch_desc(&buf, branch_name);
if (!buf.len || buf.buf[buf.len-1] != '\n')
strbuf_addch(&buf, '\n');
- strbuf_commented_addf(&buf, comment_line_char,
+ strbuf_commented_addf(&buf, comment_line_str,
_("Please edit the description for the branch\n"
" %s\n"
- "Lines starting with '%c' will be stripped.\n"),
- branch_name, comment_line_char);
+ "Lines starting with '%s' will be stripped.\n"),
+ branch_name, comment_line_str);
write_file_buf(edit_description(), buf.buf, buf.len);
strbuf_reset(&buf);
if (launch_editor(edit_description(), &buf, NULL)) {
strbuf_release(&buf);
return -1;
}
- strbuf_stripspace(&buf, comment_line_char);
+ strbuf_stripspace(&buf, comment_line_str);
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
@@ -737,7 +746,7 @@ 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_BOOL(0, "omit-empty", &omit_empty,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
N_("do not output a newline after empty formatted refs")),
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),
@@ -767,7 +776,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_branch_usage, options);
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_branch_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
track = git_branch_track;
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 3106e56..25f860a 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -64,7 +64,8 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
}
static const char * const bugreport_usage[] = {
- N_("git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ N_("git bugreport [(-o | --output-directory) <path>]\n"
+ " [(-s | --suffix) <format> | --no-suffix]\n"
" [--diagnose[=<mode>]]"),
NULL
};
@@ -138,8 +139,11 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
strbuf_complete(&report_path, '/');
output_path_len = report_path.len;
- strbuf_addstr(&report_path, "git-bugreport-");
- strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+ strbuf_addstr(&report_path, "git-bugreport");
+ if (option_suffix) {
+ strbuf_addch(&report_path, '-');
+ strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+ }
strbuf_addstr(&report_path, ".txt");
switch (safe_create_leading_directories(report_path.buf)) {
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index ea8ad60..0c948f4 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -15,7 +15,6 @@
#include "parse-options.h"
#include "userdiff.h"
#include "streaming.h"
-#include "tree-walk.h"
#include "oid-array.h"
#include "packfile.h"
#include "object-file.h"
@@ -107,7 +106,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
struct object_info oi = OBJECT_INFO_INIT;
struct strbuf sb = STRBUF_INIT;
unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
- unsigned get_oid_flags = GET_OID_RECORD_PATH | GET_OID_ONLY_TO_DIE;
+ unsigned get_oid_flags =
+ GET_OID_RECORD_PATH |
+ GET_OID_ONLY_TO_DIE |
+ GET_OID_HASH_ANY;
const char *path = force_path;
const int opt_cw = (opt == 'c' || opt == 'w');
if (!path && opt_cw)
@@ -222,8 +224,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
&type,
&size);
const char *target;
+
+ if (!buffer)
+ die(_("unable to read %s"), oid_to_hex(&oid));
+
if (!skip_prefix(buffer, "object ", &target) ||
- get_oid_hex(target, &blob_oid))
+ get_oid_hex_algop(target, &blob_oid,
+ &hash_algos[oid.algo]))
die("%s not a valid tag", oid_to_hex(&oid));
free(buffer);
} else
@@ -307,8 +314,8 @@ static int is_atom(const char *atom, const char *s, int slen)
return alen == slen && !memcmp(atom, s, alen);
}
-static void expand_atom(struct strbuf *sb, const char *atom, int len,
- struct expand_data *data)
+static int expand_atom(struct strbuf *sb, const char *atom, int len,
+ struct expand_data *data)
{
if (is_atom("objectname", atom, len)) {
if (!data->mark_query)
@@ -340,7 +347,8 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
strbuf_addstr(sb,
oid_to_hex(&data->delta_base_oid));
} else
- die("unknown format element: %.*s", len, atom);
+ return 0;
+ return 1;
}
static void expand_format(struct strbuf *sb, const char *start,
@@ -351,12 +359,11 @@ static void expand_format(struct strbuf *sb, const char *start,
if (skip_prefix(start, "%", &start) || *start != '(')
strbuf_addch(sb, '%');
- else if (!(end = strchr(start + 1, ')')))
- die("format element '%s' does not end in ')'", start);
- else {
- expand_atom(sb, start + 1, end - start - 1, data);
+ else if ((end = strchr(start + 1, ')')) &&
+ expand_atom(sb, start + 1, end - start - 1, data))
start = end + 1;
- }
+ else
+ strbuf_expand_bad_format(start, "cat-file");
}
}
@@ -417,6 +424,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
contents = repo_read_object_file(the_repository, oid, &type,
&size);
+ if (!contents)
+ die("object %s disappeared", oid_to_hex(oid));
if (use_mailmap) {
size_t s = size;
@@ -424,8 +433,6 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
size = cast_size_t_to_ulong(s);
}
- if (!contents)
- die("object %s disappeared", oid_to_hex(oid));
if (type != data->type)
die("object %s changed type!?", oid_to_hex(oid));
if (data->info.sizep && size != data->size && !use_mailmap)
@@ -482,6 +489,8 @@ static void batch_object_write(const char *obj_name,
buf = repo_read_object_file(the_repository, &data->oid, &data->type,
&data->size);
+ if (!buf)
+ die(_("unable to read %s"), oid_to_hex(&data->oid));
buf = replace_idents_using_mailmap(buf, &s);
data->size = cast_size_t_to_ulong(s);
@@ -512,7 +521,9 @@ static void batch_one_object(const char *obj_name,
struct expand_data *data)
{
struct object_context ctx;
- int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
+ int flags =
+ GET_OID_HASH_ANY |
+ (opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0);
enum get_oid_result result;
result = get_oid_with_context(the_repository, obj_name,
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 3b68b47..2e086a2 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -7,7 +7,6 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
-#include "dir.h"
#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f02434b..71e6036 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,7 +1,6 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
-#include "blob.h"
#include "branch.h"
#include "cache-tree.h"
#include "checkout.h"
@@ -27,10 +26,8 @@
#include "remote.h"
#include "resolve-undo.h"
#include "revision.h"
-#include "run-command.h"
#include "setup.h"
#include "submodule.h"
-#include "submodule-config.h"
#include "symlinks.h"
#include "trace2.h"
#include "tree.h"
@@ -94,7 +91,7 @@ struct checkout_opts {
int new_branch_log;
enum branch_track track;
struct diff_options diff_options;
- char *conflict_style;
+ int conflict_style;
int branch_exists;
const char *prefix;
@@ -103,6 +100,8 @@ struct checkout_opts {
struct tree *source_tree;
};
+#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
+
struct branch_info {
char *name; /* The short name used */
char *path; /* The full name of a real branch */
@@ -254,7 +253,8 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
}
static int checkout_merged(int pos, const struct checkout *state,
- int *nr_checkouts, struct mem_pool *ce_mem_pool)
+ int *nr_checkouts, struct mem_pool *ce_mem_pool,
+ int conflict_style)
{
struct cache_entry *ce = the_index.cache[pos];
const char *path = ce->name;
@@ -265,7 +265,7 @@ static int checkout_merged(int pos, const struct checkout *state,
mmbuffer_t result_buf;
struct object_id threeway[3];
unsigned mode = 0;
- struct ll_merge_options ll_opts;
+ struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
int renormalize = 0;
memset(threeway, 0, sizeof(threeway));
@@ -287,9 +287,9 @@ static int checkout_merged(int pos, const struct checkout *state,
read_mmblob(&ours, &threeway[1]);
read_mmblob(&theirs, &threeway[2]);
- memset(&ll_opts, 0, sizeof(ll_opts));
git_config_get_bool("merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
+ ll_opts.conflict_style = conflict_style;
merge_status = ll_merge(&result_buf, path, &ancestor, "base",
&ours, "ours", &theirs, "theirs",
state->istate, &ll_opts);
@@ -420,7 +420,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
else if (opts->merge)
errs |= checkout_merged(pos, &state,
&nr_unmerged,
- &ce_mem_pool);
+ &ce_mem_pool,
+ opts->conflict_style);
pos = skip_same_name(ce, pos) - 1;
}
}
@@ -707,8 +708,9 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
init_checkout_metadata(&opts.meta, info->refname,
info->commit ? &info->commit->object.oid : null_oid(),
NULL);
- parse_tree(tree);
- init_tree_desc(&tree_desc, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ return 128;
+ init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size);
switch (unpack_trees(1, &tree_desc, &opts)) {
case -2:
*writeout_error = 1;
@@ -786,9 +788,15 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (new_branch_info->commit)
BUG("'switch --orphan' should never accept a commit as starting point");
new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
- } else
+ if (!new_tree)
+ BUG("unable to read empty tree");
+ } else {
new_tree = repo_get_commit_tree(the_repository,
new_branch_info->commit);
+ if (!new_tree)
+ return error(_("unable to read tree (%s)"),
+ oid_to_hex(&new_branch_info->commit->object.oid));
+ }
if (opts->discard_changes) {
ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
@@ -822,10 +830,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
die(_("unable to parse commit %s"),
oid_to_hex(old_commit_oid));
- init_tree_desc(&trees[0], tree->buffer, tree->size);
- parse_tree(new_tree);
+ init_tree_desc(&trees[0], &tree->object.oid,
+ tree->buffer, tree->size);
+ if (parse_tree(new_tree) < 0)
+ exit(128);
tree = new_tree;
- init_tree_desc(&trees[1], tree->buffer, tree->size);
+ init_tree_desc(&trees[1], &tree->object.oid,
+ tree->buffer, tree->size);
ret = unpack_trees(2, trees, &topts);
clear_unpack_trees_porcelain(&topts);
@@ -871,7 +882,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
* entries in the index.
*/
- add_files_to_cache(the_repository, NULL, NULL, 0, 0);
+ add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
+ 0);
init_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);
@@ -890,6 +902,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
o.branch1 = new_branch_info->name;
o.branch2 = "local";
+ o.conflict_style = opts->conflict_style;
ret = merge_trees(&o,
new_tree,
work,
@@ -1023,7 +1036,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
remove_branch_state(the_repository, !opts->quiet);
strbuf_release(&msg);
if (!opts->quiet &&
- (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
+ !opts->force_detach &&
+ (new_branch_info->path || !strcmp(new_branch_info->name, "HEAD")))
report_tracking(new_branch_info);
}
@@ -1202,6 +1216,8 @@ static int git_checkout_config(const char *var, const char *value,
struct checkout_opts *opts = cb;
if (!strcmp(var, "diff.ignoresubmodules")) {
+ if (!value)
+ return config_error_nonbool(var);
handle_ignore_submodules_arg(&opts->diff_options, value);
return 0;
}
@@ -1225,7 +1241,9 @@ static void setup_new_branch_info_and_source_tree(
struct tree **source_tree = &opts->source_tree;
struct object_id branch_rev;
- new_branch_info->name = xstrdup(arg);
+ /* treat '@' as a shortcut for 'HEAD' */
+ new_branch_info->name = !strcmp(arg, "@") ? xstrdup("HEAD") :
+ xstrdup(arg);
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&
@@ -1239,10 +1257,15 @@ static void setup_new_branch_info_and_source_tree(
if (!new_branch_info->commit) {
/* not a commit */
*source_tree = parse_tree_indirect(rev);
+ if (!*source_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(rev));
} else {
parse_commit_or_die(new_branch_info->commit);
*source_tree = repo_get_commit_tree(the_repository,
new_branch_info->commit);
+ if (!*source_tree)
+ die(_("unable to read tree (%s)"),
+ oid_to_hex(&new_branch_info->commit->object.oid));
}
}
@@ -1516,6 +1539,26 @@ static void die_if_some_operation_in_progress(void)
wt_status_state_free_buffers(&state);
}
+/*
+ * die if attempting to checkout an existing branch that is in use
+ * in another worktree, unless ignore-other-wortrees option is given.
+ * The check is bypassed when the branch is already the current one,
+ * as it will not make things any worse.
+ */
+static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
+ const char *full_ref)
+{
+ int flags;
+ char *head_ref;
+
+ if (opts->ignore_other_worktrees)
+ return;
+ head_ref = resolve_refdup("HEAD", 0, NULL, &flags);
+ if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
+ die_if_checked_out(full_ref, 1);
+ free(head_ref);
+}
+
static int checkout_branch(struct checkout_opts *opts,
struct branch_info *new_branch_info)
{
@@ -1576,14 +1619,15 @@ static int checkout_branch(struct checkout_opts *opts,
if (!opts->can_switch_when_in_progress)
die_if_some_operation_in_progress();
- if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
- !opts->ignore_other_worktrees) {
- int flag;
- char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
- if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new_branch_info->path)))
- die_if_checked_out(new_branch_info->path, 1);
- free(head_ref);
+ /* "git checkout <branch>" */
+ if (new_branch_info->path && !opts->force_detach && !opts->new_branch)
+ die_if_switching_to_a_branch_in_use(opts, new_branch_info->path);
+
+ /* "git checkout -B <branch>" */
+ if (opts->new_branch_force) {
+ char *full_ref = xstrfmt("refs/heads/%s", opts->new_branch);
+ die_if_switching_to_a_branch_in_use(opts, full_ref);
+ free(full_ref);
}
if (!new_branch_info->commit && opts->new_branch) {
@@ -1597,6 +1641,24 @@ static int checkout_branch(struct checkout_opts *opts,
return switch_branches(opts, new_branch_info);
}
+static int parse_opt_conflict(const struct option *o, const char *arg, int unset)
+{
+ struct checkout_opts *opts = o->value;
+
+ if (unset) {
+ opts->conflict_style = -1;
+ return 0;
+ }
+ opts->conflict_style = parse_conflict_style_name(arg);
+ if (opts->conflict_style < 0)
+ return error(_("unknown conflict style '%s'"), arg);
+ /* --conflict overrides a previous --no-merge */
+ if (!opts->merge)
+ opts->merge = -1;
+
+ return 0;
+}
+
static struct option *add_common_options(struct checkout_opts *opts,
struct option *prevopts)
{
@@ -1607,8 +1669,9 @@ static struct option *add_common_options(struct checkout_opts *opts,
PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
- OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
- N_("conflict style (merge, diff3, or zdiff3)")),
+ OPT_CALLBACK(0, "conflict", opts, N_("style"),
+ N_("conflict style (merge, diff3, or zdiff3)"),
+ parse_opt_conflict),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
@@ -1627,7 +1690,7 @@ static struct option *add_common_switch_branch_options(
parse_opt_tracking_mode),
OPT__FORCE(&opts->force, N_("force checkout (throw away local modifications)"),
PARSE_OPT_NOCOMPLETE),
- OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
+ OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unborn branch")),
OPT_BOOL_F(0, "overwrite-ignore", &opts->overwrite_ignore,
N_("update ignored files (default)"),
PARSE_OPT_NOCOMPLETE),
@@ -1667,10 +1730,11 @@ static char cb_option = 'b';
static int checkout_main(int argc, const char **argv, const char *prefix,
struct checkout_opts *opts, struct option *options,
- const char * const usagestr[],
- struct branch_info *new_branch_info)
+ const char * const usagestr[])
{
int parseopt_flags = 0;
+ struct branch_info new_branch_info = { 0 };
+ int ret;
opts->overwrite_ignore = 1;
opts->prefix = prefix;
@@ -1699,15 +1763,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->show_progress = isatty(2);
}
- if (opts->conflict_style) {
- struct key_value_info kvi = KVI_INIT;
- struct config_context ctx = {
- .kvi = &kvi,
- };
- opts->merge = 1; /* implied */
- git_xmerge_config("merge.conflictstyle", opts->conflict_style,
- &ctx, NULL);
- }
+ /* --conflicts implies --merge */
+ if (opts->merge == -1)
+ opts->merge = opts->conflict_style >= 0;
+
if (opts->force) {
opts->discard_changes = 1;
opts->ignore_unmerged_opt = "--force";
@@ -1786,7 +1845,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->track == BRANCH_TRACK_UNSPECIFIED &&
!opts->new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- new_branch_info, opts, &rev);
+ &new_branch_info, opts, &rev);
argv += n;
argc -= n;
} else if (!opts->accept_ref && opts->from_treeish) {
@@ -1795,7 +1854,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
die(_("could not resolve %s"), opts->from_treeish);
- setup_new_branch_info_and_source_tree(new_branch_info,
+ setup_new_branch_info_and_source_tree(&new_branch_info,
opts, &rev,
opts->from_treeish);
@@ -1815,7 +1874,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
* Try to give more helpful suggestion.
* new_branch && argc > 1 will be caught later.
*/
- if (opts->new_branch && argc == 1 && !new_branch_info->commit)
+ if (opts->new_branch && argc == 1 && !new_branch_info.commit)
die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
argv[0], opts->new_branch);
@@ -1865,14 +1924,21 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, new_branch_info);
+ ret = checkout_paths(opts, &new_branch_info);
else
- return checkout_branch(opts, new_branch_info);
+ ret = checkout_branch(opts, &new_branch_info);
+
+ branch_info_release(&new_branch_info);
+ clear_pathspec(&opts->pathspec);
+ free(opts->pathspec_from_file);
+ free(options);
+
+ return ret;
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option checkout_options[] = {
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -1885,10 +1951,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.switch_branch_doing_nothing_is_ok = 1;
opts.only_merge_on_switching_branches = 0;
@@ -1916,18 +1979,13 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
options = add_common_switch_branch_options(&opts, options);
options = add_checkout_path_options(&opts, options);
- ret = checkout_main(argc, argv, prefix, &opts,
- options, checkout_usage, &new_branch_info);
- branch_info_release(&new_branch_info);
- clear_pathspec(&opts.pathspec);
- free(opts.pathspec_from_file);
- FREE_AND_NULL(options);
- return ret;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ checkout_usage);
}
int cmd_switch(int argc, const char **argv, const char *prefix)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options = NULL;
struct option switch_options[] = {
OPT_STRING('c', "create", &opts.new_branch, N_("branch"),
@@ -1940,10 +1998,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
N_("throw away local modifications")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.accept_ref = 1;
opts.accept_pathspec = 0;
@@ -1960,16 +2015,13 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
cb_option = 'c';
- ret = checkout_main(argc, argv, prefix, &opts,
- options, switch_branch_usage, &new_branch_info);
- branch_info_release(&new_branch_info);
- FREE_AND_NULL(options);
- return ret;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ switch_branch_usage);
}
int cmd_restore(int argc, const char **argv, const char *prefix)
{
- struct checkout_opts opts;
+ struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option restore_options[] = {
OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
@@ -1983,10 +2035,7 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
OPT_END()
};
- int ret;
- struct branch_info new_branch_info = { 0 };
- memset(&opts, 0, sizeof(opts));
opts.accept_ref = 0;
opts.accept_pathspec = 1;
opts.empty_pathspec_ok = 0;
@@ -1999,9 +2048,6 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
options = add_common_options(&opts, options);
options = add_checkout_path_options(&opts, options);
- ret = checkout_main(argc, argv, prefix, &opts,
- options, restore_usage, &new_branch_info);
- branch_info_release(&new_branch_info);
- FREE_AND_NULL(options);
- return ret;
+ return checkout_main(argc, argv, prefix, &opts, options,
+ restore_usage);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 49c224e..29efe84 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -25,7 +25,7 @@
#include "help.h"
#include "prompt.h"
-static int force = -1; /* unset */
+static int require_force = -1; /* unset */
static int interactive;
static struct string_list del_list = STRING_LIST_INIT_DUP;
static unsigned int colopts;
@@ -128,7 +128,7 @@ static int git_clean_config(const char *var, const char *value,
}
if (!strcmp(var, "clean.requireforce")) {
- force = !git_config_bool(var, value);
+ require_force = git_config_bool(var, value);
return 0;
}
@@ -920,7 +920,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
{
int i, res;
int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
+ int ignored_only = 0, force = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf abs_path = STRBUF_INIT;
struct dir_struct dir = DIR_INIT;
@@ -946,22 +946,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
};
git_config(git_clean_config, NULL);
- if (force < 0)
- force = 0;
- else
- config_set = 1;
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
- if (!interactive && !dry_run && !force) {
- if (config_set)
- die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
- "refusing to clean"));
- else
- die(_("clean.requireForce defaults to true and neither -i, -n, nor -f given;"
- " refusing to clean"));
- }
+ if (require_force != 0 && !force && !interactive && !dry_run)
+ die(_("clean.requireForce is true and -f not given: refusing to clean"));
if (force > 1)
rm_flags = 0;
@@ -971,7 +961,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (ignored && ignored_only)
- die(_("-x and -X cannot be used together"));
+ die(_("options '%s' and '%s' cannot be used together"), "-x", "-X");
if (!ignored)
setup_standard_excludes(&dir);
if (ignored_only)
diff --git a/builtin/clone.c b/builtin/clone.c
index c6357af..221edbc 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -19,7 +19,6 @@
#include "hex.h"
#include "lockfile.h"
#include "parse-options.h"
-#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
#include "object-file.h"
@@ -72,6 +71,7 @@ static char *remote_name = NULL;
static char *option_branch = NULL;
static struct string_list option_not = STRING_LIST_INIT_NODUP;
static const char *real_git_dir;
+static const char *ref_format;
static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
@@ -116,7 +116,7 @@ static struct option builtin_clone_options[] = {
OPT_HIDDEN_BOOL(0, "naked", &option_bare,
N_("create a bare repository")),
OPT_BOOL(0, "mirror", &option_mirror,
- N_("create a mirror repository (implies bare)")),
+ N_("create a mirror repository (implies --bare)")),
OPT_BOOL('l', "local", &option_local,
N_("to clone from a local repository")),
OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
@@ -157,6 +157,8 @@ static struct option builtin_clone_options[] = {
N_("any cloned submodules will be shallow")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
N_("set config inside the new repository")),
OPT_STRING_LIST(0, "server-option", &server_options,
@@ -327,7 +329,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
int src_len, dest_len;
struct dir_iterator *iter;
int iter_status;
- struct strbuf realpath = STRBUF_INIT;
+
+ /*
+ * Refuse copying directories by default which aren't owned by us. The
+ * code that performs either the copying or hardlinking is not prepared
+ * to handle various edge cases where an adversary may for example
+ * racily swap out files for symlinks. This can cause us to
+ * inadvertently use the wrong source file.
+ *
+ * Furthermore, even if we were prepared to handle such races safely,
+ * creating hardlinks across user boundaries is an inherently unsafe
+ * operation as the hardlinked files can be rewritten at will by the
+ * potentially-untrusted user. We thus refuse to do so by default.
+ */
+ die_upon_dubious_ownership(NULL, NULL, src_repo);
mkdir_if_missing(dest->buf, 0777);
@@ -375,9 +390,27 @@ 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) {
- strbuf_realpath(&realpath, src->buf, 1);
- if (!link(realpath.buf, dest->buf))
+ if (!link(src->buf, dest->buf)) {
+ struct stat st;
+
+ /*
+ * Sanity-check whether the created hardlink
+ * actually links to the expected file now. This
+ * catches time-of-check-time-of-use bugs in
+ * case the source file was meanwhile swapped.
+ */
+ if (lstat(dest->buf, &st))
+ die(_("hardlink cannot be checked at '%s'"), dest->buf);
+ if (st.st_mode != iter->st.st_mode ||
+ st.st_ino != iter->st.st_ino ||
+ st.st_dev != iter->st.st_dev ||
+ st.st_size != iter->st.st_size ||
+ st.st_uid != iter->st.st_uid ||
+ st.st_gid != iter->st.st_gid)
+ die(_("hardlink different from source at '%s'"), dest->buf);
+
continue;
+ }
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
@@ -390,8 +423,6 @@ 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)
@@ -736,8 +767,9 @@ static int checkout(int submodule_progress, int filter_submodules)
tree = parse_tree_indirect(&oid);
if (!tree)
die(_("unable to parse commit %s"), oid_to_hex(&oid));
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ exit(128);
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
@@ -791,6 +823,8 @@ static int git_clone_config(const char *k, const char *v,
const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "clone.defaultremotename")) {
+ if (!v)
+ return config_error_nonbool(k);
free(remote_name);
remote_name = xstrdup(v);
}
@@ -922,6 +956,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct ref *mapped_refs = NULL;
const struct ref *ref;
struct strbuf key = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
const char *src_ref_prefix = "refs/heads/";
@@ -930,7 +965,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int submodule_progress;
int filter_submodules = 0;
int hash_algo;
+ unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
const int do_not_override_repo_unix_permissions = -1;
+ const char *template_dir;
+ char *template_dir_dup = NULL;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -950,11 +988,24 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("You must specify a repository to clone."),
builtin_clone_usage, builtin_clone_options);
+ xsetenv("GIT_CLONE_PROTECTION_ACTIVE", "true", 0 /* allow user override */);
+ template_dir = get_template_dir(option_template);
+ if (*template_dir && !is_absolute_path(template_dir))
+ template_dir = template_dir_dup =
+ absolute_pathdup(template_dir);
+ xsetenv("GIT_CLONE_TEMPLATE_DIR", template_dir, 1);
+
if (option_depth || option_since || option_not.nr)
deepen = 1;
if (option_single_branch == -1)
option_single_branch = deepen ? 1 : 0;
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (option_mirror)
option_bare = 1;
@@ -965,7 +1016,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (bundle_uri && deepen)
- die(_("--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-exclude"));
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--bundle-uri",
+ "--depth/--shallow-since/--shallow-exclude");
repo_name = argv[0];
@@ -1097,8 +1150,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
- do_not_override_repo_unix_permissions, INIT_DB_QUIET);
+ /*
+ * Initialize the repository, but skip initializing the reference
+ * database. We do not yet know about the object format of the
+ * repository, and reference backends may persist that information into
+ * their on-disk data structures.
+ */
+ init_db(git_dir, real_git_dir, template_dir, GIT_HASH_UNKNOWN,
+ ref_storage_format, NULL,
+ do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
if (real_git_dir) {
free((char *)git_dir);
@@ -1106,6 +1166,50 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
/*
+ * We have a chicken-and-egg situation between initializing the refdb
+ * and spawning transport helpers:
+ *
+ * - Initializing the refdb requires us to know about the object
+ * format. We thus have to spawn the transport helper to learn
+ * about it.
+ *
+ * - The transport helper may want to access the Git repository. But
+ * because the refdb has not been initialized, we don't have "HEAD"
+ * or "refs/". Thus, the helper cannot find the Git repository.
+ *
+ * Ideally, we would have structured the helper protocol such that it's
+ * mandatory for the helper to first announce its capabilities without
+ * yet assuming a fully initialized repository. Like that, we could
+ * have added a "lazy-refdb-init" capability that announces whether the
+ * helper is ready to handle not-yet-initialized refdbs. If any helper
+ * didn't support them, we would have fully initialized the refdb with
+ * the SHA1 object format, but later on bailed out if we found out that
+ * the remote repository used a different object format.
+ *
+ * But we didn't, and thus we use the following workaround to partially
+ * initialize the repository's refdb such that it can be discovered by
+ * Git commands. To do so, we:
+ *
+ * - Create an invalid HEAD ref pointing at "refs/heads/.invalid".
+ *
+ * - Create the "refs/" directory.
+ *
+ * - Set up the ref storage format and repository version as
+ * required.
+ *
+ * This is sufficient for Git commands to discover the Git directory.
+ */
+ initialize_repository_version(GIT_HASH_UNKNOWN,
+ the_repository->ref_storage_format, 1);
+
+ strbuf_addf(&buf, "%s/HEAD", git_dir);
+ write_file(buf.buf, "ref: refs/heads/.invalid");
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s/refs", git_dir);
+ safe_create_dir(buf.buf, 1);
+
+ /*
* additional config can be injected with -c, make sure it's included
* after init_db, which clears the entire config environment.
*/
@@ -1185,10 +1289,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- if (option_sparse_checkout && git_sparse_checkout_init(dir))
- return 1;
-
- remote = remote_get(remote_name);
+ remote = remote_get_early(remote_name);
refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
branch_top.buf);
@@ -1266,6 +1367,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
+ strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+ refspec_ref_prefixes(&remote->fetch,
+ &transport_ls_refs_options.ref_prefixes);
+ if (option_branch)
+ expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
+ option_branch);
+ if (!option_no_tags)
+ strvec_push(&transport_ls_refs_options.ref_prefixes,
+ "refs/tags/");
+
+ refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
+
+ /*
+ * Now that we know what algorithm the remote side is using, let's set
+ * ours to the same thing.
+ */
+ hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+ initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
+ repo_set_hash_algo(the_repository, hash_algo);
+ create_reference_database(the_repository->ref_storage_format, NULL, 1);
+
/*
* Before fetching from the remote, download and install bundle
* data from the --bundle-uri option.
@@ -1281,24 +1403,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
bundle_uri);
else if (has_heuristic)
git_config_set_gently("fetch.bundleuri", bundle_uri);
- }
-
- strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
- refspec_ref_prefixes(&remote->fetch,
- &transport_ls_refs_options.ref_prefixes);
- if (option_branch)
- expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
- option_branch);
- if (!option_no_tags)
- strvec_push(&transport_ls_refs_options.ref_prefixes,
- "refs/tags/");
-
- refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
-
- if (refs)
- mapped_refs = wanted_peer_refs(refs, &remote->fetch);
-
- if (!bundle_uri) {
+ } else {
/*
* Populate transport->got_remote_bundle_uri and
* transport->bundle_uri. We might get nothing.
@@ -1319,13 +1424,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- /*
- * Now that we know what algorithm the remote side is using,
- * let's set ours to the same thing.
- */
- hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
- initialize_repository_version(hash_algo, 1);
- repo_set_hash_algo(the_repository, hash_algo);
+ if (refs)
+ mapped_refs = wanted_peer_refs(refs, &remote->fetch);
if (mapped_refs) {
/*
@@ -1428,12 +1528,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
dissociate_from_references();
}
+ if (option_sparse_checkout && git_sparse_checkout_init(dir))
+ return 1;
+
junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress, filter_submodules);
free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
+ strbuf_release(&buf);
strbuf_release(&key);
free_refs(mapped_refs);
free_refs(remote_head_points_at);
@@ -1441,6 +1545,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(dir);
free(path);
free(repo_to_free);
+ free(template_dir_dup);
junk_mode = JUNK_LEAVE_ALL;
transport_ls_refs_options_release(&transport_ls_refs_options);
diff --git a/builtin/column.c b/builtin/column.c
index a83be8b..10ff7e0 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -45,6 +45,8 @@ int cmd_column(int argc, const char **argv, const char *prefix)
memset(&copts, 0, sizeof(copts));
copts.padding = 1;
argc = parse_options(argc, argv, prefix, options, builtin_column_usage, 0);
+ if (copts.padding < 0)
+ die(_("%s must be non-negative"), "--padding");
if (argc)
usage_with_options(builtin_column_usage, options);
if (real_command || command) {
@@ -56,5 +58,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
string_list_append(&list, sb.buf);
print_columns(&list, colopts, &copts);
+ strbuf_release(&sb);
+ string_list_clear(&list, 0);
return 0;
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 45d035a..7102ee9 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -1,17 +1,16 @@
#include "builtin.h"
#include "commit.h"
#include "config.h"
-#include "dir.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "lockfile.h"
#include "parse-options.h"
#include "repository.h"
#include "commit-graph.h"
#include "object-store-ll.h"
#include "progress.h"
#include "replace-object.h"
+#include "strbuf.h"
#include "tag.h"
#include "trace2.h"
@@ -22,7 +21,7 @@
N_("git commit-graph write [--object-dir <dir>] [--append]\n" \
" [--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]\n" \
" [--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]\n" \
- " <split options>")
+ " <split-options>")
static const char * builtin_commit_graph_verify_usage[] = {
BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 02625e7..1bb7819 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -11,9 +11,6 @@
#include "object-store-ll.h"
#include "repository.h"
#include "commit.h"
-#include "tree.h"
-#include "utf8.h"
-#include "gpg-interface.h"
#include "parse-options.h"
static const char * const commit_tree_usage[] = {
diff --git a/builtin/commit.c b/builtin/commit.c
index 781af2e..6e14844 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -16,17 +16,12 @@
#include "editor.h"
#include "environment.h"
#include "diff.h"
-#include "diffcore.h"
#include "commit.h"
#include "gettext.h"
#include "revision.h"
#include "wt-status.h"
#include "run-command.h"
-#include "hook.h"
-#include "refs.h"
-#include "log-tree.h"
#include "strbuf.h"
-#include "utf8.h"
#include "object-name.h"
#include "parse-options.h"
#include "path.h"
@@ -35,9 +30,6 @@
#include "string-list.h"
#include "rerere.h"
#include "unpack-trees.h"
-#include "quote.h"
-#include "submodule.h"
-#include "gpg-interface.h"
#include "column.h"
#include "sequencer.h"
#include "sparse-index.h"
@@ -339,8 +331,9 @@ static void create_base_index(const struct commit *current_head)
tree = parse_tree_indirect(&current_head->object.oid);
if (!tree)
die(_("failed to unpack HEAD tree object"));
- parse_tree(tree);
- init_tree_desc(&t, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ exit(128);
+ init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts))
exit(128); /* We've already reported the error, finish dying */
}
@@ -448,16 +441,21 @@ static const char *prepare_index(const char **argv, const char *prefix,
* (B) on failure, rollback the real index.
*/
if (all || (also && pathspec.nr)) {
+ char *ps_matched = xcalloc(pathspec.nr, 1);
repo_hold_locked_index(the_repository, &index_lock,
LOCK_DIE_ON_ERROR);
add_files_to_cache(the_repository, also ? prefix : NULL,
- &pathspec, 0, 0);
+ &pathspec, ps_matched, 0, 0);
+ if (!all && report_path_error(ps_matched, &pathspec))
+ exit(128);
+
refresh_cache_or_die(refresh_flags);
cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new index file"));
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
+ free(ps_matched);
goto out;
}
@@ -692,9 +690,10 @@ static void adjust_comment_line_char(const struct strbuf *sb)
char *candidate;
const char *p;
- comment_line_char = candidates[0];
- if (!memchr(sb->buf, comment_line_char, sb->len))
+ if (!memchr(sb->buf, candidates[0], sb->len)) {
+ comment_line_str = xstrfmt("%c", candidates[0]);
return;
+ }
p = sb->buf;
candidate = strchr(candidates, *p);
@@ -713,7 +712,7 @@ static void adjust_comment_line_char(const struct strbuf *sb)
if (!*p)
die(_("unable to select a comment character that is not used\n"
"in the current commit message"));
- comment_line_char = *p;
+ comment_line_str = xstrfmt("%c", *p);
}
static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
@@ -745,7 +744,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
const char *hook_arg2 = NULL;
int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
int old_display_comment_prefix;
- int merge_contains_scissors = 0;
int invoked_hook;
/* This checks and barfs if author is badly specified */
@@ -849,7 +847,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
wt_status_locate_end(sb.buf + merge_msg_start,
sb.len - merge_msg_start) <
sb.len - merge_msg_start)
- merge_contains_scissors = 1;
+ s->added_cut_line = 1;
} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
@@ -897,10 +895,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->hints = 0;
if (clean_message_contents)
- strbuf_stripspace(&sb, '\0');
+ strbuf_stripspace(&sb, NULL);
if (signoff)
- append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
+ append_signoff(&sb, ignored_log_message_bytes(sb.buf, sb.len), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
@@ -917,24 +915,23 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct ident_split ci, ai;
const char *hint_cleanup_all = allow_empty_message ?
_("Please enter the commit message for your changes."
- " Lines starting\nwith '%c' will be ignored.\n") :
+ " Lines starting\nwith '%s' will be ignored.\n") :
_("Please enter the commit message for your changes."
- " Lines starting\nwith '%c' will be ignored, and an empty"
+ " Lines starting\nwith '%s' will be ignored, and an empty"
" message aborts the commit.\n");
const char *hint_cleanup_space = allow_empty_message ?
_("Please enter the commit message for your changes."
" Lines starting\n"
- "with '%c' will be kept; you may remove them"
+ "with '%s' will be kept; you may remove them"
" yourself if you want to.\n") :
_("Please enter the commit message for your changes."
" Lines starting\n"
- "with '%c' will be kept; you may remove them"
+ "with '%s' will be kept; you may remove them"
" yourself if you want to.\n"
"An empty message aborts the commit.\n");
if (whence != FROM_COMMIT) {
- if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
- !merge_contains_scissors)
- wt_status_add_cut_line(s->fp);
+ if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+ wt_status_add_cut_line(s);
status_printf_ln(
s, GIT_COLOR_NORMAL,
whence == FROM_MERGE ?
@@ -952,12 +949,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
fprintf(s->fp, "\n");
if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
- status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_str);
else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
- if (whence == FROM_COMMIT && !merge_contains_scissors)
- wt_status_add_cut_line(s->fp);
+ if (whence == FROM_COMMIT)
+ wt_status_add_cut_line(s);
} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
- status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_str);
/*
* These should never fail because they come from our own
@@ -1166,22 +1163,45 @@ static void handle_ignored_arg(struct wt_status *s)
die(_("Invalid ignored mode '%s'"), ignored_arg);
}
-static void handle_untracked_files_arg(struct wt_status *s)
+static enum untracked_status_type parse_untracked_setting_name(const char *u)
{
- if (!untracked_files_arg)
- ; /* default already initialized */
- else if (!strcmp(untracked_files_arg, "no"))
- s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
- else if (!strcmp(untracked_files_arg, "normal"))
- s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
- else if (!strcmp(untracked_files_arg, "all"))
- s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
/*
* Please update $__git_untracked_file_modes in
* git-completion.bash when you add new options
*/
+ switch (git_parse_maybe_bool(u)) {
+ case 0:
+ u = "no";
+ break;
+ case 1:
+ u = "normal";
+ break;
+ default:
+ break;
+ }
+
+ if (!strcmp(u, "no"))
+ return SHOW_NO_UNTRACKED_FILES;
+ else if (!strcmp(u, "normal"))
+ return SHOW_NORMAL_UNTRACKED_FILES;
+ else if (!strcmp(u, "all"))
+ return SHOW_ALL_UNTRACKED_FILES;
else
- die(_("Invalid untracked files mode '%s'"), untracked_files_arg);
+ return SHOW_UNTRACKED_FILES_ERROR;
+}
+
+static void handle_untracked_files_arg(struct wt_status *s)
+{
+ enum untracked_status_type u;
+
+ if (!untracked_files_arg)
+ return; /* default already initialized */
+
+ u = parse_untracked_setting_name(untracked_files_arg);
+ if (u == SHOW_UNTRACKED_FILES_ERROR)
+ die(_("Invalid untracked files mode '%s'"),
+ untracked_files_arg);
+ s->show_untracked_files = u;
}
static const char *read_commit_message(const char *name)
@@ -1464,16 +1484,12 @@ static int git_status_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "status.showuntrackedfiles")) {
- if (!v)
- return config_error_nonbool(k);
- else if (!strcmp(v, "no"))
- s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
- else if (!strcmp(v, "normal"))
- s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
- else if (!strcmp(v, "all"))
- s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
- else
+ enum untracked_status_type u;
+
+ u = parse_untracked_setting_name(v);
+ if (u == SHOW_UNTRACKED_FILES_ERROR)
return error(_("Invalid untracked files mode '%s'"), v);
+ s->show_untracked_files = u;
return 0;
}
if (!strcmp(k, "diff.renamelimit")) {
@@ -1885,7 +1901,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
&oid, flags);
}
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
cleanup:
strbuf_release(&author_ident);
diff --git a/builtin/config.c b/builtin/config.c
index 11a4d4e..0015620 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -44,6 +44,7 @@ static struct config_options config_options;
static int show_origin;
static int show_scope;
static int fixed_value;
+static const char *comment;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
@@ -173,6 +174,7 @@ static struct option builtin_config_options[] = {
OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
+ OPT_STRING(0, "comment", &comment, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
OPT_END(),
};
@@ -708,10 +710,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if (use_global_config) {
- char *user_config, *xdg_config;
-
- git_global_config(&user_config, &xdg_config);
- if (!user_config)
+ given_config_source.file = git_global_config();
+ if (!given_config_source.file)
/*
* It is unknown if HOME/.gitconfig exists, so
* we do not know if we should write to XDG
@@ -719,19 +719,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
* is set and points at a sane location.
*/
die(_("$HOME not set"));
-
given_config_source.scope = CONFIG_SCOPE_GLOBAL;
-
- if (access_or_warn(user_config, R_OK, 0) &&
- xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
- given_config_source.file = xdg_config;
- free(user_config);
- } else {
- given_config_source.file = user_config;
- free(xdg_config);
- }
- }
- else if (use_system_config) {
+ } else if (use_system_config) {
given_config_source.file = git_system_config();
given_config_source.scope = CONFIG_SCOPE_SYSTEM;
} else if (use_local_config) {
@@ -760,7 +749,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
given_config_source.scope = CONFIG_SCOPE_COMMAND;
}
-
if (respect_includes_opt == -1)
config_options.respect_includes = !given_config_source.file;
else
@@ -811,6 +799,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
usage_builtin_config();
}
+ if (comment &&
+ !(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) {
+ error(_("--comment is only applicable to add/set/replace operations"));
+ usage_builtin_config();
+ }
+
/* check usage of --fixed-value */
if (fixed_value) {
int allowed_usage = 0;
@@ -847,6 +841,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
flags |= CONFIG_FLAGS_FIXED_VALUE;
}
+ comment = git_config_prepare_comment_string(comment);
+
if (actions & PAGING_ACTIONS)
setup_auto_pager("config", 1);
@@ -894,7 +890,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], &default_kvi);
- ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
+ ret = git_config_set_in_file_gently(given_config_source.file, argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -905,7 +901,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
value = normalize_value(argv[0], argv[1], &default_kvi);
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2],
- flags);
+ comment, flags);
}
else if (actions == ACTION_ADD) {
check_write();
@@ -914,7 +910,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value,
CONFIG_REGEX_NONE,
- flags);
+ comment, flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
@@ -922,7 +918,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
value = normalize_value(argv[0], argv[1], &default_kvi);
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value, argv[2],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -950,17 +946,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (argc == 2)
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], NULL, argv[1],
- flags);
+ NULL, flags);
else
return git_config_set_in_file_gently(given_config_source.file,
- argv[0], NULL);
+ argv[0], NULL, NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_write();
check_argc(argc, 1, 2);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], NULL, argv[1],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
check_write();
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 3a6a750..17f929d 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -294,6 +294,8 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, usage, 0);
socket_path = argv[0];
+ if (!have_unix_sockets())
+ die(_("credential-cache--daemon unavailable; no unix socket support"));
if (!socket_path)
usage_with_options(usage, options);
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 43b9d0e..bef120b 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -7,8 +7,6 @@
#ifndef NO_UNIX_SOCKETS
-#include "credential.h"
-#include "string-list.h"
#include "unix-socket.h"
#include "run-command.h"
@@ -151,6 +149,9 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
op = argv[0];
+ if (!have_unix_sockets())
+ die(_("credential-cache unavailable; no unix socket support"));
+
if (!socket_path)
socket_path = get_socket_path();
if (!socket_path)
diff --git a/builtin/describe.c b/builtin/describe.c
index fb6b050..d6c77a7 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -7,9 +7,7 @@
#include "lockfile.h"
#include "commit.h"
#include "tag.h"
-#include "blob.h"
#include "refs.h"
-#include "exec-cmd.h"
#include "object-name.h"
#include "parse-options.h"
#include "read-cache-ll.h"
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index f38912c..018011f 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -11,7 +11,6 @@
#include "preload-index.h"
#include "repository.h"
#include "revision.h"
-#include "submodule.h"
static const char diff_files_usage[] =
"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 220f341..3e05260 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -7,8 +7,6 @@
#include "repository.h"
#include "revision.h"
#include "setup.h"
-#include "sparse-index.h"
-#include "submodule.h"
static const char diff_cache_usage[] =
"git diff-index [-m] [--cached] [--merge-base] "
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 86be634..a8e68ce 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -6,7 +6,6 @@
#include "gettext.h"
#include "hex.h"
#include "log-tree.h"
-#include "submodule.h"
#include "read-cache-ll.h"
#include "repository.h"
#include "revision.h"
diff --git a/builtin/diff.c b/builtin/diff.c
index 55e7d21..6e196e0 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -10,7 +10,6 @@
#include "lockfile.h"
#include "color.h"
#include "commit.h"
-#include "blob.h"
#include "gettext.h"
#include "tag.h"
#include "diff.h"
@@ -21,7 +20,6 @@
#include "revision.h"
#include "log-tree.h"
#include "setup.h"
-#include "submodule.h"
#include "oid-array.h"
#include "tree.h"
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 0f5eae9..a3c72b8 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -18,7 +18,6 @@
#include "copy.h"
#include "run-command.h"
#include "environment.h"
-#include "exec-cmd.h"
#include "gettext.h"
#include "hex.h"
#include "parse-options.h"
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 70aff51..4693d18 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -25,7 +25,6 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
-#include "commit-slab.h"
static const char *fast_export_usage[] = {
N_("git fast-export [<rev-list-opts>]"),
@@ -137,8 +136,7 @@ static int anonymized_entry_cmp(const void *cmp_data UNUSED,
a = container_of(eptr, const struct anonymized_entry, hash);
if (keydata) {
const struct anonymized_entry_key *key = keydata;
- int equal = !strncmp(a->orig, key->orig, key->orig_len) &&
- !a->orig[key->orig_len];
+ int equal = !xstrncmpz(a->orig, key->orig, key->orig_len);
return !equal;
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 444f41c..dc5a9d3 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1236,20 +1236,6 @@ static void *gfi_unpack_entry(
return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
}
-static const char *get_mode(const char *str, uint16_t *modep)
-{
- unsigned char c;
- uint16_t mode = 0;
-
- while ((c = *str++) != ' ') {
- if (c < '0' || c > '7')
- return NULL;
- mode = (mode << 3) + (c - '0');
- }
- *modep = mode;
- return str;
-}
-
static void load_tree(struct tree_entry *root)
{
struct object_id *oid = &root->versions[1].oid;
@@ -1287,7 +1273,7 @@ static void load_tree(struct tree_entry *root)
t->entries[t->entry_count++] = e;
e->tree = NULL;
- c = get_mode(c, &e->versions[1].mode);
+ c = parse_mode(c, &e->versions[1].mode);
if (!c)
die("Corrupt mode in %s", oid_to_hex(oid));
e->versions[0].mode = e->versions[1].mode;
@@ -1625,6 +1611,7 @@ static int update_branch(struct branch *b)
oidclr(&old_oid);
if (!force_update && !is_null_oid(&old_oid)) {
struct commit *old_cmit, *new_cmit;
+ int ret;
old_cmit = lookup_commit_reference_gently(the_repository,
&old_oid, 0);
@@ -1633,7 +1620,10 @@ static int update_branch(struct branch *b)
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
- if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
+ ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit);
+ if (ret < 0)
+ exit(128);
+ if (!ret) {
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, oid_to_hex(&b->oid),
@@ -2220,7 +2210,7 @@ static int parse_mapped_oid_hex(const char *hex, struct object_id *oid, const ch
*
* idnum ::= ':' bigint;
*
- * Return the first character after the value in *endptr.
+ * Update *endptr to point to the first character after the value.
*
* Complain if the following character is not what is expected,
* either a space or end of the string.
@@ -2253,8 +2243,8 @@ static uintmax_t parse_mark_ref_eol(const char *p)
}
/*
- * Parse the mark reference, demanding a trailing space. Return a
- * pointer to the space.
+ * Parse the mark reference, demanding a trailing space. Update *p to
+ * point to the first character after the space.
*/
static uintmax_t parse_mark_ref_space(const char **p)
{
@@ -2268,15 +2258,67 @@ static uintmax_t parse_mark_ref_space(const char **p)
return mark;
}
+/*
+ * Parse the path string into the strbuf. The path can either be quoted with
+ * escape sequences or unquoted without escape sequences. Unquoted strings may
+ * contain spaces only if `is_last_field` is nonzero; otherwise, it stops
+ * parsing at the first space.
+ */
+static void parse_path(struct strbuf *sb, const char *p, const char **endp,
+ int is_last_field, const char *field)
+{
+ if (*p == '"') {
+ if (unquote_c_style(sb, p, endp))
+ die("Invalid %s: %s", field, command_buf.buf);
+ if (strlen(sb->buf) != sb->len)
+ die("NUL in %s: %s", field, command_buf.buf);
+ } else {
+ /*
+ * Unless we are parsing the last field of a line,
+ * SP is the end of this field.
+ */
+ *endp = is_last_field
+ ? p + strlen(p)
+ : strchrnul(p, ' ');
+ strbuf_add(sb, p, *endp - p);
+ }
+}
+
+/*
+ * Parse the path string into the strbuf, and complain if this is not the end of
+ * the string. Unquoted strings may contain spaces.
+ */
+static void parse_path_eol(struct strbuf *sb, const char *p, const char *field)
+{
+ const char *end;
+
+ parse_path(sb, p, &end, 1, field);
+ if (*end)
+ die("Garbage after %s: %s", field, command_buf.buf);
+}
+
+/*
+ * Parse the path string into the strbuf, and ensure it is followed by a space.
+ * Unquoted strings may not contain spaces. Update *endp to point to the first
+ * character after the space.
+ */
+static void parse_path_space(struct strbuf *sb, const char *p,
+ const char **endp, const char *field)
+{
+ parse_path(sb, p, endp, 0, field);
+ if (**endp != ' ')
+ die("Missing space after %s: %s", field, command_buf.buf);
+ (*endp)++;
+}
+
static void file_change_m(const char *p, struct branch *b)
{
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf path = STRBUF_INIT;
struct object_entry *oe;
struct object_id oid;
uint16_t mode, inline_data = 0;
- p = get_mode(p, &mode);
+ p = parse_mode(p, &mode);
if (!p)
die("Corrupt mode: %s", command_buf.buf);
switch (mode) {
@@ -2308,16 +2350,12 @@ static void file_change_m(const char *p, struct branch *b)
die("Missing space after SHA1: %s", command_buf.buf);
}
- strbuf_reset(&uq);
- if (!unquote_c_style(&uq, p, &endp)) {
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
/* Git does not track empty, non-toplevel directories. */
- if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) {
- tree_content_remove(&b->branch_tree, p, NULL, 0);
+ if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *path.buf) {
+ tree_content_remove(&b->branch_tree, path.buf, NULL, 0);
return;
}
@@ -2338,10 +2376,6 @@ static void file_change_m(const char *p, struct branch *b)
if (S_ISDIR(mode))
die("Directories cannot be specified 'inline': %s",
command_buf.buf);
- if (p != uq.buf) {
- strbuf_addstr(&uq, p);
- p = uq.buf;
- }
while (read_next_command() != EOF) {
const char *v;
if (skip_prefix(command_buf.buf, "cat-blob ", &v))
@@ -2367,74 +2401,48 @@ static void file_change_m(const char *p, struct branch *b)
command_buf.buf);
}
- if (!*p) {
+ if (!*path.buf) {
tree_content_replace(&b->branch_tree, &oid, mode, NULL);
return;
}
- tree_content_set(&b->branch_tree, p, &oid, mode, NULL);
+ tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL);
}
static void file_change_d(const char *p, struct branch *b)
{
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf path = STRBUF_INIT;
- strbuf_reset(&uq);
- if (!unquote_c_style(&uq, p, &endp)) {
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
- tree_content_remove(&b->branch_tree, p, NULL, 1);
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
+ tree_content_remove(&b->branch_tree, path.buf, NULL, 1);
}
-static void file_change_cr(const char *s, struct branch *b, int rename)
+static void file_change_cr(const char *p, struct branch *b, int rename)
{
- const char *d;
- static struct strbuf s_uq = STRBUF_INIT;
- static struct strbuf d_uq = STRBUF_INIT;
- const char *endp;
+ static struct strbuf source = STRBUF_INIT;
+ static struct strbuf dest = STRBUF_INIT;
struct tree_entry leaf;
- strbuf_reset(&s_uq);
- if (!unquote_c_style(&s_uq, s, &endp)) {
- if (*endp != ' ')
- die("Missing space after source: %s", command_buf.buf);
- } else {
- endp = strchr(s, ' ');
- if (!endp)
- die("Missing space after source: %s", command_buf.buf);
- strbuf_add(&s_uq, s, endp - s);
- }
- s = s_uq.buf;
-
- endp++;
- if (!*endp)
- die("Missing dest: %s", command_buf.buf);
-
- d = endp;
- strbuf_reset(&d_uq);
- if (!unquote_c_style(&d_uq, d, &endp)) {
- if (*endp)
- die("Garbage after dest in: %s", command_buf.buf);
- d = d_uq.buf;
- }
+ strbuf_reset(&source);
+ parse_path_space(&source, p, &p, "source");
+ strbuf_reset(&dest);
+ parse_path_eol(&dest, p, "dest");
memset(&leaf, 0, sizeof(leaf));
if (rename)
- tree_content_remove(&b->branch_tree, s, &leaf, 1);
+ tree_content_remove(&b->branch_tree, source.buf, &leaf, 1);
else
- tree_content_get(&b->branch_tree, s, &leaf, 1);
+ tree_content_get(&b->branch_tree, source.buf, &leaf, 1);
if (!leaf.versions[1].mode)
- die("Path %s not in branch", s);
- if (!*d) { /* C "path/to/subdir" "" */
+ die("Path %s not in branch", source.buf);
+ if (!*dest.buf) { /* C "path/to/subdir" "" */
tree_content_replace(&b->branch_tree,
&leaf.versions[1].oid,
leaf.versions[1].mode,
leaf.tree);
return;
}
- tree_content_set(&b->branch_tree, d,
+ tree_content_set(&b->branch_tree, dest.buf,
&leaf.versions[1].oid,
leaf.versions[1].mode,
leaf.tree);
@@ -2442,7 +2450,6 @@ static void file_change_cr(const char *s, struct branch *b, int rename)
static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout)
{
- static struct strbuf uq = STRBUF_INIT;
struct object_entry *oe;
struct branch *s;
struct object_id oid, commit_oid;
@@ -2507,10 +2514,6 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
die("Invalid ref name or SHA1 expression: %s", p);
if (inline_data) {
- if (p != uq.buf) {
- strbuf_addstr(&uq, p);
- p = uq.buf;
- }
read_next_command();
parse_and_store_blob(&last_blob, &oid, 0);
} else if (oe) {
@@ -2809,8 +2812,7 @@ static void parse_new_tag(const char *arg)
enum object_type type;
const char *v;
- t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
- memset(t, 0, sizeof(struct tag));
+ t = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct tag));
t->name = mem_pool_strdup(&fi_mem_pool, arg);
if (last_tag)
last_tag->next_tag = t;
@@ -3163,6 +3165,7 @@ static void print_ls(int mode, const unsigned char *hash, const char *path)
static void parse_ls(const char *p, struct branch *b)
{
+ static struct strbuf path = STRBUF_INIT;
struct tree_entry *root = NULL;
struct tree_entry leaf = {NULL};
@@ -3179,17 +3182,9 @@ static void parse_ls(const char *p, struct branch *b)
root->versions[1].mode = S_IFDIR;
load_tree(root);
}
- if (*p == '"') {
- static struct strbuf uq = STRBUF_INIT;
- const char *endp;
- strbuf_reset(&uq);
- if (unquote_c_style(&uq, p, &endp))
- die("Invalid path: %s", command_buf.buf);
- if (*endp)
- die("Garbage after path in: %s", command_buf.buf);
- p = uq.buf;
- }
- tree_content_get(root, p, &leaf, 1);
+ strbuf_reset(&path);
+ parse_path_eol(&path, p, "path");
+ tree_content_get(root, path.buf, &leaf, 1);
/*
* A directory in preparation would have a sha1 of zero
* until it is saved. Save, for simplicity.
@@ -3197,7 +3192,7 @@ static void parse_ls(const char *p, struct branch *b)
if (S_ISDIR(leaf.versions[1].mode))
store_tree(&leaf);
- print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p);
+ print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, path.buf);
if (leaf.tree)
release_tree_content_recursive(leaf.tree);
if (!b || root != &b->branch_tree)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index fd134ba..5857d86 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -26,7 +26,6 @@
#include "connected.h"
#include "strvec.h"
#include "utf8.h"
-#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "pkt-line.h"
@@ -38,7 +37,6 @@
#include "shallow.h"
#include "trace.h"
#include "trace2.h"
-#include "worktree.h"
#include "bundle-uri.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -102,6 +100,7 @@ static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
struct fetch_config {
enum display_format display_format;
+ int all;
int prune;
int prune_tags;
int show_forced_updates;
@@ -115,6 +114,11 @@ static int git_fetch_config(const char *k, const char *v,
{
struct fetch_config *fetch_config = cb;
+ if (!strcmp(k, "fetch.all")) {
+ fetch_config->all = git_config_bool(k, v);
+ return 0;
+ }
+
if (!strcmp(k, "fetch.prune")) {
fetch_config->prune = git_config_bool(k, v);
return 0;
@@ -134,6 +138,7 @@ static int git_fetch_config(const char *k, const char *v,
int r = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
fetch_config->recurse_submodules = r;
+ return 0;
}
if (!strcmp(k, "submodule.fetchjobs")) {
@@ -444,9 +449,8 @@ static void filter_prefetch_refspec(struct refspec *rs)
continue;
if (!rs->items[i].dst ||
(rs->items[i].src &&
- !strncmp(rs->items[i].src,
- ref_namespace[NAMESPACE_TAGS].ref,
- strlen(ref_namespace[NAMESPACE_TAGS].ref)))) {
+ starts_with(rs->items[i].src,
+ ref_namespace[NAMESPACE_TAGS].ref))) {
int j;
free(rs->items[i].src);
@@ -978,6 +982,8 @@ static int update_local_ref(struct ref *ref,
uint64_t t_before = getnanotime();
fast_forward = repo_in_merge_bases(the_repository, current,
updated);
+ if (fast_forward < 0)
+ exit(128);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -1651,7 +1657,7 @@ static int do_fetch(struct transport *transport,
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
- retcode = error("%s", err.buf);
+ retcode = -1;
goto cleanup;
}
}
@@ -1711,7 +1717,6 @@ static int do_fetch(struct transport *transport,
retcode = ref_transaction_commit(transaction, &err);
if (retcode) {
- error("%s", err.buf);
ref_transaction_free(transaction);
transaction = NULL;
goto cleanup;
@@ -1775,9 +1780,14 @@ static int do_fetch(struct transport *transport,
}
cleanup:
- if (retcode && transaction) {
- ref_transaction_abort(transaction, &err);
- error("%s", err.buf);
+ if (retcode) {
+ if (err.len) {
+ error("%s", err.buf);
+ strbuf_reset(&err);
+ }
+ if (transaction && ref_transaction_abort(transaction, &err) &&
+ err.len)
+ error("%s", err.buf);
}
display_state_release(&display_state);
@@ -2128,7 +2138,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
- int all = 0, multiple = 0;
+ int all = -1, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
int enable_auto_gc = 1;
@@ -2333,11 +2343,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+ if (all < 0) {
+ /*
+ * no --[no-]all given;
+ * only use config option if no remote was explicitly specified
+ */
+ all = (!argc) ? config.all : 0;
+ }
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
else if (argc > 1)
die(_("fetch --all does not make sense with refspecs"));
+
(void) for_each_remote(get_one_remote_for_fetch, &list);
/* do not do fetch_multiple() of one */
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 350bfa6..919282e 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,13 +1,12 @@
#include "builtin.h"
+#include "commit.h"
#include "config.h"
#include "gettext.h"
-#include "refs.h"
#include "object.h"
#include "parse-options.h"
#include "ref-filter.h"
#include "strbuf.h"
#include "strvec.h"
-#include "commit-reach.h"
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
@@ -19,16 +18,12 @@ static char const * const for_each_ref_usage[] = {
int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
{
- int i;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
- int maxcount = 0, icase = 0, omit_empty = 0;
- struct ref_array array;
+ int icase = 0, include_root_refs = 0, from_stdin = 0;
struct ref_filter filter = REF_FILTER_INIT;
struct ref_format format = REF_FORMAT_INIT;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
- int from_stdin = 0;
+ unsigned int flags = FILTER_REFS_REGULAR;
struct strvec vec = STRVEC_INIT;
struct option opts[] = {
@@ -40,11 +35,11 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", &format.quote_style,
N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
- OPT_BOOL(0, "omit-empty", &omit_empty,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
N_("do not output a newline after empty formatted refs")),
OPT_GROUP(""),
- OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
+ OPT_INTEGER( 0 , "count", &format.array_opts.max_count, 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_REF_FILTER_EXCLUDE(&filter),
@@ -58,18 +53,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
+ OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
OPT_END(),
};
- memset(&array, 0, sizeof(array));
-
format.format = "%(objectname) %(objecttype)\t%(refname)";
git_config(git_default_config, NULL);
+ /* Set default (refname) sorting */
+ string_list_append(&sorting_options, "refname");
+
parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
- if (maxcount < 0) {
- error("invalid --count argument: `%d'", maxcount);
+ if (format.array_opts.max_count < 0) {
+ error("invalid --count argument: `%d'", format.array_opts.max_count);
usage_with_options(for_each_ref_usage, opts);
}
if (HAS_MULTI_BITS(format.quote_style)) {
@@ -100,27 +97,12 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
filter.name_patterns = argv;
}
+ if (include_root_refs)
+ flags |= FILTER_REFS_ROOT_REFS;
+
filter.match_as_path = 1;
- filter_refs(&array, &filter, FILTER_REFS_ALL);
- filter_ahead_behind(the_repository, &format, &array);
-
- ref_array_sort(sorting, &array);
-
- if (!maxcount || array.nr < maxcount)
- maxcount = array.nr;
- for (i = 0; i < maxcount; i++) {
- strbuf_reset(&err);
- strbuf_reset(&output);
- if (format_ref_array_item(array.items[i], &format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- if (output.len || !omit_empty)
- putchar('\n');
- }
+ filter_and_format_refs(&filter, flags, sorting, &format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
ref_filter_clear(&filter);
ref_sorting_release(sorting);
strvec_clear(&vec);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 6119259..f892487 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -10,13 +10,10 @@
#include "refs.h"
#include "pack.h"
#include "cache-tree.h"
-#include "tree-walk.h"
#include "fsck.h"
#include "parse-options.h"
-#include "dir.h"
#include "progress.h"
#include "streaming.h"
-#include "decorate.h"
#include "packfile.h"
#include "object-file.h"
#include "object-name.h"
@@ -512,9 +509,7 @@ static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid
return 0;
}
-static int fsck_handle_reflog(const char *logname,
- const struct object_id *oid UNUSED,
- int flag UNUSED, void *cb_data)
+static int fsck_handle_reflog(const char *logname, void *cb_data)
{
struct strbuf refname = STRBUF_INIT;
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 5d01db5..1593713 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1,19 +1,20 @@
#include "builtin.h"
#include "abspath.h"
#include "config.h"
+#include "dir.h"
#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "fsmonitor-ll.h"
#include "fsmonitor-ipc.h"
-#include "fsmonitor-path-utils.h"
#include "fsmonitor-settings.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "repository.h"
#include "simple-ipc.h"
#include "khash.h"
-#include "pkt-line.h"
+#include "run-command.h"
#include "trace.h"
#include "trace2.h"
diff --git a/builtin/gc.c b/builtin/gc.c
index 7c11d5e..d187cec 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -180,13 +180,51 @@ static void gc_config(void)
git_config(git_default_config, NULL);
}
-struct maintenance_run_opts;
+enum schedule_priority {
+ SCHEDULE_NONE = 0,
+ SCHEDULE_WEEKLY = 1,
+ SCHEDULE_DAILY = 2,
+ SCHEDULE_HOURLY = 3,
+};
+
+static enum schedule_priority parse_schedule(const char *value)
+{
+ if (!value)
+ return SCHEDULE_NONE;
+ if (!strcasecmp(value, "hourly"))
+ return SCHEDULE_HOURLY;
+ if (!strcasecmp(value, "daily"))
+ return SCHEDULE_DAILY;
+ if (!strcasecmp(value, "weekly"))
+ return SCHEDULE_WEEKLY;
+ return SCHEDULE_NONE;
+}
+
+struct maintenance_run_opts {
+ int auto_flag;
+ int quiet;
+ enum schedule_priority schedule;
+};
+
+static int pack_refs_condition(void)
+{
+ /*
+ * The auto-repacking logic for refs is handled by the ref backends and
+ * exposed via `git pack-refs --auto`. We thus always return truish
+ * here and let the backend decide for us.
+ */
+ return 1;
+}
+
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
struct child_process cmd = CHILD_PROCESS_INIT;
cmd.git_cmd = 1;
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
+ if (opts->auto_flag)
+ strvec_push(&cmd.args, "--auto");
+
return run_command(&cmd);
}
@@ -547,7 +585,7 @@ done:
return ret;
}
-static void gc_before_repack(void)
+static void gc_before_repack(struct maintenance_run_opts *opts)
{
/*
* We may be called twice, as both the pre- and
@@ -558,7 +596,7 @@ static void gc_before_repack(void)
if (done++)
return;
- if (pack_refs && maintenance_task_pack_refs(NULL))
+ if (pack_refs && maintenance_task_pack_refs(opts))
die(FAILED_RUN, "pack-refs");
if (prune_reflogs) {
@@ -574,7 +612,6 @@ static void gc_before_repack(void)
int cmd_gc(int argc, const char **argv, const char *prefix)
{
int aggressive = 0;
- int auto_gc = 0;
int quiet = 0;
int force = 0;
const char *name;
@@ -583,6 +620,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int keep_largest_pack = -1;
timestamp_t dummy;
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
+ struct maintenance_run_opts opts = {0};
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -593,7 +631,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
- OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
+ OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL_F(0, "force", &force,
N_("force running gc even if there may be another gc running"),
@@ -638,7 +676,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (quiet)
strvec_push(&repack, "-q");
- if (auto_gc) {
+ if (opts.auto_flag) {
/*
* Auto-gc should be least intrusive as possible.
*/
@@ -663,7 +701,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (lock_repo_for_gc(force, &pid))
return 0;
- gc_before_repack(); /* dies on failure */
+ gc_before_repack(&opts); /* dies on failure */
delete_tempfile(&pidfile);
/*
@@ -688,7 +726,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
name = lock_repo_for_gc(force, &pid);
if (name) {
- if (auto_gc)
+ if (opts.auto_flag)
return 0; /* be quiet on --auto */
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
name, (uintmax_t)pid);
@@ -703,7 +741,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
atexit(process_log_file_at_exit);
}
- gc_before_repack();
+ gc_before_repack(&opts);
if (!repository_format_precious_objects) {
struct child_process repack_cmd = CHILD_PROCESS_INIT;
@@ -758,7 +796,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL);
- if (auto_gc && too_many_loose_objects())
+ if (opts.auto_flag && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));
@@ -773,26 +811,6 @@ static const char *const builtin_maintenance_run_usage[] = {
NULL
};
-enum schedule_priority {
- SCHEDULE_NONE = 0,
- SCHEDULE_WEEKLY = 1,
- SCHEDULE_DAILY = 2,
- SCHEDULE_HOURLY = 3,
-};
-
-static enum schedule_priority parse_schedule(const char *value)
-{
- if (!value)
- return SCHEDULE_NONE;
- if (!strcasecmp(value, "hourly"))
- return SCHEDULE_HOURLY;
- if (!strcasecmp(value, "daily"))
- return SCHEDULE_DAILY;
- if (!strcasecmp(value, "weekly"))
- return SCHEDULE_WEEKLY;
- return SCHEDULE_NONE;
-}
-
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
int unset)
{
@@ -809,12 +827,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
return 0;
}
-struct maintenance_run_opts {
- int auto_flag;
- int quiet;
- enum schedule_priority schedule;
-};
-
/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)
@@ -1296,7 +1308,7 @@ static struct maintenance_task tasks[] = {
[TASK_PACK_REFS] = {
"pack-refs",
maintenance_task_pack_refs,
- NULL,
+ pack_refs_condition,
},
};
@@ -1543,19 +1555,18 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
if (!found) {
int rc;
- char *user_config = NULL, *xdg_config = NULL;
+ char *global_config_file = NULL;
if (!config_file) {
- git_global_config(&user_config, &xdg_config);
- config_file = user_config;
- if (!user_config)
- die(_("$HOME not set"));
+ global_config_file = git_global_config();
+ config_file = global_config_file;
}
+ if (!config_file)
+ die(_("$HOME not set"));
rc = git_config_set_multivar_in_file_gently(
config_file, "maintenance.repo", maintpath,
- CONFIG_REGEX_NONE, 0);
- free(user_config);
- free(xdg_config);
+ CONFIG_REGEX_NONE, NULL, 0);
+ free(global_config_file);
if (rc)
die(_("unable to add '%s' value of '%s'"),
@@ -1612,18 +1623,18 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
if (found) {
int rc;
- char *user_config = NULL, *xdg_config = NULL;
+ char *global_config_file = NULL;
+
if (!config_file) {
- git_global_config(&user_config, &xdg_config);
- config_file = user_config;
- if (!user_config)
- die(_("$HOME not set"));
+ global_config_file = git_global_config();
+ config_file = global_config_file;
}
+ if (!config_file)
+ die(_("$HOME not set"));
rc = git_config_set_multivar_in_file_gently(
- config_file, key, NULL, maintpath,
+ config_file, key, NULL, maintpath, NULL,
CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
- free(user_config);
- free(xdg_config);
+ free(global_config_file);
if (rc &&
(!force || rc == CONFIG_NOTHING_SET))
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 20d0dfe..66a7389 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -4,7 +4,6 @@
#include "builtin.h"
#include "commit.h"
#include "tar.h"
-#include "quote.h"
static const char builtin_get_tar_commit_id_usage[] =
"git get-tar-commit-id";
diff --git a/builtin/grep.c b/builtin/grep.c
index fe78d4c..5777ba8 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -9,15 +9,11 @@
#include "hex.h"
#include "repository.h"
#include "config.h"
-#include "blob.h"
-#include "tree.h"
-#include "commit.h"
#include "tag.h"
#include "tree-walk.h"
#include "parse-options.h"
#include "string-list.h"
#include "run-command.h"
-#include "userdiff.h"
#include "grep.h"
#include "quote.h"
#include "dir.h"
@@ -531,7 +527,7 @@ static int grep_submodule(struct grep_opt *opt,
strbuf_addstr(&base, filename);
strbuf_addch(&base, '/');
- init_tree_desc(&tree, data, size);
+ init_tree_desc(&tree, oid, data, size);
hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
object_type == OBJ_COMMIT);
strbuf_release(&base);
@@ -575,7 +571,9 @@ static int grep_cache(struct grep_opt *opt,
data = repo_read_object_file(the_repository, &ce->oid,
&type, &size);
- init_tree_desc(&tree, data, size);
+ if (!data)
+ die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
+ init_tree_desc(&tree, &ce->oid, data, size);
hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
strbuf_setlen(&name, name_base_len);
@@ -671,7 +669,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
oid_to_hex(&entry.oid));
strbuf_addch(base, '/');
- init_tree_desc(&sub, data, size);
+ init_tree_desc(&sub, &entry.oid, data, size);
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
check_attr);
free(data);
@@ -715,7 +713,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_add(&base, name, len);
strbuf_addch(&base, ':');
}
- init_tree_desc(&tree, data, size);
+ init_tree_desc(&tree, &obj->oid, data, size);
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
obj->type == OBJ_COMMIT);
strbuf_release(&base);
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 5ffec99..82ca6d2 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -14,7 +14,6 @@
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
-#include "exec-cmd.h"
#include "setup.h"
#include "strbuf.h"
#include "write-or-die.h"
diff --git a/builtin/hook.c b/builtin/hook.c
index 09b51a6..5234693 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -3,7 +3,6 @@
#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
-#include "strbuf.h"
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index dda94a9..856428f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -8,11 +8,9 @@
#include "csum-file.h"
#include "blob.h"
#include "commit.h"
-#include "tag.h"
#include "tree.h"
#include "progress.h"
#include "fsck.h"
-#include "exec-cmd.h"
#include "strbuf.h"
#include "streaming.h"
#include "thread-utils.h"
@@ -26,7 +24,7 @@
#include "setup.h"
static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
+"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict[=<msg-id>=<severity>...]] [--fsck-objects[=<msg-id>=<severity>...]] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
struct object_entry {
struct pack_idx_entry idx;
@@ -1257,6 +1255,7 @@ static void resolve_deltas(void)
base_cache_limit = delta_base_cache_limit * nr_threads;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
+ work_lock();
for (i = 0; i < nr_threads; i++) {
int ret = pthread_create(&thread_data[i].thread, NULL,
threaded_second_pass, thread_data + i);
@@ -1264,6 +1263,7 @@ static void resolve_deltas(void)
die(_("unable to create thread: %s"),
strerror(ret));
}
+ work_unlock();
for (i = 0; i < nr_threads; i++)
pthread_join(thread_data[i].thread, NULL);
cleanup_thread();
@@ -1524,14 +1524,12 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
struct strbuf pack_name = STRBUF_INIT;
struct strbuf index_name = STRBUF_INIT;
struct strbuf rev_index_name = STRBUF_INIT;
- int err;
if (!from_stdin) {
close(input_fd);
} else {
fsync_component_or_die(FSYNC_COMPONENT_PACK, output_fd, curr_pack_name);
- err = close(output_fd);
- if (err)
+ if (close(output_fd))
die_errno(_("error while closing pack file"));
}
@@ -1566,17 +1564,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
- /*
- * Let's just mimic git-unpack-objects here and write
- * the last part of the input buffer to stdout.
- */
- while (input_len) {
- err = xwrite(1, input_buffer + input_offset, input_len);
- if (err <= 0)
- break;
- input_len -= err;
- input_offset += err;
- }
+ /* Write the last part of the buffer to stdout */
+ write_in_full(1, input_buffer + input_offset, input_len);
}
strbuf_release(&rev_index_name);
@@ -1785,8 +1774,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
} else if (!strcmp(arg, "--check-self-contained-and-connected")) {
strict = 1;
check_self_contained_and_connected = 1;
- } else if (!strcmp(arg, "--fsck-objects")) {
+ } else if (skip_to_optional_arg(arg, "--fsck-objects", &arg)) {
do_fsck_object = 1;
+ fsck_set_msg_types(&fsck_options, arg);
} else if (!strcmp(arg, "--verify")) {
verify = 1;
} else if (!strcmp(arg, "--verify-stat")) {
diff --git a/builtin/init-db.c b/builtin/init-db.c
index cb727c8..0170469 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -5,12 +5,13 @@
*/
#include "builtin.h"
#include "abspath.h"
-#include "config.h"
#include "environment.h"
#include "gettext.h"
#include "object-file.h"
#include "parse-options.h"
#include "path.h"
+#include "refs.h"
+#include "repository.h"
#include "setup.h"
#include "strbuf.h"
@@ -57,6 +58,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
static const char *const init_db_usage[] = {
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
" [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+ " [--ref-format=<format>]\n"
" [-b <branch-name> | --initial-branch=<branch-name>]\n"
" [--shared[=<permissions>]] [<directory>]"),
NULL
@@ -76,8 +78,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *template_dir = NULL;
unsigned int flags = 0;
const char *object_format = NULL;
+ const char *ref_format = NULL;
const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
+ unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
int init_shared_repository = -1;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
@@ -95,6 +99,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
N_("override the name of the initial branch")),
OPT_STRING(0, "object-format", &object_format, N_("hash"),
N_("specify the hash algorithm to use")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_END()
};
@@ -158,6 +164,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
die(_("unknown hash algorithm '%s'"), object_format);
}
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
@@ -236,5 +248,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
flags |= INIT_DB_EXIST_OK;
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
- initial_branch, init_shared_repository, flags);
+ ref_storage_format, initial_branch,
+ init_shared_repository, flags);
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 033bd15..8768bfe 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -9,12 +9,13 @@
#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
+#include "tempfile.h"
#include "trailer.h"
#include "config.h"
static const char * const git_interpret_trailers_usage[] = {
N_("git interpret-trailers [--in-place] [--trim-empty]\n"
- " [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
+ " [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"),
NULL
};
@@ -91,6 +92,102 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
return 0;
}
+static struct tempfile *trailers_tempfile;
+
+static FILE *create_in_place_tempfile(const char *file)
+{
+ struct stat st;
+ struct strbuf filename_template = STRBUF_INIT;
+ const char *tail;
+ FILE *outfile;
+
+ if (stat(file, &st))
+ die_errno(_("could not stat %s"), file);
+ if (!S_ISREG(st.st_mode))
+ die(_("file %s is not a regular file"), file);
+ if (!(st.st_mode & S_IWUSR))
+ die(_("file %s is not writable by user"), file);
+
+ /* Create temporary file in the same directory as the original */
+ tail = strrchr(file, '/');
+ if (tail)
+ strbuf_add(&filename_template, file, tail - file + 1);
+ strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
+
+ trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
+ strbuf_release(&filename_template);
+ outfile = fdopen_tempfile(trailers_tempfile, "w");
+ if (!outfile)
+ die_errno(_("could not open temporary file"));
+
+ return outfile;
+}
+
+static void read_input_file(struct strbuf *sb, const char *file)
+{
+ if (file) {
+ if (strbuf_read_file(sb, file, 0) < 0)
+ die_errno(_("could not read input file '%s'"), file);
+ } else {
+ if (strbuf_read(sb, fileno(stdin), 0) < 0)
+ die_errno(_("could not read from stdin"));
+ }
+}
+
+static void interpret_trailers(const struct process_trailer_options *opts,
+ struct list_head *new_trailer_head,
+ const char *file)
+{
+ LIST_HEAD(head);
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf trailer_block = STRBUF_INIT;
+ struct trailer_info info;
+ FILE *outfile = stdout;
+
+ trailer_config_init();
+
+ read_input_file(&sb, file);
+
+ if (opts->in_place)
+ outfile = create_in_place_tempfile(file);
+
+ parse_trailers(opts, &info, sb.buf, &head);
+
+ /* Print the lines before the trailers */
+ if (!opts->only_trailers)
+ fwrite(sb.buf, 1, info.trailer_block_start, outfile);
+
+ if (!opts->only_trailers && !info.blank_line_before_trailer)
+ fprintf(outfile, "\n");
+
+
+ if (!opts->only_input) {
+ LIST_HEAD(config_head);
+ LIST_HEAD(arg_head);
+ parse_trailers_from_config(&config_head);
+ parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
+ list_splice(&config_head, &arg_head);
+ process_trailers_lists(&head, &arg_head);
+ }
+
+ /* Print trailer block. */
+ format_trailers(opts, &head, &trailer_block);
+ free_trailers(&head);
+ fwrite(trailer_block.buf, 1, trailer_block.len, outfile);
+ strbuf_release(&trailer_block);
+
+ /* Print the lines after the trailers as is */
+ if (!opts->only_trailers)
+ fwrite(sb.buf + info.trailer_block_end, 1, sb.len - info.trailer_block_end, outfile);
+ trailer_info_release(&info);
+
+ if (opts->in_place)
+ if (rename_tempfile(&trailers_tempfile, file))
+ die_errno(_("could not rename temporary file to %s"), file);
+
+ strbuf_release(&sb);
+}
+
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
{
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
@@ -132,11 +229,11 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
if (argc) {
int i;
for (i = 0; i < argc; i++)
- process_trailers(argv[i], &opts, &trailers);
+ interpret_trailers(&opts, &trailers, argv[i]);
} else {
if (opts.in_place)
die(_("no input file given for in-place editing"));
- process_trailers(NULL, &opts, &trailers);
+ interpret_trailers(&opts, &trailers, NULL);
}
new_trailers_clear(&trailers);
diff --git a/builtin/log.c b/builtin/log.c
index ba775d7..c0a8bb9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -26,7 +26,6 @@
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
-#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
#include "string-list.h"
@@ -36,7 +35,6 @@
#include "streaming.h"
#include "version.h"
#include "mailmap.h"
-#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
#include "repository.h"
@@ -594,8 +592,11 @@ static int git_log_config(const char *var, const char *value,
decoration_style = 0; /* maybe warn? */
return 0;
}
- if (!strcmp(var, "log.diffmerges"))
+ if (!strcmp(var, "log.diffmerges")) {
+ if (!value)
+ return config_error_nonbool(var);
return diff_merges_config(value);
+ }
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
@@ -1296,7 +1297,7 @@ static void prepare_cover_text(struct pretty_print_context *pp,
subject = subject_sb.buf;
do_pp:
- pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
+ pp_email_subject(pp, &subject, sb, encoding, need_8bit_cte);
pp_remainder(pp, &body, sb, 0);
strbuf_release(&description_sb);
@@ -1363,12 +1364,13 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode.type = DATE_RFC2822;
pp.rev = rev;
- pp.print_email_subject = 1;
+ pp.encode_email_headers = rev->encode_email_headers;
pp_user_info(&pp, NULL, &sb, committer, encoding);
prepare_cover_text(&pp, description_file, branch_name, &sb,
encoding, need_8bit_cte);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
+ free(pp.after_subject);
strbuf_release(&sb);
shortlog_init(&log);
@@ -1623,7 +1625,7 @@ static struct commit *get_base_commit(const char *base_commit,
{
struct commit *base = NULL;
struct commit **rev;
- int i = 0, rev_nr = 0, auto_select, die_on_failure;
+ int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
switch (auto_base) {
case AUTO_BASE_NEVER:
@@ -1656,7 +1658,7 @@ static struct commit *get_base_commit(const char *base_commit,
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
- struct commit_list *base_list;
+ struct commit_list *base_list = NULL;
struct commit *commit;
struct object_id oid;
@@ -1667,11 +1669,12 @@ static struct commit *get_base_commit(const char *base_commit,
return NULL;
}
commit = lookup_commit_or_die(&oid, "upstream base");
- base_list = repo_get_merge_bases_many(the_repository,
- commit, total,
- list);
- /* There should be one and only one merge base. */
- if (!base_list || base_list->next) {
+ if (repo_get_merge_bases_many(the_repository,
+ commit, total,
+ list,
+ &base_list) < 0 ||
+ /* There should be one and only one merge base. */
+ !base_list || base_list->next) {
if (die_on_failure) {
die(_("could not find exact merge base"));
} else {
@@ -1702,11 +1705,11 @@ static struct commit *get_base_commit(const char *base_commit,
*/
while (rev_nr > 1) {
for (i = 0; i < rev_nr / 2; i++) {
- struct commit_list *merge_base;
- merge_base = repo_get_merge_bases(the_repository,
- rev[2 * i],
- rev[2 * i + 1]);
- if (!merge_base || merge_base->next) {
+ struct commit_list *merge_base = NULL;
+ if (repo_get_merge_bases(the_repository,
+ rev[2 * i],
+ rev[2 * i + 1], &merge_base) < 0 ||
+ !merge_base || merge_base->next) {
if (die_on_failure) {
die(_("failed to find exact merge base"));
} else {
@@ -1723,7 +1726,10 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!repo_in_merge_bases(the_repository, base, rev[0])) {
+ ret = repo_in_merge_bases(the_repository, base, rev[0]);
+ if (ret < 0)
+ exit(128);
+ if (!ret) {
if (die_on_failure) {
die(_("base commit should be the ancestor of revision list"));
} else {
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a0229c3..6eeb5cb 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -14,19 +14,15 @@
#include "gettext.h"
#include "object-name.h"
#include "strbuf.h"
-#include "tree.h"
-#include "cache-tree.h"
#include "parse-options.h"
#include "resolve-undo.h"
#include "string-list.h"
#include "path.h"
#include "pathspec.h"
#include "read-cache.h"
-#include "run-command.h"
#include "setup.h"
#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
#include "object-store.h"
#include "hex.h"
@@ -270,7 +266,6 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
struct strbuf sb = STRBUF_INIT;
while (strbuf_expand_step(&sb, &format)) {
- const char *end;
size_t len;
struct stat st;
@@ -278,12 +273,6 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
strbuf_addch(&sb, '%');
else if ((len = strbuf_expand_literal(&sb, format)))
format += len;
- else if (*format != '(')
- die(_("bad ls-files format: element '%s' "
- "does not start with '('"), format);
- else if (!(end = strchr(format + 1, ')')))
- die(_("bad ls-files format: element '%s' "
- "does not end in ')'"), format);
else if (skip_prefix(format, "(objectmode)", &format))
strbuf_addf(&sb, "%06o", ce->ce_mode);
else if (skip_prefix(format, "(objectname)", &format))
@@ -312,8 +301,7 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
else if (skip_prefix(format, "(path)", &format))
write_name_to_buf(&sb, fullname);
else
- die(_("bad ls-files format: %%%.*s"),
- (int)(end - format + 1), format);
+ strbuf_expand_bad_format(format, "ls-files");
}
strbuf_addch(&sb, line_terminator);
fwrite(sb.buf, sb.len, 1, stdout);
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index fc76575..e8d65eb 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -5,7 +5,6 @@
#include "pkt-line.h"
#include "ref-filter.h"
#include "remote.h"
-#include "refs.h"
#include "parse-options.h"
#include "wildmatch.h"
@@ -58,6 +57,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
struct transport *transport;
const struct ref *ref;
struct ref_array ref_array;
+ struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct option options[] = {
@@ -141,13 +141,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
item->symref = xstrdup_or_null(ref->symref);
}
- if (sorting_options.nr) {
- struct ref_sorting *sorting;
-
- sorting = ref_sorting_options(&sorting_options);
- ref_array_sort(sorting, &ref_array);
- ref_sorting_release(sorting);
- }
+ sorting = ref_sorting_options(&sorting_options);
+ ref_array_sort(sorting, &ref_array);
for (i = 0; i < ref_array.nr; i++) {
const struct ref_array_item *ref = ref_array.items[i];
@@ -157,6 +152,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
status = 0; /* we found something */
}
+ ref_sorting_release(sorting);
ref_array_clear(&ref_array);
if (transport_disconnect(transport))
status = 1;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 209d2dc..7bf84b2 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -9,9 +9,7 @@
#include "hex.h"
#include "object-name.h"
#include "object-store-ll.h"
-#include "blob.h"
#include "tree.h"
-#include "commit.h"
#include "path.h"
#include "quote.h"
#include "parse-options.h"
@@ -102,19 +100,12 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
return 0;
while (strbuf_expand_step(&sb, &format)) {
- const char *end;
size_t len;
if (skip_prefix(format, "%", &format))
strbuf_addch(&sb, '%');
else if ((len = strbuf_expand_literal(&sb, format)))
format += len;
- else if (*format != '(')
- die(_("bad ls-tree format: element '%s' "
- "does not start with '('"), format);
- else if (!(end = strchr(format + 1, ')')))
- die(_("bad ls-tree format: element '%s' "
- "does not end in ')'"), format);
else if (skip_prefix(format, "(objectmode)", &format))
strbuf_addf(&sb, "%06o", mode);
else if (skip_prefix(format, "(objecttype)", &format))
@@ -137,8 +128,7 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
strbuf_setlen(base, baselen);
strbuf_release(&sbuf);
} else
- die(_("bad ls-tree format: %%%.*s"),
- (int)(end - format + 1), format);
+ strbuf_expand_bad_format(format, "ls-tree");
}
strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
fwrite(sb.buf, sb.len, 1, stdout);
@@ -377,6 +367,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
OPT_END()
};
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+ struct object_context obj_context;
int ret;
git_config(git_default_config, NULL);
@@ -408,7 +399,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
ls_tree_usage, ls_tree_options);
if (argc < 1)
usage_with_options(ls_tree_usage, ls_tree_options);
- if (repo_get_oid(the_repository, argv[0], &oid))
+ if (get_oid_with_context(the_repository, argv[0],
+ GET_OID_HASH_ANY, &oid,
+ &obj_context))
die("Not a valid object name %s", argv[0]);
/*
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 53b55dd..53a2264 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -6,7 +6,6 @@
#include "abspath.h"
#include "environment.h"
#include "gettext.h"
-#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
#include "parse-options.h"
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index e68b7fe..5a8e729 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -3,9 +3,6 @@
#include "commit.h"
#include "gettext.h"
#include "hex.h"
-#include "refs.h"
-#include "diff.h"
-#include "revision.h"
#include "object-name.h"
#include "parse-options.h"
#include "repository.h"
@@ -13,10 +10,13 @@
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
- struct commit_list *result, *r;
+ struct commit_list *result = NULL, *r;
- result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
- rev_nr - 1, rev + 1);
+ if (repo_get_merge_bases_many_dirty(the_repository, rev[0],
+ rev_nr - 1, rev + 1, &result) < 0) {
+ free_commit_list(result);
+ return -1;
+ }
if (!result)
return 1;
@@ -77,13 +77,17 @@ static int handle_independent(int count, const char **args)
static int handle_octopus(int count, const char **args, int show_all)
{
struct commit_list *revs = NULL;
- struct commit_list *result, *rev;
+ struct commit_list *result = NULL, *rev;
int i;
for (i = count - 1; i >= 0; i--)
commit_list_insert(get_commit_reference(args[i]), &revs);
- result = get_octopus_merge_bases(revs);
+ if (get_octopus_merge_bases(revs, &result) < 0) {
+ free_commit_list(revs);
+ free_commit_list(result);
+ return 128;
+ }
free_commit_list(revs);
reduce_heads_replace(&result);
@@ -103,12 +107,16 @@ static int handle_octopus(int count, const char **args, int show_all)
static int handle_is_ancestor(int argc, const char **argv)
{
struct commit *one, *two;
+ int ret;
if (argc != 2)
die("--is-ancestor takes exactly two commits");
one = get_commit_reference(argv[0]);
two = get_commit_reference(argv[1]);
- if (repo_in_merge_bases(the_repository, one, two))
+ ret = repo_in_merge_bases(the_repository, one, two);
+ if (ret < 0)
+ exit(128);
+ if (ret)
return 0;
else
return 1;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 832c93d..1f98733 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "abspath.h"
+#include "diff.h"
#include "hex.h"
#include "object-name.h"
#include "object-store.h"
@@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int set_diff_algorithm(xpparam_t *xpp,
+ const char *alg)
+{
+ long diff_algorithm = parse_algorithm_value(alg);
+ if (diff_algorithm < 0)
+ return -1;
+ xpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+ return 0;
+}
+
+static int diff_algorithm_cb(const struct option *opt,
+ const char *arg, int unset)
+{
+ xpparam_t *xpp = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (set_diff_algorithm(xpp, arg))
+ return error(_("option diff-algorithm accepts \"myers\", "
+ "\"minimal\", \"patience\" and \"histogram\""));
+
+ return 0;
+}
+
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
const char *names[3] = { 0 };
@@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
XDL_MERGE_FAVOR_THEIRS),
OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
XDL_MERGE_FAVOR_UNION),
+ OPT_CALLBACK_F(0, "diff-algorithm", &xmp.xpp, N_("<algorithm>"),
+ N_("choose a diff algorithm"),
+ PARSE_OPT_NONEG, diff_algorithm_cb),
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
N_("for conflicts, use this marker size")),
OPT__QUIET(&quiet, N_("do not warn about conflicts")),
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 3366699..c2ce044 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,13 +1,10 @@
#include "builtin.h"
#include "advice.h"
-#include "commit.h"
#include "gettext.h"
#include "hash.h"
-#include "tag.h"
#include "merge-recursive.h"
#include "object-name.h"
#include "repository.h"
-#include "xdiff-interface.h"
static const char builtin_merge_recursive_usage[] =
"git %s <base>... -- <head> <remote> ...";
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index a35e045..8bdb439 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -13,7 +13,6 @@
#include "parse-options.h"
#include "repository.h"
#include "blob.h"
-#include "exec-cmd.h"
#include "merge-blobs.h"
#include "quote.h"
#include "tree.h"
@@ -430,41 +429,56 @@ static int real_merge(struct merge_tree_options *o,
struct merge_options opt;
copy_merge_options(&opt, &o->merge_options);
- parent1 = get_merge_parent(branch1);
- if (!parent1)
- help_unknown_ref(branch1, "merge-tree",
- _("not something we can merge"));
-
- parent2 = get_merge_parent(branch2);
- if (!parent2)
- help_unknown_ref(branch2, "merge-tree",
- _("not something we can merge"));
-
opt.show_rename_progress = 0;
opt.branch1 = branch1;
opt.branch2 = branch2;
if (merge_base) {
- struct commit *base_commit;
struct tree *base_tree, *parent1_tree, *parent2_tree;
- base_commit = lookup_commit_reference_by_name(merge_base);
- if (!base_commit)
- die(_("could not lookup commit '%s'"), merge_base);
+ /*
+ * We actually only need the trees because we already
+ * have a merge base.
+ */
+ struct object_id base_oid, head_oid, merge_oid;
+
+ if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
+ die(_("could not parse as tree '%s'"), merge_base);
+ base_tree = parse_tree_indirect(&base_oid);
+ if (!base_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
+ if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
+ die(_("could not parse as tree '%s'"), branch1);
+ parent1_tree = parse_tree_indirect(&head_oid);
+ if (!parent1_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
+ if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
+ die(_("could not parse as tree '%s'"), branch2);
+ parent2_tree = parse_tree_indirect(&merge_oid);
+ if (!parent2_tree)
+ die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
opt.ancestor = merge_base;
- base_tree = repo_get_commit_tree(the_repository, base_commit);
- parent1_tree = repo_get_commit_tree(the_repository, parent1);
- parent2_tree = repo_get_commit_tree(the_repository, parent2);
merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
} else {
+ parent1 = get_merge_parent(branch1);
+ if (!parent1)
+ help_unknown_ref(branch1, "merge-tree",
+ _("not something we can merge"));
+
+ parent2 = get_merge_parent(branch2);
+ if (!parent2)
+ help_unknown_ref(branch2, "merge-tree",
+ _("not something we can merge"));
+
/*
* Get the merge bases, in reverse order; see comment above
* merge_incore_recursive in merge-ort.h
*/
- merge_bases = repo_get_merge_bases(the_repository, parent1,
- parent2);
+ if (repo_get_merge_bases(the_repository, parent1,
+ parent2, &merge_bases) < 0)
+ exit(128);
if (!merge_bases && !o->allow_unrelated_histories)
die(_("refusing to merge unrelated histories"));
merge_bases = reverse_commit_list(merge_bases);
@@ -549,7 +563,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG),
OPT_STRING(0, "merge-base",
&merge_base,
- N_("commit"),
+ N_("tree-ish"),
N_("specify a merge-base for the merge")),
OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
N_("option for selected merge strategy")),
@@ -577,7 +591,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (o.mode == MODE_TRIVIAL)
die(_("--trivial-merge is incompatible with all other options"));
if (merge_base)
- die(_("--merge-base is incompatible with --stdin"));
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--merge-base", "--stdin");
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct strbuf **split;
diff --git a/builtin/merge.c b/builtin/merge.c
index d748d46..6f4fec8 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -31,8 +31,6 @@
#include "unpack-trees.h"
#include "cache-tree.h"
#include "dir.h"
-#include "utf8.h"
-#include "log-tree.h"
#include "color.h"
#include "rerere.h"
#include "help.h"
@@ -42,10 +40,8 @@
#include "resolve-undo.h"
#include "remote.h"
#include "fmt-merge-msg.h"
-#include "gpg-interface.h"
#include "sequencer.h"
#include "string-list.h"
-#include "packfile.h"
#include "tag.h"
#include "alias.h"
#include "branch.h"
@@ -196,8 +192,7 @@ static struct strategy *get_strategy(const char *name)
int j, found = 0;
struct cmdname *ent = main_cmds.names[i];
for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
- if (!strncmp(ent->name, all_strategy[j].name, ent->len)
- && !all_strategy[j].name[ent->len])
+ if (!xstrncmpz(all_strategy[j].name, ent->name, ent->len))
found = 1;
if (!found)
add_cmdname(&not_strategies, ent->name, ent->len);
@@ -480,7 +475,7 @@ static void finish(struct commit *head_commit,
run_hooks_l("post-merge", squash ? "1" : "0", NULL);
if (new_head)
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
strbuf_release(&reflog_message);
}
@@ -682,7 +677,8 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
cache_tree_free(&the_index.cache_tree);
for (i = 0; i < nr_trees; i++) {
parse_tree(trees[i]);
- init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+ init_tree_desc(t+i, &trees[i]->object.oid,
+ trees[i]->buffer, trees[i]->size);
}
if (unpack_trees(nr_trees, t, &opts))
return -1;
@@ -826,7 +822,7 @@ static const char scissors_editor_comment[] =
N_("An empty message aborts the commit.\n");
static const char no_scissors_editor_comment[] =
-N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
+N_("Lines starting with '%s' will be ignored, and an empty message aborts\n"
"the commit.\n");
static void write_merge_heads(struct commit_list *);
@@ -857,19 +853,19 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_addch(&msg, '\n');
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
wt_status_append_cut_line(&msg);
- strbuf_commented_addf(&msg, comment_line_char, "\n");
+ strbuf_commented_addf(&msg, comment_line_str, "\n");
}
- strbuf_commented_addf(&msg, comment_line_char,
+ strbuf_commented_addf(&msg, comment_line_str,
_(merge_editor_comment));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
- strbuf_commented_addf(&msg, comment_line_char,
+ strbuf_commented_addf(&msg, comment_line_str,
_(scissors_editor_comment));
else
- strbuf_commented_addf(&msg, comment_line_char,
- _(no_scissors_editor_comment), comment_line_char);
+ strbuf_commented_addf(&msg, comment_line_str,
+ _(no_scissors_editor_comment), comment_line_str);
}
if (signoff)
- append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
+ append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
@@ -1319,7 +1315,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (abort_current_merge) {
int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL};
- struct strbuf stash_oid = STRBUF_INIT;
+ char stash_oid_hex[GIT_MAX_HEXSZ + 1];
+ struct object_id stash_oid = {0};
if (orig_argc != 2)
usage_msg_opt(_("--abort expects no arguments"),
@@ -1328,17 +1325,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
- if (read_oneliner(&stash_oid, git_path_merge_autostash(the_repository),
- READ_ONELINER_SKIP_IF_EMPTY))
- unlink(git_path_merge_autostash(the_repository));
+ if (!read_ref("MERGE_AUTOSTASH", &stash_oid))
+ delete_ref("", "MERGE_AUTOSTASH", &stash_oid, REF_NO_DEREF);
/* Invoke 'git reset --merge' */
ret = cmd_reset(nargc, nargv, prefix);
- if (stash_oid.len)
- apply_autostash_oid(stash_oid.buf);
+ if (!is_null_oid(&stash_oid)) {
+ oid_to_hex_r(stash_oid_hex, &stash_oid);
+ apply_autostash_oid(stash_oid_hex);
+ }
- strbuf_release(&stash_oid);
goto done;
}
@@ -1517,13 +1514,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!remoteheads)
; /* already up-to-date */
- else if (!remoteheads->next)
- common = repo_get_merge_bases(the_repository, head_commit,
- remoteheads->item);
- else {
+ else if (!remoteheads->next) {
+ if (repo_get_merge_bases(the_repository, head_commit,
+ remoteheads->item, &common) < 0) {
+ ret = 2;
+ goto done;
+ }
+ } else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
- common = get_octopus_merge_bases(list);
+ if (get_octopus_merge_bases(list, &common) < 0) {
+ free(list);
+ ret = 2;
+ goto done;
+ }
free(list);
}
@@ -1567,13 +1571,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
if (autostash)
- create_autostash(the_repository,
- git_path_merge_autostash(the_repository));
+ create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
if (checkout_fast_forward(the_repository,
&head_commit->object.oid,
&commit->object.oid,
overwrite_ignore)) {
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
ret = 1;
goto done;
}
@@ -1631,7 +1634,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
struct commit_list *j;
for (j = remoteheads; j; j = j->next) {
- struct commit_list *common_one;
+ struct commit_list *common_one = NULL;
struct commit *common_item;
/*
@@ -1639,9 +1642,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = repo_get_merge_bases(the_repository,
- head_commit,
- j->item);
+ if (repo_get_merge_bases(the_repository, head_commit,
+ j->item, &common_one) < 0)
+ exit(128);
+
common_item = common_one->item;
free_commit_list(common_one);
if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
@@ -1659,8 +1663,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die_ff_impossible();
if (autostash)
- create_autostash(the_repository,
- git_path_merge_autostash(the_repository));
+ create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
/* We are going to make a new commit. */
git_committer_info(IDENT_STRICT);
@@ -1745,7 +1748,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
fprintf(stderr, _("Merge with strategy %s failed.\n"),
use_strategies[0]->name);
- apply_autostash(git_path_merge_autostash(the_repository));
+ apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
ret = 2;
goto done;
} else if (best_strategy == wt_strategy)
diff --git a/builtin/mktag.c b/builtin/mktag.c
index d8e0b5a..4767f1a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -3,7 +3,6 @@
#include "hex.h"
#include "parse-options.h"
#include "strbuf.h"
-#include "tag.h"
#include "replace-object.h"
#include "object-file.h"
#include "object-store-ll.h"
diff --git a/builtin/mv.c b/builtin/mv.c
index c596515..22e64fc 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -15,7 +15,6 @@
#include "pathspec.h"
#include "lockfile.h"
#include "dir.h"
-#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
#include "read-cache-ll.h"
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 2dd1807..ad9930c 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -15,6 +15,7 @@
#include "commit-slab.h"
#include "commit-graph.h"
#include "wildmatch.h"
+#include "mem-pool.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@@ -155,30 +156,25 @@ static struct rev_name *create_or_update_name(struct commit *commit,
return name;
}
-static char *get_parent_name(const struct rev_name *name, int parent_number)
+static char *get_parent_name(const struct rev_name *name, int parent_number,
+ struct mem_pool *string_pool)
{
- struct strbuf sb = STRBUF_INIT;
size_t len;
strip_suffix(name->tip_name, "^0", &len);
if (name->generation > 0) {
- strbuf_grow(&sb, len +
- 1 + decimal_width(name->generation) +
- 1 + decimal_width(parent_number));
- strbuf_addf(&sb, "%.*s~%d^%d", (int)len, name->tip_name,
- name->generation, parent_number);
+ return mem_pool_strfmt(string_pool, "%.*s~%d^%d",
+ (int)len, name->tip_name,
+ name->generation, parent_number);
} else {
- strbuf_grow(&sb, len +
- 1 + decimal_width(parent_number));
- strbuf_addf(&sb, "%.*s^%d", (int)len, name->tip_name,
- parent_number);
+ return mem_pool_strfmt(string_pool, "%.*s^%d",
+ (int)len, name->tip_name, parent_number);
}
- return strbuf_detach(&sb, NULL);
}
static void name_rev(struct commit *start_commit,
const char *tip_name, timestamp_t taggerdate,
- int from_tag, int deref)
+ int from_tag, int deref, struct mem_pool *string_pool)
{
struct prio_queue queue;
struct commit *commit;
@@ -195,9 +191,10 @@ static void name_rev(struct commit *start_commit,
if (!start_name)
return;
if (deref)
- start_name->tip_name = xstrfmt("%s^0", tip_name);
+ start_name->tip_name = mem_pool_strfmt(string_pool, "%s^0",
+ tip_name);
else
- start_name->tip_name = xstrdup(tip_name);
+ start_name->tip_name = mem_pool_strdup(string_pool, tip_name);
memset(&queue, 0, sizeof(queue)); /* Use the prio_queue as LIFO */
prio_queue_put(&queue, start_commit);
@@ -235,7 +232,8 @@ static void name_rev(struct commit *start_commit,
if (parent_number > 1)
parent_name->tip_name =
get_parent_name(name,
- parent_number);
+ parent_number,
+ string_pool);
else
parent_name->tip_name = name->tip_name;
ALLOC_GROW(parents_to_queue,
@@ -415,7 +413,7 @@ static int name_ref(const char *path, const struct object_id *oid,
return 0;
}
-static void name_tips(void)
+static void name_tips(struct mem_pool *string_pool)
{
int i;
@@ -428,7 +426,7 @@ static void name_tips(void)
struct tip_table_entry *e = &tip_table.table[i];
if (e->commit) {
name_rev(e->commit, e->refname, e->taggerdate,
- e->from_tag, e->deref);
+ e->from_tag, e->deref, string_pool);
}
}
}
@@ -561,6 +559,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
+ struct mem_pool string_pool;
struct object_array revs = OBJECT_ARRAY_INIT;
int all = 0, annotate_stdin = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
@@ -587,6 +586,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ mem_pool_init(&string_pool, 0);
init_commit_rev_name(&rev_names);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
@@ -648,7 +648,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
adjust_cutoff_timestamp_for_slop();
for_each_ref(name_ref, &data);
- name_tips();
+ name_tips(&string_pool);
if (annotate_stdin) {
struct strbuf sb = STRBUF_INIT;
@@ -676,6 +676,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
always, allow_undefined, data.name_only);
}
+ UNLEAK(string_pool);
UNLEAK(revs);
return 0;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 9f38863..cb01130 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -9,7 +9,6 @@
#include "builtin.h"
#include "config.h"
-#include "alloc.h"
#include "editor.h"
#include "environment.h"
#include "gettext.h"
@@ -19,7 +18,6 @@
#include "object-store-ll.h"
#include "path.h"
#include "repository.h"
-#include "blob.h"
#include "pretty.h"
#include "refs.h"
#include "exec-cmd.h"
@@ -181,7 +179,7 @@ static void write_commented_object(int fd, const struct object_id *object)
if (strbuf_read(&buf, show.out, 0) < 0)
die_errno(_("could not read 'show' output"));
- strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_str);
write_or_die(fd, cbuf.buf, cbuf.len);
strbuf_release(&cbuf);
@@ -209,10 +207,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
- comment_line_char);
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ comment_line_str);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
@@ -225,7 +223,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
die(_("please supply the note contents using either -m or -F option"));
}
if (d->stripspace)
- strbuf_stripspace(&d->buf, comment_line_char);
+ strbuf_stripspace(&d->buf, comment_line_str);
}
}
@@ -266,7 +264,7 @@ static void concat_messages(struct note_data *d)
if ((d->stripspace == UNSPECIFIED &&
d->messages[i]->stripspace == STRIPSPACE) ||
d->stripspace == STRIPSPACE)
- strbuf_stripspace(&d->buf, 0);
+ strbuf_stripspace(&d->buf, NULL);
strbuf_reset(&msg);
}
strbuf_release(&msg);
@@ -718,9 +716,11 @@ static int append_edit(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
- if (prev_buf && size)
+ if (!prev_buf)
+ die(_("unable to read %s"), oid_to_hex(note));
+ if (size)
strbuf_add(&buf, prev_buf, size);
- if (d.buf.len && prev_buf && size)
+ if (d.buf.len && size)
append_separator(&buf);
strbuf_insert(&d.buf, 0, buf.buf, buf.len);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 89a8b5a..baf0090 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -6,10 +6,8 @@
#include "config.h"
#include "attr.h"
#include "object.h"
-#include "blob.h"
#include "commit.h"
#include "tag.h"
-#include "tree.h"
#include "delta.h"
#include "pack.h"
#include "pack-revindex.h"
@@ -18,7 +16,6 @@
#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"
@@ -221,13 +218,19 @@ static int thin;
static int num_preferred_base;
static struct progress *progress_state;
-static struct packed_git *reuse_packfile;
+static struct bitmapped_pack *reuse_packfiles;
+static size_t reuse_packfiles_nr;
+static size_t reuse_packfiles_used_nr;
static uint32_t reuse_packfile_objects;
static struct bitmap *reuse_packfile_bitmap;
static int use_bitmap_index_default = 1;
static int use_bitmap_index = -1;
-static int allow_pack_reuse = 1;
+static enum {
+ NO_PACK_REUSE = 0,
+ SINGLE_PACK_REUSE,
+ MULTI_PACK_REUSE,
+} allow_pack_reuse = SINGLE_PACK_REUSE;
static enum {
WRITE_BITMAP_FALSE = 0,
WRITE_BITMAP_QUIET,
@@ -1013,7 +1016,9 @@ static off_t find_reused_offset(off_t where)
return reused_chunks[lo-1].difference;
}
-static void write_reused_pack_one(size_t pos, struct hashfile *out,
+static void write_reused_pack_one(struct packed_git *reuse_packfile,
+ size_t pos, struct hashfile *out,
+ off_t pack_start,
struct pack_window **w_curs)
{
off_t offset, next, cur;
@@ -1023,7 +1028,8 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
offset = pack_pos_to_offset(reuse_packfile, pos);
next = pack_pos_to_offset(reuse_packfile, pos + 1);
- record_reused_object(offset, offset - hashfile_total(out));
+ record_reused_object(offset,
+ offset - (hashfile_total(out) - pack_start));
cur = offset;
type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
@@ -1091,41 +1097,93 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
}
-static size_t write_reused_pack_verbatim(struct hashfile *out,
+static size_t write_reused_pack_verbatim(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *out,
+ off_t pack_start,
struct pack_window **w_curs)
{
- size_t pos = 0;
+ size_t pos = reuse_packfile->bitmap_pos;
+ size_t end;
+
+ if (pos % BITS_IN_EWORD) {
+ size_t word_pos = (pos / BITS_IN_EWORD);
+ size_t offset = pos % BITS_IN_EWORD;
+ size_t last;
+ eword_t word = reuse_packfile_bitmap->words[word_pos];
+
+ if (offset + reuse_packfile->bitmap_nr < BITS_IN_EWORD)
+ last = offset + reuse_packfile->bitmap_nr;
+ else
+ last = BITS_IN_EWORD;
+
+ for (; offset < last; offset++) {
+ if (word >> offset == 0)
+ return word_pos;
+ if (!bitmap_get(reuse_packfile_bitmap,
+ word_pos * BITS_IN_EWORD + offset))
+ return word_pos;
+ }
+
+ pos += BITS_IN_EWORD - (pos % BITS_IN_EWORD);
+ }
+
+ /*
+ * Now we're going to copy as many whole eword_t's as possible.
+ * "end" is the index of the last whole eword_t we copy, but
+ * there may be additional bits to process. Those are handled
+ * individually by write_reused_pack().
+ *
+ * Begin by advancing to the first word boundary in range of the
+ * bit positions occupied by objects in "reuse_packfile". Then
+ * pick the last word boundary in the same range. If we have at
+ * least one word's worth of bits to process, continue on.
+ */
+ end = reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr;
+ if (end % BITS_IN_EWORD)
+ end -= end % BITS_IN_EWORD;
+ if (pos >= end)
+ return reuse_packfile->bitmap_pos / BITS_IN_EWORD;
+
+ while (pos < end &&
+ reuse_packfile_bitmap->words[pos / BITS_IN_EWORD] == (eword_t)~0)
+ pos += BITS_IN_EWORD;
- while (pos < reuse_packfile_bitmap->word_alloc &&
- reuse_packfile_bitmap->words[pos] == (eword_t)~0)
- pos++;
+ if (pos > end)
+ pos = end;
- if (pos) {
- off_t to_write;
+ if (reuse_packfile->bitmap_pos < pos) {
+ off_t pack_start_off = pack_pos_to_offset(reuse_packfile->p, 0);
+ off_t pack_end_off = pack_pos_to_offset(reuse_packfile->p,
+ pos - reuse_packfile->bitmap_pos);
- written = (pos * BITS_IN_EWORD);
- to_write = pack_pos_to_offset(reuse_packfile, written)
- - sizeof(struct pack_header);
+ written += pos - reuse_packfile->bitmap_pos;
/* We're recording one chunk, not one object. */
- record_reused_object(sizeof(struct pack_header), 0);
+ record_reused_object(pack_start_off,
+ pack_start_off - (hashfile_total(out) - pack_start));
hashflush(out);
- copy_pack_data(out, reuse_packfile, w_curs,
- sizeof(struct pack_header), to_write);
+ copy_pack_data(out, reuse_packfile->p, w_curs,
+ pack_start_off, pack_end_off - pack_start_off);
display_progress(progress_state, written);
}
- return pos;
+ if (pos % BITS_IN_EWORD)
+ BUG("attempted to jump past a word boundary to %"PRIuMAX,
+ (uintmax_t)pos);
+ return pos / BITS_IN_EWORD;
}
-static void write_reused_pack(struct hashfile *f)
+static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *f)
{
- size_t i = 0;
+ size_t i = reuse_packfile->bitmap_pos / BITS_IN_EWORD;
uint32_t offset;
+ off_t pack_start = hashfile_total(f) - sizeof(struct pack_header);
struct pack_window *w_curs = NULL;
if (allow_ofs_delta)
- i = write_reused_pack_verbatim(f, &w_curs);
+ i = write_reused_pack_verbatim(reuse_packfile, f, pack_start,
+ &w_curs);
for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
eword_t word = reuse_packfile_bitmap->words[i];
@@ -1136,16 +1194,23 @@ static void write_reused_pack(struct hashfile *f)
break;
offset += ewah_bit_ctz64(word >> offset);
+ if (pos + offset < reuse_packfile->bitmap_pos)
+ continue;
+ if (pos + offset >= reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr)
+ goto done;
/*
* Can use bit positions directly, even for MIDX
* bitmaps. See comment in try_partial_reuse()
* for why.
*/
- write_reused_pack_one(pos + offset, f, &w_curs);
+ write_reused_pack_one(reuse_packfile->p,
+ pos + offset - reuse_packfile->bitmap_pos,
+ f, pack_start, &w_curs);
display_progress(progress_state, ++written);
}
}
+done:
unuse_pack(&w_curs);
}
@@ -1197,9 +1262,14 @@ static void write_pack_file(void)
offset = write_pack_header(f, nr_remaining);
- if (reuse_packfile) {
+ if (reuse_packfiles_nr) {
assert(pack_to_stdout);
- write_reused_pack(f);
+ for (j = 0; j < reuse_packfiles_nr; j++) {
+ reused_chunks_nr = 0;
+ write_reused_pack(&reuse_packfiles[j], f);
+ if (reused_chunks_nr)
+ reuse_packfiles_used_nr++;
+ }
offset = hashfile_total(f);
}
@@ -1756,7 +1826,8 @@ static void add_pbase_object(struct tree_desc *tree,
tree = pbase_tree_get(&entry.oid);
if (!tree)
return;
- init_tree_desc(&sub, tree->tree_data, tree->tree_size);
+ init_tree_desc(&sub, &tree->oid,
+ tree->tree_data, tree->tree_size);
add_pbase_object(&sub, down, downlen, fullname);
pbase_tree_put(tree);
@@ -1816,7 +1887,8 @@ static void add_preferred_base_object(const char *name)
}
else {
struct tree_desc tree;
- init_tree_desc(&tree, it->pcache.tree_data, it->pcache.tree_size);
+ init_tree_desc(&tree, &it->pcache.oid,
+ it->pcache.tree_data, it->pcache.tree_size);
add_pbase_object(&tree, name, cmplen, name);
}
}
@@ -3175,7 +3247,19 @@ static int git_pack_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "pack.allowpackreuse")) {
- allow_pack_reuse = git_config_bool(k, v);
+ int res = git_parse_maybe_bool_text(v);
+ if (res < 0) {
+ if (!strcasecmp(v, "single"))
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ else if (!strcasecmp(v, "multi"))
+ allow_pack_reuse = MULTI_PACK_REUSE;
+ else
+ die(_("invalid pack.allowPackReuse value: '%s'"), v);
+ } else if (res) {
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ } else {
+ allow_pack_reuse = NO_PACK_REUSE;
+ }
return 0;
}
if (!strcmp(k, "pack.threads")) {
@@ -3204,7 +3288,7 @@ static int git_pack_config(const char *k, const char *v,
return 0;
}
if (!strcmp(k, "uploadpack.blobpackfileuri")) {
- struct configured_exclusion *ex = xmalloc(sizeof(*ex));
+ struct configured_exclusion *ex;
const char *oid_end, *pack_end;
/*
* Stores the pack hash. This is not a true object ID, but is
@@ -3212,6 +3296,10 @@ static int git_pack_config(const char *k, const char *v,
*/
struct object_id pack_hash;
+ if (!v)
+ return config_error_nonbool(k);
+
+ ex = xmalloc(sizeof(*ex));
if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
*oid_end != ' ' ||
parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
@@ -3930,7 +4018,7 @@ static void loosen_unused_packed_objects(void)
*/
static int pack_options_allow_reuse(void)
{
- return allow_pack_reuse &&
+ return allow_pack_reuse != NO_PACK_REUSE &&
pack_to_stdout &&
!ignore_packed_keep_on_disk &&
!ignore_packed_keep_in_core &&
@@ -3943,13 +4031,18 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
return -1;
- if (pack_options_allow_reuse() &&
- !reuse_partial_packfile_from_bitmap(
- bitmap_git,
- &reuse_packfile,
- &reuse_packfile_objects,
- &reuse_packfile_bitmap)) {
- assert(reuse_packfile_objects);
+ if (pack_options_allow_reuse())
+ reuse_partial_packfile_from_bitmap(bitmap_git,
+ &reuse_packfiles,
+ &reuse_packfiles_nr,
+ &reuse_packfile_bitmap,
+ allow_pack_reuse == MULTI_PACK_REUSE);
+
+ if (reuse_packfiles) {
+ reuse_packfile_objects = bitmap_popcount(reuse_packfile_bitmap);
+ if (!reuse_packfile_objects)
+ BUG("expected non-empty reuse bitmap");
+
nr_result += reuse_packfile_objects;
nr_seen += reuse_packfile_objects;
display_progress(progress_state, nr_seen);
@@ -4305,6 +4398,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
if (sparse < 0)
sparse = the_repository->settings.pack_use_sparse;
+ if (the_repository->settings.pack_use_multi_pack_reuse)
+ allow_pack_reuse = MULTI_PACK_REUSE;
}
reset_pack_idx_option(&pack_idx_opts);
@@ -4517,11 +4612,20 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
fprintf_ln(stderr,
_("Total %"PRIu32" (delta %"PRIu32"),"
" reused %"PRIu32" (delta %"PRIu32"),"
- " pack-reused %"PRIu32),
+ " pack-reused %"PRIu32" (from %"PRIuMAX")"),
written, written_delta, reused, reused_delta,
- reuse_packfile_objects);
+ reuse_packfile_objects,
+ (uintmax_t)reuse_packfiles_used_nr);
+
+ trace2_data_intmax("pack-objects", the_repository, "written", written);
+ trace2_data_intmax("pack-objects", the_repository, "written/delta", written_delta);
+ trace2_data_intmax("pack-objects", the_repository, "reused", reused);
+ trace2_data_intmax("pack-objects", the_repository, "reused/delta", reused_delta);
+ trace2_data_intmax("pack-objects", the_repository, "pack-reused", reuse_packfile_objects);
+ trace2_data_intmax("pack-objects", the_repository, "packs-reused", reuse_packfiles_used_nr);
cleanup:
+ clear_packing_data(&to_pack);
list_objects_filter_release(&filter_options);
strvec_clear(&rp);
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index bcf383c..db40825 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -7,24 +7,28 @@
#include "revision.h"
static char const * const pack_refs_usage[] = {
- N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
+ N_("git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]"),
NULL
};
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{
- unsigned int flags = PACK_REFS_PRUNE;
- static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
- static struct string_list included_refs = STRING_LIST_INIT_NODUP;
- struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
- .includes = &included_refs,
- .flags = flags };
- static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
+ struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
+ struct string_list included_refs = STRING_LIST_INIT_NODUP;
+ struct pack_refs_opts pack_refs_opts = {
+ .exclusions = &excludes,
+ .includes = &included_refs,
+ .flags = PACK_REFS_PRUNE,
+ };
+ struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
+ int pack_all = 0;
+ int ret;
struct option opts[] = {
- OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
+ OPT_BOOL(0, "all", &pack_all, N_("pack everything")),
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+ OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), PACK_REFS_AUTO),
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
N_("references to include")),
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
@@ -38,11 +42,16 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
for_each_string_list_item(item, &option_excluded_refs)
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
- if (pack_refs_opts.flags & PACK_REFS_ALL)
+ if (pack_all)
string_list_append(pack_refs_opts.includes, "*");
if (!pack_refs_opts.includes->nr)
string_list_append(pack_refs_opts.includes, "refs/tags/*");
- return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
+ ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
+
+ clear_ref_exclusions(&excludes);
+ string_list_clear(&included_refs, 0);
+ string_list_clear(&option_excluded_refs, 0);
+ return ret;
}
diff --git a/builtin/pull.c b/builtin/pull.c
index be2b2c9..72cbb76 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -14,7 +14,6 @@
#include "merge.h"
#include "object-name.h"
#include "parse-options.h"
-#include "exec-cmd.h"
#include "run-command.h"
#include "oid-array.h"
#include "remote.h"
@@ -24,15 +23,11 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "revision.h"
#include "submodule.h"
#include "submodule-config.h"
-#include "tempfile.h"
-#include "lockfile.h"
#include "wt-status.h"
#include "commit-reach.h"
#include "sequencer.h"
-#include "packfile.h"
/**
* Parses the value of --rebase. If value is a false value, returns
@@ -820,7 +815,7 @@ static int get_octopus_merge_base(struct object_id *merge_base,
const struct object_id *merge_head,
const struct object_id *fork_point)
{
- struct commit_list *revs = NULL, *result;
+ struct commit_list *revs = NULL, *result = NULL;
commit_list_insert(lookup_commit_reference(the_repository, curr_head),
&revs);
@@ -830,7 +825,8 @@ static int get_octopus_merge_base(struct object_id *merge_base,
commit_list_insert(lookup_commit_reference(the_repository, fork_point),
&revs);
- result = get_octopus_merge_bases(revs);
+ if (get_octopus_merge_bases(revs, &result) < 0)
+ exit(128);
free_commit_list(revs);
reduce_heads_replace(&result);
@@ -931,6 +927,8 @@ static int get_can_ff(struct object_id *orig_head,
merge_head = lookup_commit_reference(the_repository, orig_merge_head);
ret = repo_is_descendant_of(the_repository, merge_head, list);
free_commit_list(list);
+ if (ret < 0)
+ exit(128);
return ret;
}
@@ -955,6 +953,8 @@ static int already_up_to_date(struct object_id *orig_head,
commit_list_insert(theirs, &list);
ok = repo_is_descendant_of(the_repository, ours, list);
free_commit_list(list);
+ if (ok < 0)
+ exit(128);
if (!ok)
return 0;
}
diff --git a/builtin/push.c b/builtin/push.c
index 2e70838..2fbb31c 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -7,7 +7,6 @@
#include "config.h"
#include "environment.h"
#include "gettext.h"
-#include "refs.h"
#include "refspec.h"
#include "run-command.h"
#include "remote.h"
@@ -392,7 +391,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
if (!is_empty_cas(&cas)) {
if (!transport->smart_options)
die("underlying transport does not support --%s option",
- CAS_OPT_NAME);
+ "force-with-lease");
transport->smart_options->cas = &cas;
}
@@ -526,26 +525,21 @@ static int git_push_config(const char *k, const char *v,
*flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
return 0;
} else if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
- break;
- case 1:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
+ break;
+ case 1:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
+ else
+ return error(_("invalid value for '%s'"), k);
}
} else if (!strcmp(k, "push.recursesubmodules")) {
- const char *value;
- if (!git_config_get_value("push.recursesubmodules", &value))
- recurse_submodules = parse_push_recurse_submodules_arg(k, value);
+ recurse_submodules = parse_push_recurse_submodules_arg(k, v);
} else if (!strcmp(k, "submodule.recurse")) {
int val = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
@@ -604,7 +598,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
@@ -639,8 +633,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
: &push_options_config);
set_push_cert_flags(&flags, push_cert);
- if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
- die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--branches/--mirror/--tags");
+ die_for_incompatible_opt4(deleterefs, "--delete",
+ tags, "--tags",
+ flags & TRANSPORT_PUSH_ALL, "--all/--branches",
+ flags & TRANSPORT_PUSH_MIRROR, "--mirror");
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
@@ -677,19 +673,13 @@ int cmd_push(int argc, const char **argv, const char *prefix)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (flags & TRANSPORT_PUSH_ALL) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--tags");
if (argc >= 2)
die(_("--all can't be combined with refspecs"));
}
if (flags & TRANSPORT_PUSH_MIRROR) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--mirror", "--tags");
if (argc >= 2)
die(_("--mirror can't be combined with refspecs"));
}
- if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--mirror");
if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
cas.use_force_if_includes = 1;
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e455a47..f02cbac 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -5,7 +5,6 @@
#include "range-diff.h"
#include "config.h"
#include "repository.h"
-#include "revision.h"
static const char * const builtin_range_diff_usage[] = {
N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 8196ca9..6f89cec 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -16,14 +16,12 @@
#include "tree-walk.h"
#include "cache-tree.h"
#include "unpack-trees.h"
-#include "dir.h"
#include "parse-options.h"
#include "repository.h"
#include "resolve-undo.h"
#include "setup.h"
#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
static int nr_trees;
static int read_empty;
@@ -263,8 +261,9 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
cache_tree_free(&the_index.cache_tree);
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
- parse_tree(tree);
- init_tree_desc(t+i, tree->buffer, tree->size);
+ if (parse_tree(tree) < 0)
+ return 128;
+ init_tree_desc(t+i, &tree->object.oid, tree->buffer, tree->size);
}
if (unpack_trees(nr_trees, t, &opts))
return 128;
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 043c65d..891f284 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -11,14 +11,10 @@
#include "gettext.h"
#include "hex.h"
#include "run-command.h"
-#include "exec-cmd.h"
#include "strvec.h"
#include "dir.h"
-#include "packfile.h"
#include "refs.h"
-#include "quote.h"
#include "config.h"
-#include "cache-tree.h"
#include "unpack-trees.h"
#include "lockfile.h"
#include "object-file.h"
@@ -62,7 +58,7 @@ enum empty_type {
EMPTY_UNSPECIFIED = -1,
EMPTY_DROP,
EMPTY_KEEP,
- EMPTY_ASK
+ EMPTY_STOP
};
enum action {
@@ -149,7 +145,6 @@ struct rebase_options {
.reapply_cherry_picks = -1, \
.allow_empty_message = 1, \
.autosquash = -1, \
- .config_autosquash = -1, \
.rebase_merges = -1, \
.config_rebase_merges = -1, \
.update_refs = -1, \
@@ -209,7 +204,7 @@ static int edit_todo_file(unsigned flags)
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- strbuf_stripspace(&todo_list.buf, comment_line_char);
+ strbuf_stripspace(&todo_list.buf, comment_line_str);
res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
@@ -520,7 +515,7 @@ static int finish_rebase(struct rebase_options *opts)
int ret = 0;
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
- unlink(git_path_auto_merge(the_repository));
+ delete_ref(NULL, "AUTO_MERGE", NULL, REF_NO_DEREF);
apply_autostash(state_dir_path("autostash", opts));
/*
* We ignore errors in 'git maintenance run --auto', since the
@@ -572,18 +567,10 @@ static int move_to_original_branch(struct rebase_options *opts)
return ret;
}
-static const char *resolvemsg =
-N_("Resolve all conflicts manually, mark them as resolved with\n"
-"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
-"You can instead skip this commit: run \"git rebase --skip\".\n"
-"To abort and get back to the state before \"git rebase\", run "
-"\"git rebase --abort\".");
-
static int run_am(struct rebase_options *opts)
{
struct child_process am = CHILD_PROCESS_INIT;
struct child_process format_patch = CHILD_PROCESS_INIT;
- struct strbuf revisions = STRBUF_INIT;
int status;
char *rebased_patches;
@@ -593,7 +580,7 @@ static int run_am(struct rebase_options *opts)
opts->reflog_action);
if (opts->action == ACTION_CONTINUE) {
strvec_push(&am.args, "--resolved");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
if (opts->gpg_sign_opt)
strvec_push(&am.args, opts->gpg_sign_opt);
status = run_command(&am);
@@ -604,7 +591,7 @@ static int run_am(struct rebase_options *opts)
}
if (opts->action == ACTION_SKIP) {
strvec_push(&am.args, "--skip");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
status = run_command(&am);
if (status)
return status;
@@ -616,13 +603,6 @@ static int run_am(struct rebase_options *opts)
return run_command(&am);
}
- strbuf_addf(&revisions, "%s...%s",
- oid_to_hex(opts->root ?
- /* this is now equivalent to !opts->upstream */
- &opts->onto->object.oid :
- &opts->upstream->object.oid),
- oid_to_hex(&opts->orig_head->object.oid));
-
rebased_patches = xstrdup(git_path("rebased-patches"));
format_patch.out = open(rebased_patches,
O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -630,7 +610,7 @@ static int run_am(struct rebase_options *opts)
status = error_errno(_("could not open '%s' for writing"),
rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
return status;
}
@@ -643,7 +623,12 @@ static int run_am(struct rebase_options *opts)
if (opts->git_format_patch_opt.len)
strvec_split(&format_patch.args,
opts->git_format_patch_opt.buf);
- strvec_push(&format_patch.args, revisions.buf);
+ strvec_pushf(&format_patch.args, "%s...%s",
+ oid_to_hex(opts->root ?
+ /* this is now equivalent to !opts->upstream */
+ &opts->onto->object.oid :
+ &opts->upstream->object.oid),
+ oid_to_hex(&opts->orig_head->object.oid));
if (opts->restrict_revision)
strvec_pushf(&format_patch.args, "^%s",
oid_to_hex(&opts->restrict_revision->object.oid));
@@ -653,7 +638,7 @@ static int run_am(struct rebase_options *opts)
struct reset_head_opts ropts = { 0 };
unlink(rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
ropts.oid = &opts->orig_head->object.oid;
ropts.branch = opts->head_name;
@@ -666,23 +651,21 @@ static int run_am(struct rebase_options *opts)
"As a result, git cannot rebase them."),
opts->revisions);
- strbuf_release(&revisions);
return status;
}
- strbuf_release(&revisions);
am.in = open(rebased_patches, O_RDONLY);
if (am.in < 0) {
status = error_errno(_("could not open '%s' for reading"),
rebased_patches);
free(rebased_patches);
- strvec_clear(&am.args);
+ child_process_clear(&am);
return status;
}
strvec_pushv(&am.args, opts->git_am_opts.v);
strvec_push(&am.args, "--rebasing");
- strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+ strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
strvec_push(&am.args, "--patch-format=mboxrd");
if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)
strvec_push(&am.args, "--rerere-autoupdate");
@@ -710,11 +693,8 @@ static int run_specific_rebase(struct rebase_options *opts)
if (opts->type == REBASE_MERGE) {
/* Run sequencer-based rebase */
- setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1);
- if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
+ if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))
setenv("GIT_SEQUENCE_EDITOR", ":", 1);
- opts->autosquash = 0;
- }
if (opts->gpg_sign_opt) {
/* remove the leading "-S" */
char *tmp = xstrdup(opts->gpg_sign_opt + 2);
@@ -879,7 +859,8 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
if (!upstream)
goto done;
- merge_bases = repo_get_merge_bases(the_repository, upstream, head);
+ if (repo_get_merge_bases(the_repository, upstream, head, &merge_bases) < 0)
+ exit(128);
if (!merge_bases || merge_bases->next)
goto done;
@@ -898,8 +879,9 @@ static void fill_branch_base(struct rebase_options *options,
{
struct commit_list *merge_bases = NULL;
- merge_bases = repo_get_merge_bases(the_repository, options->onto,
- options->orig_head);
+ if (repo_get_merge_bases(the_repository, options->onto,
+ options->orig_head, &merge_bases) < 0)
+ exit(128);
if (!merge_bases || merge_bases->next)
oidcpy(branch_base, null_oid());
else
@@ -963,10 +945,14 @@ static enum empty_type parse_empty_value(const char *value)
return EMPTY_DROP;
else if (!strcasecmp(value, "keep"))
return EMPTY_KEEP;
- else if (!strcasecmp(value, "ask"))
- return EMPTY_ASK;
+ else if (!strcasecmp(value, "stop"))
+ return EMPTY_STOP;
+ else if (!strcasecmp(value, "ask")) {
+ warning(_("--empty=ask is deprecated; use '--empty=stop' instead."));
+ return EMPTY_STOP;
+ }
- die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value);
+ die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"stop\"."), value);
}
static int parse_opt_keep_empty(const struct option *opt, const char *arg,
@@ -1145,7 +1131,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"instead of ignoring them"),
1, PARSE_OPT_HIDDEN),
OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
- OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|ask)",
+ OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|stop)",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
@@ -1266,7 +1252,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
if (options.action != ACTION_NONE && !in_progress)
- die(_("No rebase in progress?"));
+ die(_("no rebase in progress"));
if (options.action == ACTION_EDIT_TODO && !is_merge(&options))
die(_("The --edit-todo action can only be used during "
@@ -1405,7 +1391,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
(options.action != ACTION_NONE) ||
(options.exec.nr > 0) ||
- (options.autosquash == -1 && options.config_autosquash == 1) ||
options.autosquash == 1) {
allow_preemptive_ff = 0;
}
@@ -1508,8 +1493,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (is_merge(&options))
die(_("apply options and merge options "
"cannot be used together"));
- else if (options.autosquash == -1 && options.config_autosquash == 1)
- die(_("apply options are incompatible with rebase.autoSquash. Consider adding --no-autosquash"));
else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
die(_("apply options are incompatible with rebase.rebaseMerges. Consider adding --no-rebase-merges"));
else if (options.update_refs == -1 && options.config_update_refs == 1)
@@ -1529,10 +1512,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
- if (options.autosquash == 1)
+ if (options.autosquash == 1) {
imply_merge(&options, "--autosquash");
- options.autosquash = (options.autosquash >= 0) ? options.autosquash :
- ((options.config_autosquash >= 0) ? options.config_autosquash : 0);
+ } else if (options.autosquash == -1) {
+ options.autosquash =
+ options.config_autosquash &&
+ (options.flags & REBASE_INTERACTIVE_EXPLICIT);
+ }
if (options.type == REBASE_UNSPECIFIED) {
if (!strcmp(options.default_backend, "merge"))
@@ -1562,7 +1548,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
- options.empty = EMPTY_ASK;
+ options.empty = EMPTY_STOP;
else if (options.exec.nr > 0)
options.empty = EMPTY_KEEP;
else
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 8c4f0cb..e8d7df1 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -22,7 +22,6 @@
#include "connected.h"
#include "strvec.h"
#include "version.h"
-#include "tag.h"
#include "gpg-interface.h"
#include "sigchain.h"
#include "fsck.h"
@@ -142,6 +141,7 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
static int receive_pack_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ const char *msg_id;
int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
if (status)
@@ -178,12 +178,14 @@ static int receive_pack_config(const char *var, const char *value,
return 0;
}
- if (skip_prefix(var, "receive.fsck.", &var)) {
- if (is_valid_msg_type(var, value))
+ if (skip_prefix(var, "receive.fsck.", &msg_id)) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (is_valid_msg_type(msg_id, value))
strbuf_addf(&fsck_msg_types, "%c%s=%s",
- fsck_msg_types.len ? ',' : '=', var, value);
+ fsck_msg_types.len ? ',' : '=', msg_id, value);
else
- warning("skipping unknown msg id '%s'", var);
+ warning("skipping unknown msg id '%s'", msg_id);
return 0;
}
@@ -591,21 +593,6 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
return strbuf_detach(&buf, NULL);
}
-static char *find_header(const char *msg, size_t len, const char *key,
- const char **next_line)
-{
- size_t out_len;
- const char *val = find_header_mem(msg, len, key, &out_len);
-
- if (!val)
- return NULL;
-
- if (next_line)
- *next_line = val + out_len + 1;
-
- return xmemdupz(val, out_len);
-}
-
/*
* Return zero if a and b are equal up to n bytes and nonzero if they are not.
* This operation is guaranteed to run in constant time to avoid leaking data.
@@ -620,13 +607,14 @@ static int constant_memequal(const char *a, const char *b, size_t n)
return res;
}
-static const char *check_nonce(const char *buf, size_t len)
+static const char *check_nonce(const char *buf)
{
- char *nonce = find_header(buf, len, "nonce", NULL);
+ size_t noncelen;
+ const char *found = find_commit_header(buf, "nonce", &noncelen);
+ char *nonce = found ? xmemdupz(found, noncelen) : NULL;
timestamp_t stamp, ostamp;
char *bohmac, *expect = NULL;
const char *retval = NONCE_BAD;
- size_t noncelen;
if (!nonce) {
retval = NONCE_MISSING;
@@ -668,7 +656,6 @@ static const char *check_nonce(const char *buf, size_t len)
goto leave;
}
- noncelen = strlen(nonce);
expect = prepare_push_cert_nonce(service_dir, stamp);
if (noncelen != strlen(expect)) {
/* This is not even the right size. */
@@ -716,35 +703,28 @@ leave:
static int check_cert_push_options(const struct string_list *push_options)
{
const char *buf = push_cert.buf;
- int len = push_cert.len;
- char *option;
- const char *next_line;
+ const char *option;
+ size_t optionlen;
int options_seen = 0;
int retval = 1;
- if (!len)
+ if (!*buf)
return 1;
- while ((option = find_header(buf, len, "push-option", &next_line))) {
- len -= (next_line - buf);
- buf = next_line;
+ while ((option = find_commit_header(buf, "push-option", &optionlen))) {
+ buf = option + optionlen + 1;
options_seen++;
if (options_seen > push_options->nr
- || strcmp(option,
- push_options->items[options_seen - 1].string)) {
- retval = 0;
- goto leave;
- }
- free(option);
+ || xstrncmpz(push_options->items[options_seen - 1].string,
+ option, optionlen))
+ return 0;
}
if (options_seen != push_options->nr)
retval = 0;
-leave:
- free(option);
return retval;
}
@@ -771,7 +751,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
check_signature(&sigcheck, push_cert.buf + bogs,
push_cert.len - bogs);
- nonce_status = check_nonce(push_cert.buf, bogs);
+ nonce_status = check_nonce(sigcheck.payload);
}
if (!is_null_oid(&push_cert_oid)) {
strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s",
@@ -1546,6 +1526,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
starts_with(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
+ int ret2;
old_object = parse_object(the_repository, old_oid);
new_object = parse_object(the_repository, new_oid);
@@ -1559,7 +1540,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
- if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
+ ret2 = repo_in_merge_bases(the_repository, old_commit, new_commit);
+ if (ret2 < 0)
+ exit(128);
+ if (!ret2) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
ret = "non-fast-forward";
@@ -2601,17 +2585,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (auto_gc) {
struct child_process proc = CHILD_PROCESS_INIT;
- proc.no_stdin = 1;
- proc.stdout_to_stderr = 1;
- proc.err = use_sideband ? -1 : 0;
- proc.git_cmd = proc.close_object_store = 1;
- strvec_pushl(&proc.args, "gc", "--auto", "--quiet",
- NULL);
-
- if (!start_command(&proc)) {
- if (use_sideband)
- copy_to_sideband(proc.err, -1, NULL);
- finish_command(&proc);
+ if (prepare_auto_maintenance(1, &proc)) {
+ proc.no_stdin = 1;
+ proc.stdout_to_stderr = 1;
+ proc.err = use_sideband ? -1 : 0;
+
+ if (!start_command(&proc)) {
+ if (use_sideband)
+ copy_to_sideband(proc.err, -1, NULL);
+ finish_command(&proc);
+ }
}
}
if (auto_update_server_info)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 6e490f8..060eb33 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -7,11 +7,15 @@
#include "wildmatch.h"
#include "worktree.h"
#include "reflog.h"
+#include "refs.h"
#include "parse-options.h"
#define BUILTIN_REFLOG_SHOW_USAGE \
N_("git reflog [show] [<log-options>] [<ref>]")
+#define BUILTIN_REFLOG_LIST_USAGE \
+ N_("git reflog list")
+
#define BUILTIN_REFLOG_EXPIRE_USAGE \
N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
" [--rewrite] [--updateref] [--stale-fix]\n" \
@@ -29,6 +33,11 @@ static const char *const reflog_show_usage[] = {
NULL,
};
+static const char *const reflog_list_usage[] = {
+ BUILTIN_REFLOG_LIST_USAGE,
+ NULL,
+};
+
static const char *const reflog_expire_usage[] = {
BUILTIN_REFLOG_EXPIRE_USAGE,
NULL
@@ -46,6 +55,7 @@ static const char *const reflog_exists_usage[] = {
static const char *const reflog_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
+ BUILTIN_REFLOG_LIST_USAGE,
BUILTIN_REFLOG_EXPIRE_USAGE,
BUILTIN_REFLOG_DELETE_USAGE,
BUILTIN_REFLOG_EXISTS_USAGE,
@@ -60,8 +70,7 @@ struct worktree_reflogs {
struct string_list reflogs;
};
-static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
- int flags UNUSED, void *cb_data)
+static int collect_reflog(const char *ref, void *cb_data)
{
struct worktree_reflogs *cb = cb_data;
struct worktree *worktree = cb->worktree;
@@ -96,8 +105,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
reflog_expire_cfg_tail = &reflog_expire_cfg;
for (ent = reflog_expire_cfg; ent; ent = ent->next)
- if (!strncmp(ent->pattern, pattern, len) &&
- ent->pattern[len] == '\0')
+ if (!xstrncmpz(ent->pattern, pattern, len))
return ent;
FLEX_ALLOC_MEM(ent, pattern, pattern, len);
@@ -239,6 +247,29 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
return cmd_log_reflog(argc, argv, prefix);
}
+static int show_reflog(const char *refname, void *cb_data UNUSED)
+{
+ printf("%s\n", refname);
+ return 0;
+}
+
+static int cmd_reflog_list(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ struct ref_store *ref_store;
+
+ argc = parse_options(argc, argv, prefix, options, reflog_list_usage, 0);
+ if (argc)
+ return error(_("%s does not accept arguments: '%s'"),
+ "list", argv[0]);
+
+ ref_store = get_main_ref_store(the_repository);
+
+ return refs_for_each_reflog(ref_store, show_reflog, NULL);
+}
+
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
struct cmd_reflog_expire_cb cmd = { 0 };
@@ -248,7 +279,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
int verbose = 0;
reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
@@ -368,7 +399,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
int verbose = 0;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
@@ -418,6 +449,7 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
+ OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
diff --git a/builtin/remote.c b/builtin/remote.c
index d91bbe7..8412d12 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -150,7 +150,7 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
else if (!strcmp(arg, "push"))
*mirror = MIRROR_PUSH;
else
- return error(_("unknown mirror argument: %s"), arg);
+ return error(_("unknown --mirror argument: %s"), arg);
return 0;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index edaee4d..15e4ccc 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -8,7 +8,6 @@
#include "path.h"
#include "run-command.h"
#include "server-info.h"
-#include "sigchain.h"
#include "strbuf.h"
#include "string-list.h"
#include "strvec.h"
@@ -315,8 +314,9 @@ static int write_oid(const struct object_id *oid,
die(_("could not start pack-objects to repack promisor objects"));
}
- xwrite(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz);
- xwrite(cmd->in, "\n", 1);
+ if (write_in_full(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ write_in_full(cmd->in, "\n", 1) < 0)
+ die(_("failed to feed promisor objects to pack-objects"));
return 0;
}
@@ -1203,19 +1203,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant && repository_format_precious_objects)
die(_("cannot delete packs in a precious-objects repo"));
- if (keep_unreachable &&
- (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
- die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "-A");
+ die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
+ keep_unreachable, "-k/--keep-unreachable",
+ pack_everything & PACK_CRUFT, "--cruft");
- if (pack_everything & PACK_CRUFT) {
+ if (pack_everything & PACK_CRUFT)
pack_everything |= ALL_INTO_ONE;
- if (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE))
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-A");
- if (keep_unreachable)
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-k");
- }
-
if (write_bitmaps < 0) {
if (!write_midx &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
diff --git a/builtin/replay.c b/builtin/replay.c
new file mode 100644
index 0000000..6bc4b47
--- /dev/null
+++ b/builtin/replay.c
@@ -0,0 +1,446 @@
+/*
+ * "git replay" builtin command
+ */
+
+#define USE_THE_INDEX_VARIABLE
+#include "git-compat-util.h"
+
+#include "builtin.h"
+#include "environment.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "merge-ort.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "revision.h"
+#include "strmap.h"
+#include <oidset.h>
+#include <tree.h>
+
+static const char *short_commit_name(struct commit *commit)
+{
+ return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV);
+}
+
+static struct commit *peel_committish(const char *name)
+{
+ struct object *obj;
+ struct object_id oid;
+
+ if (repo_get_oid(the_repository, name, &oid))
+ return NULL;
+ obj = parse_object(the_repository, &oid);
+ return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+ OBJ_COMMIT);
+}
+
+static char *get_author(const char *message)
+{
+ size_t len;
+ const char *a;
+
+ a = find_commit_header(message, "author", &len);
+ if (a)
+ return xmemdupz(a, len);
+
+ return NULL;
+}
+
+static struct commit *create_commit(struct tree *tree,
+ struct commit *based_on,
+ struct commit *parent)
+{
+ struct object_id ret;
+ struct object *obj;
+ struct commit_list *parents = NULL;
+ char *author;
+ char *sign_commit = NULL; /* FIXME: cli users might want to sign again */
+ struct commit_extra_header *extra;
+ struct strbuf msg = STRBUF_INIT;
+ const char *out_enc = get_commit_output_encoding();
+ const char *message = repo_logmsg_reencode(the_repository, based_on,
+ NULL, out_enc);
+ const char *orig_message = NULL;
+ const char *exclude_gpgsig[] = { "gpgsig", NULL };
+
+ commit_list_insert(parent, &parents);
+ extra = read_commit_extra_headers(based_on, exclude_gpgsig);
+ find_commit_subject(message, &orig_message);
+ strbuf_addstr(&msg, orig_message);
+ author = get_author(message);
+ reset_ident_date();
+ if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
+ &ret, author, NULL, sign_commit, extra)) {
+ error(_("failed to write commit object"));
+ return NULL;
+ }
+ free(author);
+ strbuf_release(&msg);
+
+ obj = parse_object(the_repository, &ret);
+ return (struct commit *)obj;
+}
+
+struct ref_info {
+ struct commit *onto;
+ struct strset positive_refs;
+ struct strset negative_refs;
+ int positive_refexprs;
+ int negative_refexprs;
+};
+
+static void get_ref_information(struct rev_cmdline_info *cmd_info,
+ struct ref_info *ref_info)
+{
+ int i;
+
+ ref_info->onto = NULL;
+ strset_init(&ref_info->positive_refs);
+ strset_init(&ref_info->negative_refs);
+ ref_info->positive_refexprs = 0;
+ ref_info->negative_refexprs = 0;
+
+ /*
+ * When the user specifies e.g.
+ * git replay origin/main..mybranch
+ * git replay ^origin/next mybranch1 mybranch2
+ * we want to be able to determine where to replay the commits. In
+ * these examples, the branches are probably based on an old version
+ * of either origin/main or origin/next, so we want to replay on the
+ * newest version of that branch. In contrast we would want to error
+ * out if they ran
+ * git replay ^origin/master ^origin/next mybranch
+ * git replay mybranch~2..mybranch
+ * the first of those because there's no unique base to choose, and
+ * the second because they'd likely just be replaying commits on top
+ * of the same commit and not making any difference.
+ */
+ for (i = 0; i < cmd_info->nr; i++) {
+ struct rev_cmdline_entry *e = cmd_info->rev + i;
+ struct object_id oid;
+ const char *refexpr = e->name;
+ char *fullname = NULL;
+ int can_uniquely_dwim = 1;
+
+ if (*refexpr == '^')
+ refexpr++;
+ if (repo_dwim_ref(the_repository, refexpr, strlen(refexpr), &oid, &fullname, 0) != 1)
+ can_uniquely_dwim = 0;
+
+ if (e->flags & BOTTOM) {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->negative_refs, fullname);
+ if (!ref_info->negative_refexprs)
+ ref_info->onto = lookup_commit_reference_gently(the_repository,
+ &e->item->oid, 1);
+ ref_info->negative_refexprs++;
+ } else {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->positive_refs, fullname);
+ ref_info->positive_refexprs++;
+ }
+
+ free(fullname);
+ }
+}
+
+static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
+ const char *onto_name,
+ const char **advance_name,
+ struct commit **onto,
+ struct strset **update_refs)
+{
+ struct ref_info rinfo;
+
+ get_ref_information(cmd_info, &rinfo);
+ if (!rinfo.positive_refexprs)
+ die(_("need some commits to replay"));
+ if (onto_name && *advance_name)
+ die(_("--onto and --advance are incompatible"));
+ else if (onto_name) {
+ *onto = peel_committish(onto_name);
+ if (rinfo.positive_refexprs <
+ strset_get_size(&rinfo.positive_refs))
+ die(_("all positive revisions given must be references"));
+ } else if (*advance_name) {
+ struct object_id oid;
+ char *fullname = NULL;
+
+ *onto = peel_committish(*advance_name);
+ if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name),
+ &oid, &fullname, 0) == 1) {
+ *advance_name = fullname;
+ } else {
+ die(_("argument to --advance must be a reference"));
+ }
+ if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple sources because ordering would be ill-defined"));
+ } else {
+ int positive_refs_complete = (
+ rinfo.positive_refexprs ==
+ strset_get_size(&rinfo.positive_refs));
+ int negative_refs_complete = (
+ rinfo.negative_refexprs ==
+ strset_get_size(&rinfo.negative_refs));
+ /*
+ * We need either positive_refs_complete or
+ * negative_refs_complete, but not both.
+ */
+ if (rinfo.negative_refexprs > 0 &&
+ positive_refs_complete == negative_refs_complete)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ if (negative_refs_complete) {
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+
+ if (rinfo.negative_refexprs == 0)
+ die(_("all positive revisions given must be references"));
+ else if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ else if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple source branches because ordering would be ill-defined"));
+
+ /* Only one entry, but we have to loop to get it */
+ strset_for_each_entry(&rinfo.negative_refs,
+ &iter, entry) {
+ *advance_name = entry->key;
+ }
+ } else { /* positive_refs_complete */
+ if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine correct base for --onto"));
+ if (rinfo.negative_refexprs == 1)
+ *onto = rinfo.onto;
+ }
+ }
+ if (!*advance_name) {
+ *update_refs = xcalloc(1, sizeof(**update_refs));
+ **update_refs = rinfo.positive_refs;
+ memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
+ }
+ strset_clear(&rinfo.negative_refs);
+ strset_clear(&rinfo.positive_refs);
+}
+
+static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
+ struct commit *commit,
+ struct commit *fallback)
+{
+ khint_t pos = kh_get_oid_map(replayed_commits, commit->object.oid);
+ if (pos == kh_end(replayed_commits))
+ return fallback;
+ return kh_value(replayed_commits, pos);
+}
+
+static struct commit *pick_regular_commit(struct commit *pickme,
+ kh_oid_map_t *replayed_commits,
+ struct commit *onto,
+ struct merge_options *merge_opt,
+ struct merge_result *result)
+{
+ struct commit *base, *replayed_base;
+ struct tree *pickme_tree, *base_tree;
+
+ base = pickme->parents->item;
+ replayed_base = mapped_commit(replayed_commits, base, onto);
+
+ result->tree = repo_get_commit_tree(the_repository, replayed_base);
+ pickme_tree = repo_get_commit_tree(the_repository, pickme);
+ base_tree = repo_get_commit_tree(the_repository, base);
+
+ merge_opt->branch1 = short_commit_name(replayed_base);
+ merge_opt->branch2 = short_commit_name(pickme);
+ merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
+
+ merge_incore_nonrecursive(merge_opt,
+ base_tree,
+ result->tree,
+ pickme_tree,
+ result);
+
+ free((char*)merge_opt->ancestor);
+ merge_opt->ancestor = NULL;
+ if (!result->clean)
+ return NULL;
+ return create_commit(result->tree, pickme, replayed_base);
+}
+
+int cmd_replay(int argc, const char **argv, const char *prefix)
+{
+ const char *advance_name = NULL;
+ struct commit *onto = NULL;
+ const char *onto_name = NULL;
+ int contained = 0;
+
+ struct rev_info revs;
+ struct commit *last_commit = NULL;
+ struct commit *commit;
+ struct merge_options merge_opt;
+ struct merge_result result;
+ struct strset *update_refs = NULL;
+ kh_oid_map_t *replayed_commits;
+ int ret = 0;
+
+ const char * const replay_usage[] = {
+ N_("(EXPERIMENTAL!) git replay "
+ "([--contained] --onto <newbase> | --advance <branch>) "
+ "<revision-range>..."),
+ NULL
+ };
+ struct option replay_options[] = {
+ OPT_STRING(0, "advance", &advance_name,
+ N_("branch"),
+ N_("make replay advance given branch")),
+ OPT_STRING(0, "onto", &onto_name,
+ N_("revision"),
+ N_("replay onto given commit")),
+ OPT_BOOL(0, "contained", &contained,
+ N_("advance all branches contained in revision-range")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, replay_options, replay_usage,
+ PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+ if (!onto_name && !advance_name) {
+ error(_("option --onto or --advance is mandatory"));
+ usage_with_options(replay_usage, replay_options);
+ }
+
+ if (advance_name && contained)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--advance", "--contained");
+
+ repo_init_revisions(the_repository, &revs, prefix);
+
+ /*
+ * Set desired values for rev walking options here. If they
+ * are changed by some user specified option in setup_revisions()
+ * below, we will detect that below and then warn.
+ *
+ * TODO: In the future we might want to either die(), or allow
+ * some options changing these values if we think they could
+ * be useful.
+ */
+ revs.reverse = 1;
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ revs.topo_order = 1;
+ revs.simplify_history = 0;
+
+ argc = setup_revisions(argc, argv, &revs, NULL);
+ if (argc > 1) {
+ ret = error(_("unrecognized argument: %s"), argv[1]);
+ goto cleanup;
+ }
+
+ /*
+ * Detect and warn if we override some user specified rev
+ * walking options.
+ */
+ if (revs.reverse != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "reverse");
+ revs.reverse = 1;
+ }
+ if (revs.sort_order != REV_SORT_IN_GRAPH_ORDER) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "sort_order");
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ }
+ if (revs.topo_order != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "topo_order");
+ revs.topo_order = 1;
+ }
+ if (revs.simplify_history != 0) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "simplify_history");
+ revs.simplify_history = 0;
+ }
+
+ determine_replay_mode(&revs.cmdline, onto_name, &advance_name,
+ &onto, &update_refs);
+
+ if (!onto) /* FIXME: Should handle replaying down to root commit */
+ die("Replaying down to root commit is not supported yet!");
+
+ if (prepare_revision_walk(&revs) < 0) {
+ ret = error(_("error preparing revisions"));
+ goto cleanup;
+ }
+
+ init_merge_options(&merge_opt, the_repository);
+ memset(&result, 0, sizeof(result));
+ merge_opt.show_rename_progress = 0;
+ last_commit = onto;
+ replayed_commits = kh_init_oid_map();
+ while ((commit = get_revision(&revs))) {
+ const struct name_decoration *decoration;
+ khint_t pos;
+ int hr;
+
+ if (!commit->parents)
+ die(_("replaying down to root commit is not supported yet!"));
+ if (commit->parents->next)
+ die(_("replaying merge commits is not supported yet!"));
+
+ last_commit = pick_regular_commit(commit, replayed_commits, onto,
+ &merge_opt, &result);
+ if (!last_commit)
+ break;
+
+ /* Record commit -> last_commit mapping */
+ pos = kh_put_oid_map(replayed_commits, commit->object.oid, &hr);
+ if (hr == 0)
+ BUG("Duplicate rewritten commit: %s\n",
+ oid_to_hex(&commit->object.oid));
+ kh_value(replayed_commits, pos) = last_commit;
+
+ /* Update any necessary branches */
+ if (advance_name)
+ continue;
+ decoration = get_name_decoration(&commit->object);
+ if (!decoration)
+ continue;
+ while (decoration) {
+ if (decoration->type == DECORATION_REF_LOCAL &&
+ (contained || strset_contains(update_refs,
+ decoration->name))) {
+ printf("update %s %s %s\n",
+ decoration->name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&commit->object.oid));
+ }
+ decoration = decoration->next;
+ }
+ }
+
+ /* In --advance mode, advance the target ref */
+ if (result.clean == 1 && advance_name) {
+ printf("update %s %s %s\n",
+ advance_name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&onto->object.oid));
+ }
+
+ merge_finalize(&merge_opt, &result);
+ kh_destroy_oid_map(replayed_commits);
+ if (update_refs) {
+ strset_clear(update_refs);
+ free(update_refs);
+ }
+ ret = result.clean;
+
+cleanup:
+ release_revisions(&revs);
+
+ /* Return */
+ if (ret < 0)
+ exit(128);
+ return ret ? 0 : 1;
+}
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 07a9d37..b2efc6f 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,6 +1,5 @@
#include "builtin.h"
#include "config.h"
-#include "dir.h"
#include "gettext.h"
#include "parse-options.h"
#include "repository.h"
diff --git a/builtin/reset.c b/builtin/reset.c
index 4b018d2..1d62ff6 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -16,10 +16,8 @@
#include "hash.h"
#include "hex.h"
#include "lockfile.h"
-#include "tag.h"
#include "object.h"
#include "pretty.h"
-#include "run-command.h"
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
@@ -33,7 +31,6 @@
#include "setup.h"
#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
#include "trace.h"
#include "trace2.h"
#include "dir.h"
@@ -119,6 +116,10 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
+ if (!tree) {
+ error(_("unable to read tree (%s)"), oid_to_hex(oid));
+ goto out;
+ }
prime_cache_tree(the_repository, the_repository->index, tree);
}
@@ -284,7 +285,9 @@ static void parse_args(struct pathspec *pathspec,
verify_filename(prefix, argv[0], 1);
}
}
- *rev_ret = rev;
+
+ /* treat '@' as a shortcut for 'HEAD' */
+ *rev_ret = !strcmp("@", rev) ? "HEAD" : rev;
parse_pathspec(pathspec, 0,
PATHSPEC_PREFER_FULL |
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 181353d..7780372 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -7,13 +7,11 @@
#include "hex.h"
#include "revision.h"
#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "object.h"
#include "object-name.h"
#include "object-file.h"
#include "object-store-ll.h"
-#include "pack.h"
#include "pack-bitmap.h"
#include "log-tree.h"
#include "graph.h"
@@ -221,6 +219,7 @@ static void show_commit(struct commit *commit, void *data)
ctx.fmt = revs->commit_format;
ctx.output_encoding = get_log_output_encoding();
ctx.color = revs->diffopt.use_color;
+ ctx.rev = revs;
pretty_print_commit(&ctx, commit, &buf);
if (buf.len) {
if (revs->commit_format != CMIT_FMT_ONELINE)
@@ -547,6 +546,18 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
*
* Let "--missing" to conditionally set fetch_if_missing.
*/
+ /*
+ * NEEDSWORK: These loops that attempt to find presence of
+ * options without understanding that the options they are
+ * skipping are broken (e.g., it would not know "--grep
+ * --exclude-promisor-objects" is not triggering
+ * "--exclude-promisor-objects" option). We really need
+ * setup_revisions() to have a mechanism to allow and disallow
+ * some sets of options for different commands (like rev-list,
+ * replay, etc). Such a mechanism should do an early parsing
+ * of options and be able to manage the `--missing=...` and
+ * `--exclude-promisor-objects` options below.
+ */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--exclude-promisor-objects")) {
@@ -755,8 +766,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (arg_print_omitted)
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
- if (arg_missing_action == MA_PRINT)
+ if (arg_missing_action == MA_PRINT) {
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+ /* Add missing tips */
+ oidset_insert_from_set(&missing_objects, &revs.missing_commits);
+ oidset_clear(&revs.missing_commits);
+ }
traverse_commit_list_filtered(
&revs, show_commit, show_object, &info,
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index fde8861..624182e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -25,6 +25,7 @@
#include "submodule.h"
#include "commit-reach.h"
#include "shallow.h"
+#include "object-file-convert.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -297,7 +298,7 @@ static int try_difference(const char *arg)
show_rev(NORMAL, &end_oid, end);
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) {
- struct commit_list *exclude;
+ struct commit_list *exclude = NULL;
struct commit *a, *b;
a = lookup_commit_reference(the_repository, &start_oid);
b = lookup_commit_reference(the_repository, &end_oid);
@@ -305,7 +306,8 @@ static int try_difference(const char *arg)
*dotdot = '.';
return 0;
}
- exclude = repo_get_merge_bases(the_repository, a, b);
+ if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
+ exit(128);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
show_rev(REVERSED, &commit->object.oid, NULL);
@@ -675,6 +677,8 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+ const struct git_hash_algo *output_algo = NULL;
+ const struct git_hash_algo *compat = NULL;
int did_repo_setup = 0;
int has_dashdash = 0;
int output_prefix = 0;
@@ -746,6 +750,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
+ compat = the_repository->compat_hash_algo;
}
if (!strcmp(arg, "--")) {
@@ -833,6 +838,22 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
flags |= GET_OID_QUIETLY;
continue;
}
+ if (opt_with_value(arg, "--output-object-format", &arg)) {
+ if (!arg)
+ die(_("no object format specified"));
+ if (!strcmp(arg, the_hash_algo->name) ||
+ !strcmp(arg, "storage")) {
+ flags |= GET_OID_HASH_ANY;
+ output_algo = the_hash_algo;
+ continue;
+ }
+ else if (compat && !strcmp(arg, compat->name)) {
+ flags |= GET_OID_HASH_ANY;
+ output_algo = compat;
+ continue;
+ }
+ else die(_("unsupported object format: %s"), arg);
+ }
if (opt_with_value(arg, "--short", &arg)) {
filter &= ~(DO_FLAGS|DO_NOREV);
verify = 1;
@@ -882,7 +903,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (skip_prefix(arg, "--disambiguate=", &arg)) {
- repo_for_each_abbrev(the_repository, arg,
+ repo_for_each_abbrev(the_repository, arg, the_hash_algo,
show_abbrev, NULL);
continue;
}
@@ -893,13 +914,15 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (opt_with_value(arg, "--branches", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --branches"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--branches");
handle_ref_opt(arg, "refs/heads/");
continue;
}
if (opt_with_value(arg, "--tags", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --tags"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--tags");
handle_ref_opt(arg, "refs/tags/");
continue;
}
@@ -909,7 +932,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (opt_with_value(arg, "--remotes", &arg)) {
if (ref_excludes.hidden_refs_configured)
- return error(_("--exclude-hidden cannot be used together with --remotes"));
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--remotes");
handle_ref_opt(arg, "refs/remotes/");
continue;
}
@@ -1059,6 +1083,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(the_hash_algo->name);
continue;
}
+ if (!strcmp(arg, "--show-ref-format")) {
+ puts(ref_storage_format_to_name(the_repository->ref_storage_format));
+ continue;
+ }
if (!strcmp(arg, "--end-of-options")) {
seen_end_of_options = 1;
if (filter & (DO_FLAGS | DO_REVS))
@@ -1083,6 +1111,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!get_oid_with_context(the_repository, name,
flags, &oid, &unused)) {
+ if (output_algo)
+ repo_oid_to_algop(the_repository, &oid,
+ output_algo, &oid);
if (verify)
revs_count++;
else
diff --git a/builtin/revert.c b/builtin/revert.c
index e6f9a1a..53935d2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,5 +1,4 @@
#include "git-compat-util.h"
-#include "config.h"
#include "builtin.h"
#include "parse-options.h"
#include "diff.h"
@@ -7,7 +6,6 @@
#include "repository.h"
#include "revision.h"
#include "rerere.h"
-#include "dir.h"
#include "sequencer.h"
#include "branch.h"
@@ -45,6 +43,31 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}
+enum empty_action {
+ EMPTY_COMMIT_UNSPECIFIED = -1,
+ STOP_ON_EMPTY_COMMIT, /* output errors and stop in the middle of a cherry-pick */
+ DROP_EMPTY_COMMIT, /* skip with a notice message */
+ KEEP_EMPTY_COMMIT, /* keep recording as empty commits */
+};
+
+static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
+{
+ int *opt_value = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (!strcmp(arg, "stop"))
+ *opt_value = STOP_ON_EMPTY_COMMIT;
+ else if (!strcmp(arg, "drop"))
+ *opt_value = DROP_EMPTY_COMMIT;
+ else if (!strcmp(arg, "keep"))
+ *opt_value = KEEP_EMPTY_COMMIT;
+ else
+ return error(_("invalid value for '%s': '%s'"), "--empty", arg);
+
+ return 0;
+}
+
static int option_parse_m(const struct option *opt,
const char *arg, int unset)
{
@@ -87,6 +110,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
+ enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
int cmd = 0;
struct option base_options[] = {
OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
@@ -116,7 +140,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
- OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
+ OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
+ OPT_CALLBACK_F(0, "empty", &empty_opt, "(stop|drop|keep)",
+ N_("how to handle commits that become empty"),
+ PARSE_OPT_NONEG, parse_opt_empty),
OPT_END(),
};
options = parse_options_concat(options, cp_extra);
@@ -136,6 +163,11 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
+ if (opts->action == REPLAY_PICK) {
+ opts->drop_redundant_commits = (empty_opt == DROP_EMPTY_COMMIT);
+ opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == KEEP_EMPTY_COMMIT);
+ }
+
/* implies allow_empty */
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
@@ -169,6 +201,8 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
"--ff", opts->allow_ff,
"--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
"--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
+ "--keep-redundant-commits", opts->keep_redundant_commits,
+ "--empty", empty_opt != EMPTY_COMMIT_UNSPECIFIED,
NULL);
}
diff --git a/builtin/rm.c b/builtin/rm.c
index dff819a..fd130ce 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -9,7 +9,6 @@
#include "config.h"
#include "lockfile.h"
#include "dir.h"
-#include "cache-tree.h"
#include "gettext.h"
#include "hash.h"
#include "tree-walk.h"
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index cd6d9e4..3df9eaa 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,19 +1,14 @@
#include "builtin.h"
#include "config.h"
-#include "commit.h"
#include "hex.h"
-#include "refs.h"
#include "pkt-line.h"
-#include "sideband.h"
#include "run-command.h"
#include "remote.h"
#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
-#include "version.h"
#include "oid-array.h"
-#include "gpg-interface.h"
#include "gettext.h"
#include "protocol.h"
#include "parse-options.h"
@@ -135,21 +130,18 @@ static int send_pack_config(const char *k, const char *v,
const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
- break;
- case 1:
- args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
+ break;
+ case 1:
+ args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
+ else
+ return error(_("invalid value for '%s'"), k);
}
}
return git_default_config(k, v, ctx, cb);
@@ -208,7 +200,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option),
OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
@@ -341,6 +333,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
}
if (!ret && !transport_refs_pushed(remote_refs))
+ /* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
return ret;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 1307ed2..3c7cd2d 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -245,7 +245,6 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
- ctx.print_email_subject = 1;
ctx.date_mode = log->date_mode;
ctx.output_encoding = get_log_output_encoding();
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 7aac525..1c15421 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -6,7 +6,6 @@
#include "object-name.h"
#include "object-store-ll.h"
#include "object.h"
-#include "tag.h"
#include "string-list.h"
#include "parse-options.h"
@@ -173,7 +172,7 @@ static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
while (*refs) {
struct object_id oid;
- if ((starts_with(*refs, "refs/") || !strcmp(*refs, "HEAD")) &&
+ if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
!read_ref(*refs, &oid)) {
show_one(show_one_opts, *refs, &oid);
}
@@ -239,7 +238,7 @@ static int cmd_show_ref__exists(const char **refs)
if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
&unused_oid, &unused_referent, &unused_type,
&failure_errno)) {
- if (failure_errno == ENOENT) {
+ if (failure_errno == ENOENT || failure_errno == EISDIR) {
error(_("reference does not exist"));
ret = 2;
} else {
@@ -315,9 +314,9 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, 0);
- if ((!!exclude_existing_opts.enabled + !!verify + !!exists) > 1)
- die(_("only one of '%s', '%s' or '%s' can be given"),
- "--exclude-existing", "--verify", "--exists");
+ die_for_incompatible_opt3(exclude_existing_opts.enabled, "--exclude-existing",
+ verify, "--verify",
+ exists, "--exists");
if (exclude_existing_opts.enabled)
return cmd_show_ref__exclude_existing(&exclude_existing_opts);
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 5c8ffb1..0f52e25 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -8,14 +8,10 @@
#include "parse-options.h"
#include "pathspec.h"
#include "repository.h"
-#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#include "cache-tree.h"
#include "lockfile.h"
-#include "resolve-undo.h"
#include "unpack-trees.h"
-#include "wt-status.h"
#include "quote.h"
#include "setup.h"
#include "sparse-index.h"
@@ -777,8 +773,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_add_options,
- builtin_sparse_checkout_add_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_add_usage, 0);
sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
@@ -824,8 +819,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_set_options,
- builtin_sparse_checkout_set_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_set_usage, 0);
if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
return 1;
@@ -835,7 +829,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
* non-cone mode, if nothing is specified, manually select just the
* top-level directory (much as 'init' would do).
*/
- if (!core_sparse_checkout_cone && argc == 0) {
+ if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
argv = default_patterns;
argc = default_patterns_nr;
} else {
@@ -996,8 +990,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_check_rules_options,
- builtin_sparse_checkout_check_rules_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_check_rules_usage, 0);
if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
check_rules_opts.cone_mode = 1;
diff --git a/builtin/stash.c b/builtin/stash.c
index 4a6771c..062be1f 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -26,7 +26,6 @@
#include "sparse-index.h"
#include "log-tree.h"
#include "diffcore.h"
-#include "exec-cmd.h"
#include "reflog.h"
#include "add-interactive.h"
@@ -285,7 +284,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
if (parse_tree(tree))
return -1;
- init_tree_desc(t, tree->buffer, tree->size);
+ init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
opts.head_idx = 1;
opts.src_index = &the_index;
@@ -521,7 +520,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("Unable to write index."));
+ die(_("could not write index"));
}
static int do_apply_stash(const char *prefix, struct stash_info *info,
@@ -538,7 +537,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
repo_read_index_preload(the_repository, NULL, 0);
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL))
- return -1;
+ return error(_("could not write index"));
if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
NULL))
@@ -871,7 +870,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op
tree[i] = parse_tree_indirect(oid[i]);
if (parse_tree(tree[i]) < 0)
die(_("failed to parse tree"));
- init_tree_desc(&tree_desc[i], tree[i]->buffer, tree[i]->size);
+ init_tree_desc(&tree_desc[i], &tree[i]->object.oid,
+ tree[i]->buffer, tree[i]->size);
}
unpack_tree_opt.head_idx = -1;
@@ -1365,7 +1365,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
repo_read_index_preload(the_repository, NULL, 0);
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL) < 0) {
- ret = -1;
+ ret = error(_("could not write index"));
goto done;
}
@@ -1556,7 +1556,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
NULL, NULL, NULL)) {
- ret = -1;
+ ret = error(_("could not write index"));
goto done;
}
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 7b700a9..e5626e5 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -13,7 +13,7 @@ static void comment_lines(struct strbuf *buf)
size_t len;
msg = strbuf_detach(buf, &len);
- strbuf_add_commented_lines(buf, msg, len, comment_line_char);
+ strbuf_add_commented_lines(buf, msg, len, comment_line_str);
free(msg);
}
@@ -59,7 +59,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
strbuf_stripspace(&buf,
- mode == STRIP_COMMENTS ? comment_line_char : '\0');
+ mode == STRIP_COMMENTS ? comment_line_str : NULL);
else
comment_lines(&buf);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index cce4645..5a71b1e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -22,7 +22,6 @@
#include "remote.h"
#include "refs.h"
#include "refspec.h"
-#include "connect.h"
#include "revision.h"
#include "diffcore.h"
#include "diff.h"
@@ -304,6 +303,9 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
struct child_process cp = CHILD_PROCESS_INIT;
char *displaypath;
+ if (validate_submodule_path(path) < 0)
+ exit(128);
+
displaypath = get_submodule_displaypath(path, info->prefix,
info->super_prefix);
@@ -635,6 +637,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
.free_removed_argv_elements = 1,
};
+ if (validate_submodule_path(path) < 0)
+ exit(128);
+
if (!submodule_from_path(the_repository, null_oid(), path))
die(_("no submodule mapping found in .gitmodules for path '%s'"),
path);
@@ -1239,6 +1244,9 @@ static void sync_submodule(const char *path, const char *prefix,
if (!is_submodule_active(the_repository, path))
return;
+ if (validate_submodule_path(path) < 0)
+ exit(128);
+
sub = submodule_from_path(the_repository, null_oid(), path);
if (sub && sub->url) {
@@ -1284,7 +1292,7 @@ static void sync_submodule(const char *path, const char *prefix,
submodule_to_gitdir(&sb, path);
strbuf_addstr(&sb, "/config");
- if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
+ if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
die(_("failed to update remote for submodule '%s'"),
path);
@@ -1382,6 +1390,9 @@ static void deinit_submodule(const char *path, const char *prefix,
struct strbuf sb_config = STRBUF_INIT;
char *sub_git_dir = xstrfmt("%s/.git", path);
+ if (validate_submodule_path(path) < 0)
+ exit(128);
+
sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub || !sub->name)
@@ -1663,16 +1674,42 @@ static char *clone_submodule_sm_gitdir(const char *name)
return sm_gitdir;
}
+static int dir_contains_only_dotgit(const char *path)
+{
+ DIR *dir = opendir(path);
+ struct dirent *e;
+ int ret = 1;
+
+ if (!dir)
+ return 0;
+
+ e = readdir_skip_dot_and_dotdot(dir);
+ if (!e)
+ ret = 0;
+ else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) ||
+ (e = readdir_skip_dot_and_dotdot(dir))) {
+ error("unexpected item '%s' in '%s'", e->d_name, path);
+ ret = 0;
+ }
+
+ closedir(dir);
+ return ret;
+}
+
static int clone_submodule(const struct module_clone_data *clone_data,
struct string_list *reference)
{
char *p;
char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);
char *sm_alternate = NULL, *error_strategy = NULL;
+ struct stat st;
struct child_process cp = CHILD_PROCESS_INIT;
const char *clone_data_path = clone_data->path;
char *to_free = NULL;
+ if (validate_submodule_path(clone_data_path) < 0)
+ exit(128);
+
if (!is_absolute_path(clone_data->path))
clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
clone_data->path);
@@ -1682,6 +1719,10 @@ static int clone_submodule(const struct module_clone_data *clone_data,
"git dir"), sm_gitdir);
if (!file_exists(sm_gitdir)) {
+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
+ !is_empty_dir(clone_data_path))
+ die(_("directory not empty: '%s'"), clone_data_path);
+
if (safe_create_leading_directories_const(sm_gitdir) < 0)
die(_("could not create directory '%s'"), sm_gitdir);
@@ -1726,10 +1767,18 @@ static int clone_submodule(const struct module_clone_data *clone_data,
if(run_command(&cp))
die(_("clone of '%s' into submodule path '%s' failed"),
clone_data->url, clone_data_path);
+
+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
+ !dir_contains_only_dotgit(clone_data_path)) {
+ char *dot_git = xstrfmt("%s/.git", clone_data_path);
+ unlink(dot_git);
+ free(dot_git);
+ die(_("directory not empty: '%s'"), clone_data_path);
+ }
} else {
char *path;
- if (clone_data->require_init && !access(clone_data_path, X_OK) &&
+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
!is_empty_dir(clone_data_path))
die(_("directory not empty: '%s'"), clone_data_path);
if (safe_create_leading_directories_const(clone_data_path) < 0)
@@ -1739,6 +1788,23 @@ static int clone_submodule(const struct module_clone_data *clone_data,
free(path);
}
+ /*
+ * We already performed this check at the beginning of this function,
+ * before cloning the objects. This tries to detect racy behavior e.g.
+ * in parallel clones, where another process could easily have made the
+ * gitdir nested _after_ it was created.
+ *
+ * To prevent further harm coming from this unintentionally-nested
+ * gitdir, let's disable it by deleting the `HEAD` file.
+ */
+ if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0) {
+ char *head = xstrfmt("%s/HEAD", sm_gitdir);
+ unlink(head);
+ free(head);
+ die(_("refusing to create/use '%s' in another submodule's "
+ "git dir"), sm_gitdir);
+ }
+
connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
p = git_pathdup_submodule(clone_data_path, "config");
@@ -2518,6 +2584,9 @@ static int update_submodule(struct update_data *update_data)
{
int ret;
+ if (validate_submodule_path(update_data->sm_path) < 0)
+ return -1;
+
ret = determine_submodule_update_strategy(the_repository,
update_data->just_cloned,
update_data->sm_path,
@@ -2625,12 +2694,21 @@ static int update_submodules(struct update_data *update_data)
for (i = 0; i < suc.update_clone_nr; i++) {
struct update_clone_data ucd = suc.update_clone[i];
- int code;
+ int code = 128;
oidcpy(&update_data->oid, &ucd.oid);
update_data->just_cloned = ucd.just_cloned;
update_data->sm_path = ucd.sub->path;
+ /*
+ * Verify that the submodule path does not contain any
+ * symlinks; if it does, it might have been tampered with.
+ * TODO: allow exempting it via
+ * `safe.submodule.path` or something
+ */
+ if (validate_submodule_path(update_data->sm_path) < 0)
+ goto fail;
+
code = ensure_core_worktree(update_data->sm_path);
if (code)
goto fail;
@@ -3357,6 +3435,9 @@ static int module_add(int argc, const char **argv, const char *prefix)
normalize_path_copy(add_data.sm_path, add_data.sm_path);
strip_dir_trailing_slashes(add_data.sm_path);
+ if (validate_submodule_path(add_data.sm_path) < 0)
+ exit(128);
+
die_on_index_match(add_data.sm_path, force);
die_on_repo_without_commits(add_data.sm_path);
diff --git a/builtin/tag.c b/builtin/tag.c
index 3918eac..9a33cb5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -18,7 +18,6 @@
#include "object-store-ll.h"
#include "path.h"
#include "tag.h"
-#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
@@ -28,6 +27,7 @@
#include "ref-filter.h"
#include "date.h"
#include "write-or-die.h"
+#include "object-file-convert.h"
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
@@ -44,18 +44,11 @@ static const char * const git_tag_usage[] = {
static unsigned int colopts;
static int force_sign_annotate;
static int config_sign_tag = -1; /* unspecified */
-static int omit_empty = 0;
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
struct ref_format *format)
{
- struct ref_array array;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
- int i;
-
- memset(&array, 0, sizeof(array));
if (filter->lines == -1)
filter->lines = 0;
@@ -73,23 +66,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
if (verify_ref_format(format))
die(_("unable to parse format string"));
filter->with_commit_tag_algo = 1;
- filter_refs(&array, filter, FILTER_REFS_TAGS);
- filter_ahead_behind(the_repository, format, &array);
- ref_array_sort(sorting, &array);
-
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&output);
- strbuf_reset(&err);
- if (format_ref_array_item(array.items[i], format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- if (output.len || !omit_empty)
- putchar('\n');
- }
+ filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
free(to_free);
return 0;
@@ -174,18 +152,52 @@ static int verify_tag(const char *name, const char *ref UNUSED,
return 0;
}
-static int do_sign(struct strbuf *buffer)
+static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
+ struct object_id *compat_oid_buf)
{
- return sign_buffer(buffer, buffer, get_signing_key());
+ const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+ struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
+ struct strbuf compat_buf = STRBUF_INIT;
+ const char *keyid = get_signing_key();
+ int ret = -1;
+
+ if (sign_buffer(buffer, &sig, keyid))
+ return -1;
+
+ if (compat) {
+ const struct git_hash_algo *algo = the_repository->hash_algo;
+
+ if (convert_object_file(&compat_buf, algo, compat,
+ buffer->buf, buffer->len, OBJ_TAG, 1))
+ goto out;
+ if (sign_buffer(&compat_buf, &compat_sig, keyid))
+ goto out;
+ add_header_signature(&compat_buf, &sig, algo);
+ strbuf_addbuf(&compat_buf, &compat_sig);
+ hash_object_file(compat, compat_buf.buf, compat_buf.len,
+ OBJ_TAG, compat_oid_buf);
+ *compat_oid = compat_oid_buf;
+ }
+
+ if (compat_sig.len)
+ add_header_signature(buffer, &compat_sig, compat);
+
+ strbuf_addbuf(buffer, &sig);
+ ret = 0;
+out:
+ strbuf_release(&sig);
+ strbuf_release(&compat_sig);
+ strbuf_release(&compat_buf);
+ return ret;
}
static const char tag_template[] =
N_("\nWrite a message for tag:\n %s\n"
- "Lines starting with '%c' will be ignored.\n");
+ "Lines starting with '%s' will be ignored.\n");
static const char tag_template_nocleanup[] =
N_("\nWrite a message for tag:\n %s\n"
- "Lines starting with '%c' will be kept; you may remove them"
+ "Lines starting with '%s' will be kept; you may remove them"
" yourself if you want to.\n");
static int git_tag_config(const char *var, const char *value,
@@ -249,9 +261,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
{
- if (sign && do_sign(buf) < 0)
+ struct object_id *compat_oid = NULL, compat_oid_buf;
+ if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
return error(_("unable to sign the tag"));
- if (write_object_file(buf->buf, buf->len, OBJ_TAG, result) < 0)
+ if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
+ compat_oid, 0) < 0)
return error(_("unable to write tag file"));
return 0;
}
@@ -314,11 +328,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
- strbuf_commented_addf(&buf, comment_line_char,
- _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_str,
+ _(tag_template), tag, comment_line_str);
else
- strbuf_commented_addf(&buf, comment_line_char,
- _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_str,
+ _(tag_template_nocleanup), tag, comment_line_str);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -333,7 +347,7 @@ static void create_tag(const struct object_id *object, const char *object_ref,
if (opt->cleanup_mode != CLEANUP_NONE)
strbuf_stripspace(buf,
- opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_str : NULL);
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
@@ -481,7 +495,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_MERGED(&filter, N_("print only tags that are merged")),
OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
- OPT_BOOL(0, "omit-empty", &omit_empty,
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options),
{
@@ -501,7 +515,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
setup_ref_filter_porcelain_msg();
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_tag_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
memset(&opt, 0, sizeof(opt));
filter.lines = -1;
@@ -547,7 +567,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct column_options copts;
memset(&copts, 0, sizeof(copts));
copts.padding = 2;
- run_column_filter(colopts, &copts);
+ if (run_column_filter(colopts, &copts))
+ die(_("could not start 'git column'"));
}
filter.name_patterns = argv;
ret = list_tags(&filter, sorting, &format);
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index fef7423..f1c85a0 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -10,12 +10,8 @@
#include "delta.h"
#include "pack.h"
#include "blob.h"
-#include "commit.h"
#include "replace-object.h"
#include "strbuf.h"
-#include "tag.h"
-#include "tree.h"
-#include "tree-walk.h"
#include "progress.h"
#include "decorate.h"
#include "fsck.h"
@@ -683,13 +679,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
use(the_hash_algo->rawsz);
/* Write the last part of the buffer to stdout */
- while (len) {
- int ret = xwrite(1, buffer + offset, len);
- if (ret <= 0)
- break;
- len -= ret;
- offset += ret;
- }
+ write_in_full(1, buffer + offset, len);
/* All done */
return has_errors;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index c0c4e65..e46afbc 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -7,11 +7,10 @@
#include "parse-options.h"
#include "quote.h"
#include "repository.h"
-#include "strvec.h"
static const char * const git_update_ref_usage[] = {
- N_("git update-ref [<options>] -d <refname> [<old-val>]"),
- N_("git update-ref [<options>] <refname> <new-val> [<old-val>]"),
+ N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
+ N_("git update-ref [<options>] <refname> <new-oid> [<old-oid>]"),
N_("git update-ref [<options>] --stdin [-z]"),
NULL
};
@@ -78,14 +77,14 @@ static char *parse_refname(const char **next)
}
/*
- * The value being parsed is <oldvalue> (as opposed to <newvalue>; the
+ * The value being parsed is <old-oid> (as opposed to <new-oid>; the
* difference affects which error messages are generated):
*/
#define PARSE_SHA1_OLD 0x01
/*
* For backwards compatibility, accept an empty string for update's
- * <newvalue> in binary mode to be equivalent to specifying zeros.
+ * <new-oid> in binary mode to be equivalent to specifying zeros.
*/
#define PARSE_SHA1_ALLOW_EMPTY 0x02
@@ -141,7 +140,7 @@ static int parse_next_oid(const char **next, const char *end,
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",
+ warning("%s %s: missing <new-oid>, treating as zero",
command, refname);
oidclr(oid);
} else {
@@ -159,14 +158,14 @@ static int parse_next_oid(const char **next, const char *end,
invalid:
die(flags & PARSE_SHA1_OLD ?
- "%s %s: invalid <oldvalue>: %s" :
- "%s %s: invalid <newvalue>: %s",
+ "%s %s: invalid <old-oid>: %s" :
+ "%s %s: invalid <new-oid>: %s",
command, refname, arg.buf);
eof:
die(flags & PARSE_SHA1_OLD ?
- "%s %s: unexpected end of input when reading <oldvalue>" :
- "%s %s: unexpected end of input when reading <newvalue>",
+ "%s %s: unexpected end of input when reading <old-oid>" :
+ "%s %s: unexpected end of input when reading <new-oid>",
command, refname);
}
@@ -195,7 +194,7 @@ static void parse_cmd_update(struct ref_transaction *transaction,
if (parse_next_oid(&next, end, &new_oid, "update", refname,
PARSE_SHA1_ALLOW_EMPTY))
- die("update %s: missing <newvalue>", refname);
+ die("update %s: missing <new-oid>", refname);
have_old = !parse_next_oid(&next, end, &old_oid, "update", refname,
PARSE_SHA1_OLD);
@@ -226,10 +225,10 @@ static void parse_cmd_create(struct ref_transaction *transaction,
die("create: missing <ref>");
if (parse_next_oid(&next, end, &new_oid, "create", refname, 0))
- die("create %s: missing <newvalue>", refname);
+ die("create %s: missing <new-oid>", refname);
if (is_null_oid(&new_oid))
- die("create %s: zero <newvalue>", refname);
+ die("create %s: zero <new-oid>", refname);
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
@@ -261,7 +260,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
have_old = 0;
} else {
if (is_null_oid(&old_oid))
- die("delete %s: zero <oldvalue>", refname);
+ die("delete %s: zero <old-oid>", refname);
have_old = 1;
}
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 9b021ef..46d9327 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -8,6 +8,8 @@
#include "replace-object.h"
#include "upload-pack.h"
#include "serve.h"
+#include "commit.h"
+#include "environment.h"
static const char * const upload_pack_usage[] = {
N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
@@ -37,6 +39,8 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
packet_trace_identity("upload-pack");
disable_replace_refs();
+ save_commit_buffer = 0;
+ xsetenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 0);
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
diff --git a/builtin/var.c b/builtin/var.c
index 8cf7dd9..cf55672 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -90,7 +90,7 @@ static char *git_config_val_global(int ident_flag UNUSED)
char *user, *xdg;
size_t unused;
- git_global_config(&user, &xdg);
+ git_global_config_paths(&user, &xdg);
if (xdg && *xdg) {
normalize_path_copy(xdg, xdg);
strbuf_addf(&buf, "%s\n", xdg);
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 9680b58..0d2b9ae 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -9,10 +9,8 @@
#include "config.h"
#include "gettext.h"
#include "object-name.h"
-#include "object-store-ll.h"
#include "repository.h"
#include "commit.h"
-#include "run-command.h"
#include "parse-options.h"
#include "gpg-interface.h"
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index d875327..c731e2f 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -9,7 +9,6 @@
#include "config.h"
#include "gettext.h"
#include "tag.h"
-#include "run-command.h"
#include "object-name.h"
#include "parse-options.h"
#include "gpg-interface.h"
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 62b7e26..7c6c725 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -49,14 +49,14 @@
_("No possible source branch, inferring '--orphan'")
#define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
- _("If you meant to create a worktree containing a new orphan branch\n" \
+ _("If you meant to create a worktree containing a new unborn branch\n" \
"(branch with no commits) for this repository, you can do so\n" \
"using the --orphan flag:\n" \
"\n" \
" git worktree add --orphan -b %s %s\n")
#define WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT \
- _("If you meant to create a worktree containing a new orphan branch\n" \
+ _("If you meant to create a worktree containing a new unborn branch\n" \
"(branch with no commits) for this repository, you can do so\n" \
"using the --orphan flag:\n" \
"\n" \
@@ -365,12 +365,12 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
bare &&
git_config_set_multivar_in_file_gently(
- to_file, "core.bare", NULL, "true", 0))
+ to_file, "core.bare", NULL, "true", NULL, 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
if (!git_configset_get(&cs, "core.worktree") &&
git_config_set_in_file_gently(to_file,
- "core.worktree", NULL))
+ "core.worktree", NULL, NULL))
error(_("failed to unset '%s' in '%s'"),
"core.worktree", to_file);
@@ -416,7 +416,6 @@ static int add_worktree(const char *path, const char *refname,
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
const char *name;
- struct child_process cp = CHILD_PROCESS_INIT;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
int len, ret;
@@ -424,7 +423,8 @@ static int add_worktree(const char *path, const char *refname,
struct commit *commit = NULL;
int is_branch = 0;
struct strbuf sb_name = STRBUF_INIT;
- struct worktree **worktrees;
+ struct worktree **worktrees, *wt = NULL;
+ struct ref_store *wt_refs;
worktrees = get_worktrees();
check_candidate_path(path, opts->force, worktrees, "add");
@@ -495,21 +495,33 @@ static int add_worktree(const char *path, const char *refname,
strbuf_realpath(&realpath, get_git_common_dir(), 1);
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
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
- * looks like an object ID will do since it will be immediately
- * replaced by the symbolic-ref or update-ref invocation in the new
- * worktree.
- */
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, "%s", oid_to_hex(null_oid()));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
/*
+ * Set up the ref store of the worktree and create the HEAD reference.
+ */
+ wt = get_linked_worktree(name, 1);
+ if (!wt) {
+ ret = error(_("could not find created worktree '%s'"), name);
+ goto done;
+ }
+ wt_refs = get_worktree_ref_store(wt);
+
+ ret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);
+ if (ret)
+ goto done;
+
+ if (!is_branch && commit)
+ ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
+ NULL, 0, UPDATE_REFS_MSG_ON_ERR);
+ else
+ ret = refs_create_symref(wt_refs, "HEAD", symref.buf, NULL);
+ if (ret)
+ goto done;
+
+ /*
* If the current worktree has sparse-checkout enabled, then copy
* the sparse-checkout patterns from the current worktree.
*/
@@ -526,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
- cp.git_cmd = 1;
-
- if (!is_branch && commit) {
- strvec_pushl(&cp.args, "update-ref", "HEAD",
- oid_to_hex(&commit->object.oid), NULL);
- } else {
- strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
- symref.buf, NULL);
- if (opts->quiet)
- strvec_push(&cp.args, "--quiet");
- }
-
- strvec_pushv(&cp.env, child_env.v);
- ret = run_command(&cp);
- if (ret)
- goto done;
if (opts->orphan &&
(ret = make_worktree_orphan(refname, opts, &child_env)))
@@ -587,6 +583,7 @@ done:
strbuf_release(&sb_git);
strbuf_release(&sb_name);
strbuf_release(&realpath);
+ free_worktree(wt);
return ret;
}
@@ -660,7 +657,7 @@ static int can_use_local_refs(const struct add_opts *opts)
strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
strbuf_addstr(&path, "/HEAD");
strbuf_read_file(&contents, path.buf, 64);
- strbuf_stripspace(&contents, 0);
+ strbuf_stripspace(&contents, NULL);
strbuf_strip_suffix(&contents, "\n");
warning(_("HEAD points to an invalid (or orphaned) reference.\n"
@@ -730,11 +727,11 @@ static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
}
if (opt_track) {
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- "--track");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--track");
} else if (!opts->checkout) {
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- "--no-checkout");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--no-checkout");
}
return 1;
}
@@ -784,7 +781,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
N_("create or reset a branch")),
- OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn/orphaned branch")),
+ OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn branch")),
OPT_BOOL('d', "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", &keep_locked, N_("keep the new working tree locked")),
@@ -806,16 +803,17 @@ static int add(int ac, const char **av, const char *prefix)
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
if (opts.detach && opts.orphan)
- die(_("options '%s', and '%s' cannot be used together"),
+ die(_("options '%s' and '%s' cannot be used together"),
"--orphan", "--detach");
if (opts.orphan && opt_track)
- die(_("'%s' and '%s' cannot be used together"), "--orphan", "--track");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--track");
if (opts.orphan && !opts.checkout)
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- "--no-checkout");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--no-checkout");
if (opts.orphan && ac == 2)
- die(_("'%s' and '%s' cannot be used together"), "--orphan",
- _("<commit-ish>"));
+ die(_("option '%s' and commit-ish cannot be used together"),
+ "--orphan");
if (lock_reason && !keep_locked)
die(_("the option '%s' requires '%s'"), "--reason", "--lock");
if (lock_reason)
@@ -850,21 +848,21 @@ static int add(int ac, const char **av, const char *prefix)
const char *s = worktree_basename(path, &n);
new_branch = xstrndup(s, n);
} else if (opts.orphan) {
- // No-op
+ ; /* no-op */
} else if (opts.detach) {
- // Check HEAD
+ /* Check HEAD */
if (!strcmp(branch, "HEAD"))
can_use_local_refs(&opts);
} else if (ac < 2 && new_branch) {
- // DWIM: Infer --orphan when repo has no refs.
+ /* DWIM: Infer --orphan when repo has no refs. */
opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
} else if (ac < 2) {
- // DWIM: Guess branch name from path.
+ /* DWIM: Guess branch name from path. */
const char *s = dwim_branch(path, &new_branch);
if (s)
branch = s;
- // DWIM: Infer --orphan when repo has no refs.
+ /* DWIM: Infer --orphan when repo has no refs. */
opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
} else if (ac == 2) {
struct object_id oid;