revert(3p/git): Revert merge of git upstream at v2.26.2

This causes cgit to serve error pages, which is undesirable.

This reverts commit 5229c9b232, reversing
changes made to f2b211131f.
This commit is contained in:
Vincent Ambo 2020-05-26 00:06:52 +01:00
parent 6f8fbf4aa4
commit 93ba78d6f4
1006 changed files with 60537 additions and 148724 deletions

View file

@ -20,7 +20,6 @@
#include "bulk-checkin.h"
#include "argv-array.h"
#include "submodule.h"
#include "add-interactive.h"
static const char * const builtin_add_usage[] = {
N_("git add [<options>] [--] <pathspec>..."),
@ -29,9 +28,6 @@ static const char * const builtin_add_usage[] = {
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
static int add_renormalize;
static int pathspec_file_nul;
static const char *pathspec_from_file;
static int legacy_stash_p; /* support for the scripted `git stash` */
struct update_callback_data {
int flags;
@ -189,34 +185,6 @@ int run_add_interactive(const char *revision, const char *patch_mode,
{
int status, i;
struct argv_array argv = ARGV_ARRAY_INIT;
int use_builtin_add_i =
git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
if (use_builtin_add_i < 0)
git_config_get_bool("add.interactive.usebuiltin",
&use_builtin_add_i);
if (use_builtin_add_i == 1) {
enum add_p_mode mode;
if (!patch_mode)
return !!run_add_i(the_repository, pathspec);
if (!strcmp(patch_mode, "--patch"))
mode = ADD_P_ADD;
else if (!strcmp(patch_mode, "--patch=stash"))
mode = ADD_P_STASH;
else if (!strcmp(patch_mode, "--patch=reset"))
mode = ADD_P_RESET;
else if (!strcmp(patch_mode, "--patch=checkout"))
mode = ADD_P_CHECKOUT;
else if (!strcmp(patch_mode, "--patch=worktree"))
mode = ADD_P_WORKTREE;
else
die("'%s' not supported", patch_mode);
return !!run_add_p(the_repository, mode, revision, pathspec);
}
argv_array_push(&argv, "add--interactive");
if (patch_mode)
@ -341,10 +309,6 @@ static struct option builtin_add_options[] = {
N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")),
OPT_HIDDEN_BOOL(0, "legacy-stash-p", &legacy_stash_p,
N_("backend for `git stash -p`")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(),
};
@ -355,7 +319,6 @@ static int add_config(const char *var, const char *value, void *cb)
ignore_add_errors = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
@ -406,10 +369,7 @@ 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_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\""));
fprintf(stderr, _("Use -f if you really want to add them.\n"));
exit_status = 1;
}
@ -442,28 +402,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive) {
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
if (add_interactive)
exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
}
if (legacy_stash_p) {
struct pathspec pathspec;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH |
PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
return run_add_interactive(NULL, "--patch=stash", &pathspec);
}
if (edit_interactive) {
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --edit"));
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
}
argc--;
argv++;
@ -475,6 +418,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible"));
if (!take_worktree_changes && addremove_explicit < 0 && argc)
/* Turn "git add pathspec..." to "git add -A pathspec..." */
addremove = 1;
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
@ -487,6 +434,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
(intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));
if (require_pathspec && argc == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}
/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
@ -496,38 +456,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);
if (pathspec_from_file) {
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (require_pathspec && pathspec.nr == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
if (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\""));
return 0;
}
if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr)
/* Turn "git add pathspec..." to "git add -A pathspec..." */
addremove = 1;
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
(intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));
if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt"));

View file

@ -24,6 +24,7 @@
#include "sequencer.h"
#include "revision.h"
#include "merge-recursive.h"
#include "revision.h"
#include "log-tree.h"
#include "notes-utils.h"
#include "rerere.h"
@ -81,11 +82,6 @@ enum signoff_type {
SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
};
enum show_patch_type {
SHOW_PATCH_RAW = 0,
SHOW_PATCH_DIFF = 1,
};
struct am_state {
/* state directory path */
char *dir;
@ -1075,6 +1071,19 @@ static const char *msgnum(const struct am_state *state)
return sb.buf;
}
/**
* Refresh and write index.
*/
static void refresh_and_write_cache(void)
{
struct lock_file lock_file = LOCK_INIT;
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write index file"));
}
/**
* Dies with a user-friendly message on how to proceed after resolving the
* problem. This message can be overridden with state->resolvemsg.
@ -1263,9 +1272,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
ident_line = find_commit_header(buffer, "author", &ident_len);
if (!ident_line)
die(_("missing author line in commit %s"),
oid_to_hex(&commit->object.oid));
if (split_ident_line(&id, ident_line, ident_len) < 0)
die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
@ -1531,7 +1538,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
o.branch1 = "HEAD";
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
o.branch2 = their_tree_name;
o.detect_directory_renames = MERGE_DIRECTORY_RENAMES_NONE;
o.detect_directory_renames = 0;
if (state->quiet)
o.verbosity = 0;
@ -1696,8 +1703,7 @@ static void am_run(struct am_state *state, int resume)
unlink(am_path(state, "dirtyindex"));
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0) < 0)
die(_("unable to write index file"));
refresh_and_write_cache();
if (repo_index_has_changes(the_repository, NULL, &sb)) {
write_state_bool(state, "dirtyindex", 1);
@ -1768,7 +1774,7 @@ static void am_run(struct am_state *state, int resume)
linelen(state->msg), state->msg);
if (advice_amworkdir)
advise(_("Use 'git am --show-current-patch=diff' to see the failed patch"));
advise(_("Use 'git am --show-current-patch' to see the failed patch"));
die_user_resolve(state);
}
@ -2066,7 +2072,7 @@ static void am_abort(struct am_state *state)
am_destroy(state);
}
static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
static int show_patch(struct am_state *state)
{
struct strbuf sb = STRBUF_INIT;
const char *patch_path;
@ -2083,17 +2089,7 @@ static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
return ret;
}
switch (sub_mode) {
case SHOW_PATCH_RAW:
patch_path = am_path(state, msgnum(state));
break;
case SHOW_PATCH_DIFF:
patch_path = am_path(state, "patch");
break;
default:
BUG("invalid mode for --show-current-patch");
}
patch_path = am_path(state, msgnum(state));
len = strbuf_read_file(&sb, patch_path, 0);
if (len < 0)
die_errno(_("failed to read '%s'"), patch_path);
@ -2133,7 +2129,7 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
return 0;
}
enum resume_type {
enum resume_mode {
RESUME_FALSE = 0,
RESUME_APPLY,
RESUME_RESOLVED,
@ -2143,45 +2139,6 @@ enum resume_type {
RESUME_SHOW_PATCH
};
struct resume_mode {
enum resume_type mode;
enum show_patch_type sub_mode;
};
static int parse_opt_show_current_patch(const struct option *opt, const char *arg, int unset)
{
int *opt_value = opt->value;
struct resume_mode *resume = container_of(opt_value, struct resume_mode, mode);
/*
* Please update $__git_showcurrentpatch in git-completion.bash
* when you add new options
*/
const char *valid_modes[] = {
[SHOW_PATCH_DIFF] = "diff",
[SHOW_PATCH_RAW] = "raw"
};
int new_value = SHOW_PATCH_RAW;
if (arg) {
for (new_value = 0; new_value < ARRAY_SIZE(valid_modes); new_value++) {
if (!strcmp(arg, valid_modes[new_value]))
break;
}
if (new_value >= ARRAY_SIZE(valid_modes))
return error(_("Invalid value for --show-current-patch: %s"), arg);
}
if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
return error(_("--show-current-patch=%s is incompatible with "
"--show-current-patch=%s"),
arg, valid_modes[resume->sub_mode]);
resume->mode = RESUME_SHOW_PATCH;
resume->sub_mode = new_value;
return 0;
}
static int git_am_config(const char *k, const char *v, void *cb)
{
int status;
@ -2199,7 +2156,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
int binary = -1;
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
struct resume_mode resume = { .mode = RESUME_FALSE };
enum resume_mode resume = RESUME_FALSE;
int in_progress;
int ret = 0;
@ -2268,26 +2225,24 @@ int cmd_am(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG),
OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
N_("override error message when patch failure occurs")),
OPT_CMDMODE(0, "continue", &resume.mode,
OPT_CMDMODE(0, "continue", &resume,
N_("continue applying patches after resolving a conflict"),
RESUME_RESOLVED),
OPT_CMDMODE('r', "resolved", &resume.mode,
OPT_CMDMODE('r', "resolved", &resume,
N_("synonyms for --continue"),
RESUME_RESOLVED),
OPT_CMDMODE(0, "skip", &resume.mode,
OPT_CMDMODE(0, "skip", &resume,
N_("skip the current patch"),
RESUME_SKIP),
OPT_CMDMODE(0, "abort", &resume.mode,
OPT_CMDMODE(0, "abort", &resume,
N_("restore the original branch and abort the patching operation."),
RESUME_ABORT),
OPT_CMDMODE(0, "quit", &resume.mode,
OPT_CMDMODE(0, "quit", &resume,
N_("abort the patching operation but keep HEAD where it is."),
RESUME_QUIT),
{ OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
"(diff|raw)",
N_("show the patch being applied"),
PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
parse_opt_show_current_patch, RESUME_SHOW_PATCH },
OPT_CMDMODE(0, "show-current-patch", &resume,
N_("show the patch being applied."),
RESUME_SHOW_PATCH),
OPT_BOOL(0, "committer-date-is-author-date",
&state.committer_date_is_author_date,
N_("lie about committer date")),
@ -2337,12 +2292,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* intend to feed us a patch but wanted to continue
* unattended.
*/
if (argc || (resume.mode == RESUME_FALSE && !isatty(0)))
if (argc || (resume == RESUME_FALSE && !isatty(0)))
die(_("previous rebase directory %s still exists but mbox given."),
state.dir);
if (resume.mode == RESUME_FALSE)
resume.mode = RESUME_APPLY;
if (resume == RESUME_FALSE)
resume = RESUME_APPLY;
if (state.signoff == SIGNOFF_EXPLICIT)
am_append_signoff(&state);
@ -2356,7 +2311,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
* stray directories.
*/
if (file_exists(state.dir) && !state.rebasing) {
if (resume.mode == RESUME_ABORT || resume.mode == RESUME_QUIT) {
if (resume == RESUME_ABORT || resume == RESUME_QUIT) {
am_destroy(&state);
am_state_release(&state);
return 0;
@ -2367,7 +2322,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
state.dir);
}
if (resume.mode)
if (resume)
die(_("Resolve operation not in progress, we are not resuming."));
for (i = 0; i < argc; i++) {
@ -2385,7 +2340,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
argv_array_clear(&paths);
}
switch (resume.mode) {
switch (resume) {
case RESUME_FALSE:
am_run(&state, 0);
break;
@ -2406,7 +2361,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
am_destroy(&state);
break;
case RESUME_SHOW_PATCH:
ret = show_patch(&state, resume.sub_mode);
ret = show_patch(&state);
break;
default:
BUG("invalid resume value");

View file

@ -52,8 +52,8 @@ static void set_terms(struct bisect_terms *terms, const char *bad,
terms->term_bad = xstrdup(bad);
}
static const char vocab_bad[] = "bad|new";
static const char vocab_good[] = "good|old";
static const char *vocab_bad = "bad|new";
static const char *vocab_good = "good|old";
/*
* Check whether the string `term` belongs to the set of strings
@ -169,12 +169,11 @@ static int bisect_reset(const char *commit)
argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
error(_("could not check out original"
" HEAD '%s'. Try 'git bisect"
" reset <commit>'."), branch.buf);
strbuf_release(&branch);
argv_array_clear(&argv);
return -1;
return error(_("could not check out original"
" HEAD '%s'. Try 'git bisect"
" reset <commit>'."), branch.buf);
}
argv_array_clear(&argv);
}
@ -206,31 +205,31 @@ static int bisect_write(const char *state, const char *rev,
struct object_id oid;
struct commit *commit;
FILE *fp = NULL;
int res = 0;
int retval = 0;
if (!strcmp(state, terms->term_bad)) {
strbuf_addf(&tag, "refs/bisect/%s", state);
} else if (one_of(state, terms->term_good, "skip", NULL)) {
strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
} else {
res = error(_("Bad bisect_write argument: %s"), state);
retval = error(_("Bad bisect_write argument: %s"), state);
goto finish;
}
if (get_oid(rev, &oid)) {
res = error(_("couldn't get the oid of the rev '%s'"), rev);
retval = error(_("couldn't get the oid of the rev '%s'"), rev);
goto finish;
}
if (update_ref(NULL, tag.buf, &oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR)) {
res = -1;
retval = -1;
goto finish;
}
fp = fopen(git_path_bisect_log(), "a");
if (!fp) {
res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
retval = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
goto finish;
}
@ -244,7 +243,7 @@ finish:
if (fp)
fclose(fp);
strbuf_release(&tag);
return res;
return retval;
}
static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
@ -282,23 +281,35 @@ static int mark_good(const char *refname, const struct object_id *oid,
return 1;
}
static const char need_bad_and_good_revision_warning[] =
static const char *need_bad_and_good_revision_warning =
N_("You need to give me at least one %s and %s revision.\n"
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
static const char need_bisect_start_warning[] =
static const char *need_bisect_start_warning =
N_("You need to start by \"git bisect start\".\n"
"You then need to give me at least one %s and %s revision.\n"
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
static int decide_next(const struct bisect_terms *terms,
const char *current_term, int missing_good,
int missing_bad)
static int bisect_next_check(const struct bisect_terms *terms,
const char *current_term)
{
int missing_good = 1, missing_bad = 1, retval = 0;
const char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
const char *good_glob = xstrfmt("%s-*", terms->term_good);
if (ref_exists(bad_ref))
missing_bad = 0;
for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
(void *) &missing_good);
if (!missing_good && !missing_bad)
return 0;
if (!current_term)
return -1;
goto finish;
if (!current_term) {
retval = -1;
goto finish;
}
if (missing_good && !missing_bad &&
!strcmp(current_term, terms->term_good)) {
@ -309,7 +320,7 @@ static int decide_next(const struct bisect_terms *terms,
*/
warning(_("bisecting only with a %s commit"), terms->term_bad);
if (!isatty(0))
return 0;
goto finish;
/*
* TRANSLATORS: Make sure to include [Y] and [n] in your
* translation. The program will only accept English input
@ -317,35 +328,21 @@ static int decide_next(const struct bisect_terms *terms,
*/
yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
if (starts_with(yesno, "N") || starts_with(yesno, "n"))
return -1;
return 0;
retval = -1;
goto finish;
}
if (!is_empty_or_missing_file(git_path_bisect_start())) {
retval = error(_(need_bad_and_good_revision_warning),
vocab_bad, vocab_good, vocab_bad, vocab_good);
} else {
retval = error(_(need_bisect_start_warning),
vocab_good, vocab_bad, vocab_good, vocab_bad);
}
if (!is_empty_or_missing_file(git_path_bisect_start()))
return error(_(need_bad_and_good_revision_warning),
vocab_bad, vocab_good, vocab_bad, vocab_good);
else
return error(_(need_bisect_start_warning),
vocab_good, vocab_bad, vocab_good, vocab_bad);
}
static int bisect_next_check(const struct bisect_terms *terms,
const char *current_term)
{
int missing_good = 1, missing_bad = 1;
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
if (ref_exists(bad_ref))
missing_bad = 0;
for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
(void *) &missing_good);
free(good_glob);
free(bad_ref);
return decide_next(terms, current_term, missing_good, missing_bad);
finish:
free((void *) good_glob);
free((void *) bad_ref);
return retval;
}
static int get_terms(struct bisect_terms *terms)
@ -399,7 +396,7 @@ static int bisect_terms(struct bisect_terms *terms, const char *option)
static int bisect_append_log_quoted(const char **argv)
{
int res = 0;
int retval = 0;
FILE *fp = fopen(git_path_bisect_log(), "a");
struct strbuf orig_args = STRBUF_INIT;
@ -407,25 +404,25 @@ static int bisect_append_log_quoted(const char **argv)
return -1;
if (fprintf(fp, "git bisect start") < 1) {
res = -1;
retval = -1;
goto finish;
}
sq_quote_argv(&orig_args, argv);
if (fprintf(fp, "%s\n", orig_args.buf) < 1)
res = -1;
retval = -1;
finish:
fclose(fp);
strbuf_release(&orig_args);
return res;
return retval;
}
static int bisect_start(struct bisect_terms *terms, int no_checkout,
const char **argv, int argc)
{
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
int flags, pathspec_pos, res = 0;
int flags, pathspec_pos, retval = 0;
struct string_list revs = STRING_LIST_INIT_DUP;
struct string_list states = STRING_LIST_INIT_DUP;
struct strbuf start_head = STRBUF_INIT;
@ -526,7 +523,7 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
argv_array_pushl(&argv, "checkout", start_head.buf,
"--", NULL);
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
res = error(_("checking out '%s' failed."
retval = error(_("checking out '%s' failed."
" Try 'git bisect start "
"<valid-branch>'."),
start_head.buf);
@ -574,12 +571,12 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
if (no_checkout) {
if (get_oid(start_head.buf, &oid) < 0) {
res = error(_("invalid ref: '%s'"), start_head.buf);
retval = error(_("invalid ref: '%s'"), start_head.buf);
goto finish;
}
if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR)) {
res = -1;
retval = -1;
goto finish;
}
}
@ -591,26 +588,26 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
for (i = 0; i < states.nr; i++)
if (bisect_write(states.items[i].string,
revs.items[i].string, terms, 1)) {
res = -1;
retval = -1;
goto finish;
}
if (must_write_terms && write_terms(terms->term_bad,
terms->term_good)) {
res = -1;
retval = -1;
goto finish;
}
res = bisect_append_log_quoted(argv);
if (res)
res = -1;
retval = bisect_append_log_quoted(argv);
if (retval)
retval = -1;
finish:
string_list_clear(&revs, 0);
string_list_clear(&states, 0);
strbuf_release(&start_head);
strbuf_release(&bisect_names);
return res;
return retval;
}
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
@ -666,8 +663,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
switch (cmdmode) {
case NEXT_ALL:
res = bisect_next_all(the_repository, prefix, no_checkout);
break;
return bisect_next_all(the_repository, prefix, no_checkout);
case WRITE_TERMS:
if (argc != 2)
return error(_("--write-terms requires two arguments"));
@ -714,13 +710,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
return error("BUG: unknown subcommand '%d'", cmdmode);
}
free_terms(&terms);
/*
* Handle early success
* From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
*/
if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE)
res = BISECT_OK;
return abs(res);
return !!res;
}

View file

@ -26,6 +26,7 @@
#include "progress.h"
#include "object-store.h"
#include "blame.h"
#include "string-list.h"
#include "refs.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
@ -319,18 +320,18 @@ static const char *format_time(timestamp_t time, const char *tz_str,
return time_buf.buf;
}
#define OUTPUT_ANNOTATE_COMPAT (1U<<0)
#define OUTPUT_LONG_OBJECT_NAME (1U<<1)
#define OUTPUT_RAW_TIMESTAMP (1U<<2)
#define OUTPUT_PORCELAIN (1U<<3)
#define OUTPUT_SHOW_NAME (1U<<4)
#define OUTPUT_SHOW_NUMBER (1U<<5)
#define OUTPUT_SHOW_SCORE (1U<<6)
#define OUTPUT_NO_AUTHOR (1U<<7)
#define OUTPUT_SHOW_EMAIL (1U<<8)
#define OUTPUT_LINE_PORCELAIN (1U<<9)
#define OUTPUT_COLOR_LINE (1U<<10)
#define OUTPUT_SHOW_AGE_WITH_COLOR (1U<<11)
#define OUTPUT_ANNOTATE_COMPAT 001
#define OUTPUT_LONG_OBJECT_NAME 002
#define OUTPUT_RAW_TIMESTAMP 004
#define OUTPUT_PORCELAIN 010
#define OUTPUT_SHOW_NAME 020
#define OUTPUT_SHOW_NUMBER 040
#define OUTPUT_SHOW_SCORE 0100
#define OUTPUT_NO_AUTHOR 0200
#define OUTPUT_SHOW_EMAIL 0400
#define OUTPUT_LINE_PORCELAIN 01000
#define OUTPUT_COLOR_LINE 02000
#define OUTPUT_SHOW_AGE_WITH_COLOR 04000
static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
{
@ -459,7 +460,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? the_hash_algo->hexsz : abbrev;
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
if (opt & OUTPUT_COLOR_LINE) {
if (cnt > 0) {
@ -861,6 +862,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("Ignore revisions from <file>")),
OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
/*
* The following two options are parsed by parse_revision_opt()
* and are only included here to get included in the "-h"
* output:
*/
{ OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb },
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
@ -876,7 +885,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
struct range_set ranges;
unsigned int range_i;
long anchor;
const int hexsz = the_hash_algo->hexsz;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
@ -923,11 +931,11 @@ parse_done:
} else if (show_progress < 0)
show_progress = isatty(2);
if (0 < abbrev && abbrev < hexsz)
if (0 < abbrev && abbrev < GIT_SHA1_HEXSZ)
/* one more abbrev length is needed for the boundary commit */
abbrev++;
else if (!abbrev)
abbrev = hexsz;
abbrev = GIT_SHA1_HEXSZ;
if (revs_file && read_ancestry(revs_file))
die_errno("reading graft file '%s' failed", revs_file);

View file

@ -624,7 +624,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_SET_INT_F(0, "set-upstream", &track, N_("do not use"),
BRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),
OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("unset the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("Unset the upstream info")),
OPT__COLOR(&branch_use_color, N_("use colored output")),
OPT_SET_INT('r', "remotes", &filter.kind, N_("act on remote-tracking branches"),
FILTER_REFS_REMOTES),

View file

@ -1,6 +1,4 @@
#include "builtin.h"
#include "argv-array.h"
#include "parse-options.h"
#include "cache.h"
#include "bundle.h"
@ -11,184 +9,59 @@
* bundle supporting "fetch", "pull", and "ls-remote".
*/
static const char * const builtin_bundle_usage[] = {
N_("git bundle create [<options>] <file> <git-rev-list args>"),
N_("git bundle verify [<options>] <file>"),
N_("git bundle list-heads <file> [<refname>...]"),
N_("git bundle unbundle <file> [<refname>...]"),
NULL
};
static const char * const builtin_bundle_create_usage[] = {
N_("git bundle create [<options>] <file> <git-rev-list args>"),
NULL
};
static const char * const builtin_bundle_verify_usage[] = {
N_("git bundle verify [<options>] <file>"),
NULL
};
static const char * const builtin_bundle_list_heads_usage[] = {
N_("git bundle list-heads <file> [<refname>...]"),
NULL
};
static const char * const builtin_bundle_unbundle_usage[] = {
N_("git bundle unbundle <file> [<refname>...]"),
NULL
};
static int verbose;
static int parse_options_cmd_bundle(int argc,
const char **argv,
const char* prefix,
const char * const usagestr[],
const struct option options[],
const char **bundle_file) {
int newargc;
newargc = parse_options(argc, argv, NULL, options, usagestr,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc < 1)
usage_with_options(usagestr, options);
*bundle_file = prefix_filename(prefix, argv[0]);
return newargc;
}
static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
int all_progress_implied = 0;
int progress = isatty(STDERR_FILENO);
struct argv_array pack_opts;
struct option options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
N_("show progress meter"), 1),
OPT_SET_INT(0, "all-progress", &progress,
N_("show progress meter during object writing phase"), 2),
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
OPT_END()
};
const char* bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_create_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
argv_array_init(&pack_opts);
if (progress == 0)
argv_array_push(&pack_opts, "--quiet");
else if (progress == 1)
argv_array_push(&pack_opts, "--progress");
else if (progress == 2)
argv_array_push(&pack_opts, "--all-progress");
if (progress && all_progress_implied)
argv_array_push(&pack_opts, "--all-progress-implied");
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts);
}
static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;
int quiet = 0;
struct option options[] = {
OPT_BOOL('q', "quiet", &quiet,
N_("do not show bundle details")),
OPT_END()
};
const char* bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
close(bundle_fd);
if (verify_bundle(the_repository, &header, !quiet))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
return 0;
}
static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;
struct option options[] = {
OPT_END()
};
const char* bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
close(bundle_fd);
return !!list_bundle_refs(&header, argc, argv);
}
static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
struct bundle_header header;
int bundle_fd = -1;
struct option options[] = {
OPT_END()
};
const char* bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
memset(&header, 0, sizeof(header));
if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
return 1;
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
return !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
}
static const char builtin_bundle_usage[] =
"git bundle create <file> <git-rev-list args>\n"
" or: git bundle verify <file>\n"
" or: git bundle list-heads <file> [<refname>...]\n"
" or: git bundle unbundle <file> [<refname>...]";
int cmd_bundle(int argc, const char **argv, const char *prefix)
{
struct option options[] = {
OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
OPT_END()
};
int result;
struct bundle_header header;
const char *cmd, *bundle_file;
int bundle_fd = -1;
argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc < 3)
usage(builtin_bundle_usage);
packet_trace_identity("bundle");
cmd = argv[1];
bundle_file = prefix_filename(prefix, argv[2]);
argc -= 2;
argv += 2;
if (argc < 2)
usage_with_options(builtin_bundle_usage, options);
memset(&header, 0, sizeof(header));
if (strcmp(cmd, "create") && (bundle_fd =
read_bundle_header(bundle_file, &header)) < 0)
return 1;
else if (!strcmp(argv[0], "create"))
result = cmd_bundle_create(argc, argv, prefix);
else if (!strcmp(argv[0], "verify"))
result = cmd_bundle_verify(argc, argv, prefix);
else if (!strcmp(argv[0], "list-heads"))
result = cmd_bundle_list_heads(argc, argv, prefix);
else if (!strcmp(argv[0], "unbundle"))
result = cmd_bundle_unbundle(argc, argv, prefix);
else {
error(_("Unknown subcommand: %s"), argv[0]);
usage_with_options(builtin_bundle_usage, options);
if (!strcmp(cmd, "verify")) {
close(bundle_fd);
if (argc != 1) {
usage(builtin_bundle_usage);
return 1;
}
if (verify_bundle(the_repository, &header, 1))
return 1;
fprintf(stderr, _("%s is okay\n"), bundle_file);
return 0;
}
return result ? 1 : 0;
if (!strcmp(cmd, "list-heads")) {
close(bundle_fd);
return !!list_bundle_refs(&header, argc, argv);
}
if (!strcmp(cmd, "create")) {
if (argc < 2) {
usage(builtin_bundle_usage);
return 1;
}
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
return !!create_bundle(the_repository, bundle_file, argc, argv);
} else if (!strcmp(cmd, "unbundle")) {
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
return !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
} else
usage(builtin_bundle_usage);
}

View file

@ -15,7 +15,6 @@
#include "sha1-array.h"
#include "packfile.h"
#include "object-store.h"
#include "promisor-remote.h"
struct batch_options {
int enabled;
@ -262,7 +261,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
strbuf_addstr(sb, data->rest);
} else if (is_atom("deltabase", atom, len)) {
if (data->mark_query)
data->info.delta_base_oid = &data->delta_base_oid;
data->info.delta_base_sha1 = data->delta_base_oid.hash;
else
strbuf_addstr(sb,
oid_to_hex(&data->delta_base_oid));
@ -525,8 +524,8 @@ static int batch_objects(struct batch_options *opt)
if (opt->all_objects) {
struct object_cb_data cb;
if (has_promisor_remote())
warning("This repository uses promisor remotes. Some objects may not be loaded.");
if (repository_format_partial_clone)
warning("This repository has extensions.partialClone set. Some objects may not be loaded.");
cb.opt = opt;
cb.expand = &data;

View file

@ -32,19 +32,19 @@ static const struct option check_ignore_options[] = {
OPT_END()
};
static void output_pattern(const char *path, struct path_pattern *pattern)
static void output_exclude(const char *path, struct exclude *exclude)
{
char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
char *bang = (exclude && exclude->flags & EXC_FLAG_NEGATIVE) ? "!" : "";
char *slash = (exclude && exclude->flags & EXC_FLAG_MUSTBEDIR) ? "/" : "";
if (!nul_term_line) {
if (!verbose) {
write_name_quoted(path, stdout, '\n');
} else {
if (pattern) {
quote_c_style(pattern->pl->src, NULL, stdout, 0);
if (exclude) {
quote_c_style(exclude->el->src, NULL, stdout, 0);
printf(":%d:%s%s%s\t",
pattern->srcpos,
bang, pattern->pattern, slash);
exclude->srcpos,
bang, exclude->pattern, slash);
}
else {
printf("::\t");
@ -56,11 +56,11 @@ static void output_pattern(const char *path, struct path_pattern *pattern)
if (!verbose) {
printf("%s%c", path, '\0');
} else {
if (pattern)
if (exclude)
printf("%s%c%d%c%s%s%s%c%s%c",
pattern->pl->src, '\0',
pattern->srcpos, '\0',
bang, pattern->pattern, slash, '\0',
exclude->el->src, '\0',
exclude->srcpos, '\0',
bang, exclude->pattern, slash, '\0',
path, '\0');
else
printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
@ -74,7 +74,7 @@ static int check_ignore(struct dir_struct *dir,
const char *full_path;
char *seen;
int num_ignored = 0, i;
struct path_pattern *pattern;
struct exclude *exclude;
struct pathspec pathspec;
if (!argc) {
@ -103,18 +103,15 @@ static int check_ignore(struct dir_struct *dir,
seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
for (i = 0; i < pathspec.nr; i++) {
full_path = pathspec.items[i].match;
pattern = NULL;
exclude = NULL;
if (!seen[i]) {
int dtype = DT_UNKNOWN;
pattern = last_matching_pattern(dir, &the_index,
exclude = last_exclude_matching(dir, &the_index,
full_path, &dtype);
if (!verbose && pattern &&
pattern->flags & PATTERN_FLAG_NEGATIVE)
pattern = NULL;
}
if (!quiet && (pattern || show_non_matching))
output_pattern(pathspec.items[i].original, pattern);
if (pattern)
if (!quiet && (exclude || show_non_matching))
output_exclude(pathspec.items[i].original, exclude);
if (exclude)
num_ignored++;
}
free(seen);

View file

@ -70,8 +70,6 @@ struct checkout_opts {
int checkout_worktree;
const char *ignore_unmerged_opt;
int ignore_unmerged;
int pathspec_file_nul;
const char *pathspec_from_file;
const char *new_branch;
const char *new_branch_force;
@ -128,7 +126,6 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
if (pos >= 0) {
struct cache_entry *old = active_cache[pos];
if (ce->ce_mode == old->ce_mode &&
!ce_intent_to_add(old) &&
oideq(&ce->oid, &old->oid)) {
old->ce_flags |= CE_UPDATE;
discard_cache_entry(ce);
@ -524,8 +521,6 @@ static int checkout_paths(const struct checkout_opts *opts,
/* Now we are committed to check them out */
if (opts->checkout_worktree)
errs |= checkout_worktree(opts);
else
remove_marked_cache_entries(&the_index, 1);
/*
* Allow updating the index when checking out from the index.
@ -713,11 +708,11 @@ static int merge_working_tree(const struct checkout_opts *opts,
* give up or do a real merge, depending on
* whether the merge flag was used.
*/
struct tree *result;
struct tree *work;
struct tree *old_tree;
struct merge_options o;
struct strbuf sb = STRBUF_INIT;
struct strbuf old_commit_shortname = STRBUF_INIT;
if (!opts->merge)
return 1;
@ -735,6 +730,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
"the following files:\n%s"), sb.buf);
strbuf_release(&sb);
if (repo_index_has_changes(the_repository,
get_commit_tree(old_branch_info->commit),
&sb))
warning(_("staged changes in the following files may be lost: %s"),
sb.buf);
strbuf_release(&sb);
/* Do more real merge */
/*
@ -758,7 +760,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
*/
init_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);
work = write_tree_from_memory(&o);
ret = reset_tree(new_tree,
opts, 1,
@ -766,25 +768,19 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (ret)
return ret;
o.ancestor = old_branch_info->name;
if (old_branch_info->name == NULL) {
strbuf_add_unique_abbrev(&old_commit_shortname,
&old_branch_info->commit->object.oid,
DEFAULT_ABBREV);
o.ancestor = old_commit_shortname.buf;
}
o.branch1 = new_branch_info->name;
o.branch2 = "local";
ret = merge_trees(&o,
new_tree,
work,
old_tree);
old_tree,
&result);
if (ret < 0)
exit(128);
ret = reset_tree(new_tree,
opts, 0,
writeout_error);
strbuf_release(&o.obuf);
strbuf_release(&old_commit_shortname);
if (ret)
return ret;
}
@ -865,7 +861,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
strbuf_addf(&msg, "checkout: moving from %s to %s",
old_desc ? old_desc : "(invalid)", new_branch_info->name);
else
strbuf_insertstr(&msg, 0, reflog_msg);
strbuf_insert(&msg, 0, reflog_msg, strlen(reflog_msg));
if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
/* Nothing to do. */
@ -1117,43 +1113,12 @@ static void setup_new_branch_info_and_source_tree(
}
}
static const char *parse_remote_branch(const char *arg,
struct object_id *rev,
int could_be_checkout_paths)
{
int num_matches = 0;
const char *remote = unique_tracking_name(arg, rev, &num_matches);
if (remote && could_be_checkout_paths) {
die(_("'%s' could be both a local file and a tracking branch.\n"
"Please use -- (and optionally --no-guess) to disambiguate"),
arg);
}
if (!remote && num_matches > 1) {
if (advice_checkout_ambiguous_remote_branch_name) {
advise(_("If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
"you can do so by fully qualifying the name with the --track option:\n"
"\n"
" git checkout --track origin/<name>\n"
"\n"
"If you'd like to always have checkouts of an ambiguous <name> prefer\n"
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config."));
}
die(_("'%s' matched multiple (%d) remote tracking branches"),
arg, num_matches);
}
return remote;
}
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new_branch_info,
struct checkout_opts *opts,
struct object_id *rev)
struct object_id *rev,
int *dwim_remotes_matched)
{
const char **new_branch = &opts->new_branch;
int argcount = 0;
@ -1258,9 +1223,13 @@ static int parse_branchname_arg(int argc, const char **argv,
recover_with_dwim = 0;
if (recover_with_dwim) {
const char *remote = parse_remote_branch(arg, rev,
could_be_checkout_paths);
const char *remote = unique_tracking_name(arg, rev,
dwim_remotes_matched);
if (remote) {
if (could_be_checkout_paths)
die(_("'%s' could be both a local file and a tracking branch.\n"
"Please use -- (and optionally --no-guess) to disambiguate"),
arg);
*new_branch = arg;
arg = remote;
/* DWIMmed to create local branch, case (3).(b) */
@ -1511,8 +1480,6 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&opts->pathspec_file_nul),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
@ -1525,6 +1492,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
const char * const usagestr[])
{
struct branch_info new_branch_info;
int dwim_remotes_matched = 0;
int parseopt_flags = 0;
memset(&new_branch_info, 0, sizeof(new_branch_info));
@ -1632,7 +1600,8 @@ 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,
&dwim_remotes_matched);
argv += n;
argc -= n;
} else if (!opts->accept_ref && opts->from_treeish) {
@ -1649,6 +1618,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
die(_("reference is not a tree: %s"), opts->from_treeish);
}
if (opts->accept_pathspec && !opts->empty_pathspec_ok && !argc &&
!opts->patch_mode) /* patch mode is special */
die(_("you must specify path(s) to restore"));
if (argc) {
parse_pathspec(&opts->pathspec, 0,
opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
@ -1668,33 +1641,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->force_detach)
die(_("git checkout: --detach does not take a path argument '%s'"),
argv[0]);
}
if (opts->pathspec_from_file) {
if (opts->pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
if (opts->force_detach)
die(_("--pathspec-from-file is incompatible with --detach"));
if (opts->patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
parse_pathspec_file(&opts->pathspec, 0,
0,
prefix, opts->pathspec_from_file, opts->pathspec_file_nul);
} else if (opts->pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (opts->pathspec.nr) {
if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."));
} else {
if (opts->accept_pathspec && !opts->empty_pathspec_ok &&
!opts->patch_mode) /* patch mode is special */
die(_("you must specify path(s) to restore"));
}
if (opts->new_branch) {
@ -1709,10 +1659,28 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
UNLEAK(opts);
if (opts->patch_mode || opts->pathspec.nr)
return checkout_paths(opts, new_branch_info.name);
else
if (opts->patch_mode || opts->pathspec.nr) {
int ret = checkout_paths(opts, new_branch_info.name);
if (ret && dwim_remotes_matched > 1 &&
advice_checkout_ambiguous_remote_branch_name)
advise(_("'%s' matched more than one remote tracking branch.\n"
"We found %d remotes with a reference that matched. So we fell back\n"
"on trying to resolve the argument as a path, but failed there too!\n"
"\n"
"If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
"you can do so by fully qualifying the name with the --track option:\n"
"\n"
" git checkout --track origin/<name>\n"
"\n"
"If you'd like to always have checkouts of an ambiguous <name> prefer\n"
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config."),
argv[0],
dwim_remotes_matched);
return ret;
} else {
return checkout_branch(opts, &new_branch_info);
}
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
@ -1746,15 +1714,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.checkout_index = -2; /* default on */
opts.checkout_worktree = -2; /* default on */
if (argc == 3 && !strcmp(argv[1], "-b")) {
/*
* User ran 'git checkout -b <branch>' and expects
* the same behavior as 'git switch -c <branch>'.
*/
opts.switch_branch_doing_nothing_is_ok = 0;
opts.only_merge_on_switching_branches = 1;
}
options = parse_options_dup(checkout_options);
options = add_common_options(&opts, options);
options = add_common_switch_branch_options(&opts, options);

View file

@ -158,8 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
*dir_gone = 1;
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
is_nonbare_repository_dir(path)) {
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) {
if (!quiet) {
quote_path_relative(path->buf, prefix, &quoted);
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
@ -649,7 +648,7 @@ static int filter_by_patterns_cmd(void)
struct strbuf confirm = STRBUF_INIT;
struct strbuf **ignore_list;
struct string_list_item *item;
struct pattern_list *pl;
struct exclude_list *el;
int changed = -1, i;
for (;;) {
@ -672,7 +671,7 @@ static int filter_by_patterns_cmd(void)
break;
memset(&dir, 0, sizeof(dir));
pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
el = add_exclude_list(&dir, EXC_CMDL, "manual exclude");
ignore_list = strbuf_split_max(&confirm, ' ', 0);
for (i = 0; ignore_list[i]; i++) {
@ -680,7 +679,7 @@ static int filter_by_patterns_cmd(void)
if (!ignore_list[i]->len)
continue;
add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
add_exclude(ignore_list[i]->buf, "", 0, el, -(i+1));
}
changed = 0;
@ -902,7 +901,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
struct pathspec pathspec;
struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct pattern_list *pl;
struct exclude_list *el;
struct string_list_item *item;
const char *qname;
struct option options[] = {
@ -947,19 +946,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (force > 1)
rm_flags = 0;
else
dir.flags |= DIR_SKIP_NESTED_GIT;
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (argc) {
/*
* Remaining args implies pathspecs specified, and we should
* recurse within those.
*/
remove_directories = 1;
}
if (remove_directories)
dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS;
@ -969,9 +958,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!ignored)
setup_standard_excludes(&dir);
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++)
add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
@ -1018,7 +1007,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
for_each_string_list_item(item, &del_list) {
struct stat st;
strbuf_reset(&abs_path);
if (prefix)
strbuf_addstr(&abs_path, prefix);
@ -1052,6 +1040,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
}
strbuf_reset(&abs_path);
}
strbuf_release(&abs_path);

View file

@ -32,6 +32,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "object-store.h"
/*
* Overall FIXMEs:
@ -59,7 +60,6 @@ static const char *real_git_dir;
static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
static int option_sparse_checkout;
static enum transport_family family;
static struct string_list option_config = STRING_LIST_INIT_NODUP;
static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
@ -147,8 +147,6 @@ static struct option builtin_clone_options[] = {
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
N_("any cloned submodules will use their remote-tracking branch")),
OPT_BOOL(0, "sparse", &option_sparse_checkout,
N_("initialize sparse-checkout file to include only files at root")),
OPT_END()
};
@ -673,7 +671,7 @@ static void update_remote_refs(const struct ref *refs,
const char *msg,
struct transport *transport,
int check_connectivity,
int check_refs_are_promisor_objects_only)
int check_refs_only)
{
const struct ref *rm = mapped_refs;
@ -682,8 +680,7 @@ static void update_remote_refs(const struct ref *refs,
opt.transport = transport;
opt.progress = transport->progress;
opt.check_refs_are_promisor_objects_only =
!!check_refs_are_promisor_objects_only;
opt.check_refs_only = !!check_refs_only;
if (check_connected(iterate_ref_map, &rm, &opt))
die(_("remote did not send all necessary objects"));
@ -737,27 +734,6 @@ static void update_head(const struct ref *our, const struct ref *remote,
}
}
static int git_sparse_checkout_init(const char *repo)
{
struct argv_array argv = ARGV_ARRAY_INIT;
int result = 0;
argv_array_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
/*
* We must apply the setting in the current process
* for the later checkout to use the sparse-checkout file.
*/
core_apply_sparse_checkout = 1;
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
error(_("failed to initialize sparse-checkout"));
result = 1;
}
argv_array_clear(&argv);
return result;
}
static int checkout(int submodule_progress)
{
struct object_id oid;
@ -809,12 +785,12 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
err |= run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
struct argv_array args = ARGV_ARRAY_INIT;
argv_array_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
if (option_shallow_submodules == 1)
argv_array_push(&args, "--depth=1");
@ -833,11 +809,6 @@ static int checkout(int submodule_progress)
argv_array_push(&args, "--no-fetch");
}
if (option_single_branch >= 0)
argv_array_push(&args, option_single_branch ?
"--single-branch" :
"--no-single-branch");
err = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
}
@ -929,7 +900,7 @@ static void dissociate_from_references(void)
free(alternates);
}
static int path_exists(const char *path)
static int dir_exists(const char *path)
{
struct stat sb;
return !stat(path, &sb);
@ -957,6 +928,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
fetch_if_missing = 0;
packet_trace_identity("clone");
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@ -1009,7 +982,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
dir = guess_dir_name(repo_name, is_bundle, option_bare);
strip_trailing_slashes(dir);
dest_exists = path_exists(dir);
dest_exists = dir_exists(dir);
if (dest_exists && !is_empty_dir(dir))
die(_("destination path '%s' already exists and is not "
"an empty directory."), dir);
@ -1020,7 +993,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
work_tree = NULL;
else {
work_tree = getenv("GIT_WORK_TREE");
if (work_tree && path_exists(work_tree))
if (work_tree && dir_exists(work_tree))
die(_("working tree '%s' already exists."), work_tree);
}
@ -1048,7 +1021,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (real_git_dir) {
if (path_exists(real_git_dir))
if (dir_exists(real_git_dir))
junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
junk_git_dir = real_git_dir;
} else {
@ -1134,9 +1107,6 @@ 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(option_origin);
strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,
@ -1190,11 +1160,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
transport->server_options = &server_options;
if (filter_options.choice) {
const char *spec =
expand_list_objects_filter_spec(&filter_options);
struct strbuf expanded_filter_spec = STRBUF_INIT;
expand_list_objects_filter_spec(&filter_options,
&expanded_filter_spec);
transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
spec);
expanded_filter_spec.buf);
transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
strbuf_release(&expanded_filter_spec);
}
if (transport->smart_options && !deepen && !filter_options.choice)
@ -1296,6 +1268,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
junk_mode = JUNK_LEAVE_REPO;
fetch_if_missing = 1;
err = checkout(submodule_progress);
strbuf_release(&reflog_msg);

View file

@ -8,18 +8,25 @@
#include "object-store.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
N_("git commit-graph [--object-dir <objdir>]"),
N_("git commit-graph read [--object-dir <objdir>]"),
N_("git commit-graph verify [--object-dir <objdir>] [--shallow]"),
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] <split options>"),
NULL
};
static const char * const builtin_commit_graph_verify_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
N_("git commit-graph verify [--object-dir <objdir>] [--shallow]"),
NULL
};
static const char * const builtin_commit_graph_read_usage[] = {
N_("git commit-graph read [--object-dir <objdir>]"),
NULL
};
static const char * const builtin_commit_graph_write_usage[] = {
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] <split options>"),
NULL
};
@ -31,32 +38,11 @@ static struct opts_commit_graph {
int append;
int split;
int shallow;
int progress;
} opts;
static struct object_directory *find_odb(struct repository *r,
const char *obj_dir)
{
struct object_directory *odb;
char *obj_dir_real = real_pathdup(obj_dir, 1);
prepare_alt_odb(r);
for (odb = r->objects->odb; odb; odb = odb->next) {
if (!strcmp(obj_dir_real, real_path(odb->path)))
break;
}
free(obj_dir_real);
if (!odb)
die(_("could not find object directory matching %s"), obj_dir);
return odb;
}
static int graph_verify(int argc, const char **argv)
{
struct commit_graph *graph = NULL;
struct object_directory *odb = NULL;
char *graph_name;
int open_ok;
int fd;
@ -69,13 +55,9 @@ static int graph_verify(int argc, const char **argv)
N_("The object directory to store the graph")),
OPT_BOOL(0, "shallow", &opts.shallow,
N_("if the commit-graph is split, only verify the tip file")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
OPT_END(),
};
trace2_cmd_mode("verify");
opts.progress = isatty(2);
argc = parse_options(argc, argv, NULL,
builtin_commit_graph_verify_options,
builtin_commit_graph_verify_usage, 0);
@ -84,11 +66,8 @@ static int graph_verify(int argc, const char **argv)
opts.obj_dir = get_object_directory();
if (opts.shallow)
flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
odb = find_odb(the_repository, opts.obj_dir);
graph_name = get_commit_graph_filename(odb);
graph_name = get_commit_graph_filename(opts.obj_dir);
open_ok = open_commit_graph(graph_name, &fd, &st);
if (!open_ok && errno != ENOENT)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
@ -96,9 +75,9 @@ static int graph_verify(int argc, const char **argv)
FREE_AND_NULL(graph_name);
if (open_ok)
graph = load_commit_graph_one_fd_st(fd, &st, odb);
else
graph = read_commit_graph_one(the_repository, odb);
graph = load_commit_graph_one_fd_st(fd, &st);
else
graph = read_commit_graph_one(the_repository, opts.obj_dir);
/* Return failure if open_ok predicted success */
if (!graph)
@ -108,6 +87,64 @@ static int graph_verify(int argc, const char **argv)
return verify_commit_graph(the_repository, graph, flags);
}
static int graph_read(int argc, const char **argv)
{
struct commit_graph *graph = NULL;
char *graph_name;
int open_ok;
int fd;
struct stat st;
static struct option builtin_commit_graph_read_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
N_("The object directory to store the graph")),
OPT_END(),
};
argc = parse_options(argc, argv, NULL,
builtin_commit_graph_read_options,
builtin_commit_graph_read_usage, 0);
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
graph_name = get_commit_graph_filename(opts.obj_dir);
open_ok = open_commit_graph(graph_name, &fd, &st);
if (!open_ok)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
graph = load_commit_graph_one_fd_st(fd, &st);
if (!graph)
return 1;
FREE_AND_NULL(graph_name);
printf("header: %08x %d %d %d %d\n",
ntohl(*(uint32_t*)graph->data),
*(unsigned char*)(graph->data + 4),
*(unsigned char*)(graph->data + 5),
*(unsigned char*)(graph->data + 6),
*(unsigned char*)(graph->data + 7));
printf("num_commits: %u\n", graph->num_commits);
printf("chunks:");
if (graph->chunk_oid_fanout)
printf(" oid_fanout");
if (graph->chunk_oid_lookup)
printf(" oid_lookup");
if (graph->chunk_commit_data)
printf(" commit_metadata");
if (graph->chunk_extra_edges)
printf(" extra_edges");
printf("\n");
UNLEAK(graph);
return 0;
}
extern int read_replace_refs;
static struct split_commit_graph_opts split_opts;
@ -115,10 +152,9 @@ static int graph_write(int argc, const char **argv)
{
struct string_list *pack_indexes = NULL;
struct string_list *commit_hex = NULL;
struct object_directory *odb = NULL;
struct string_list lines;
int result = 0;
enum commit_graph_write_flags flags = 0;
unsigned int flags = COMMIT_GRAPH_PROGRESS;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
@ -132,7 +168,6 @@ static int graph_write(int argc, const char **argv)
N_("start walk at commits listed by stdin")),
OPT_BOOL(0, "append", &opts.append,
N_("include all commits already in the commit-graph file")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
OPT_BOOL(0, "split", &opts.split,
N_("allow writing an incremental commit-graph file")),
OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
@ -144,13 +179,10 @@ static int graph_write(int argc, const char **argv)
OPT_END(),
};
opts.progress = isatty(2);
split_opts.size_multiple = 2;
split_opts.max_commits = 0;
split_opts.expire_time = 0;
trace2_cmd_mode("write");
argc = parse_options(argc, argv, NULL,
builtin_commit_graph_write_options,
builtin_commit_graph_write_usage, 0);
@ -160,17 +192,14 @@ static int graph_write(int argc, const char **argv)
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
if (opts.append)
flags |= COMMIT_GRAPH_WRITE_APPEND;
flags |= COMMIT_GRAPH_APPEND;
if (opts.split)
flags |= COMMIT_GRAPH_WRITE_SPLIT;
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
flags |= COMMIT_GRAPH_SPLIT;
read_replace_refs = 0;
odb = find_odb(the_repository, opts.obj_dir);
if (opts.reachable) {
if (write_commit_graph_reachable(odb, flags, &split_opts))
if (write_commit_graph_reachable(opts.obj_dir, flags, &split_opts))
return 1;
return 0;
}
@ -184,15 +213,13 @@ static int graph_write(int argc, const char **argv)
if (opts.stdin_packs)
pack_indexes = &lines;
if (opts.stdin_commits) {
if (opts.stdin_commits)
commit_hex = &lines;
flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
}
UNLEAK(buf);
}
if (write_commit_graph(odb,
if (write_commit_graph(opts.obj_dir,
pack_indexes,
commit_hex,
flags,
@ -222,9 +249,9 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
builtin_commit_graph_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
save_commit_buffer = 0;
if (argc > 0) {
if (!strcmp(argv[0], "read"))
return graph_read(argc, argv);
if (!strcmp(argv[0], "verify"))
return graph_verify(argc, argv);
if (!strcmp(argv[0], "write"))

View file

@ -107,9 +107,9 @@ static int all, also, interactive, patch_interactive, only, amend, signoff;
static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
static int no_post_rewrite, allow_empty_message;
static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
static char *sign_commit, *pathspec_from_file;
static char *sign_commit;
/*
* The default commit message cleanup mode will remove the lines
@ -343,31 +343,11 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
PATHSPEC_PREFER_FULL,
prefix, argv);
if (pathspec_from_file) {
if (interactive)
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
if (all)
die(_("--pathspec-from-file with -a does not make sense"));
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_FULL,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (!pathspec.nr && (also || (only && !amend && !allow_empty)))
die(_("No paths with --include/--only does not make sense."));
if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt"));
if (interactive) {
char *old_index_env = NULL, *old_repo_index_file;
char *old_index_env = NULL;
hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
@ -375,16 +355,12 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to create temporary index"));
old_repo_index_file = the_repository->index_file;
the_repository->index_file =
(char *)get_lock_file_path(&index_lock);
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1);
if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
setenv(INDEX_ENVIRONMENT, old_index_env, 1);
else
@ -534,7 +510,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
s->nowarn = nowarn;
s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
if (!s->is_initial)
oidcpy(&s->oid_commit, &oid);
hashcpy(s->sha1_commit, oid.hash);
s->status_format = status_format;
s->ignore_submodule_arg = ignore_submodule_arg;
@ -561,7 +537,7 @@ static void export_one(const char *var, const char *s, const char *e, int hack)
struct strbuf buf = STRBUF_INIT;
if (hack)
strbuf_addch(&buf, hack);
strbuf_add(&buf, s, e - s);
strbuf_addf(&buf, "%.*s", (int)(e - s), s);
setenv(var, buf.buf, 1);
strbuf_release(&buf);
}
@ -968,7 +944,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
*/
if (!committable && whence != FROM_MERGE && !allow_empty &&
!(amend && is_a_merge(current_head))) {
s->hints = advice_status_hints;
s->display_comment_prefix = old_display_comment_prefix;
run_status(stdout, index_file, prefix, 0, s);
if (amend)
@ -1223,6 +1198,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
if (argc == 0 && (also || (only && !amend && !allow_empty)))
die(_("No paths with --include/--only does not make sense."));
cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
handle_untracked_files_arg(s);
@ -1429,7 +1406,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
if (!s.is_initial)
oidcpy(&s.oid_commit, &oid);
hashcpy(s.sha1_commit, oid.hash);
s.ignore_submodule_arg = ignore_submodule_arg;
s.status_format = status_format;
@ -1486,6 +1463,28 @@ static int git_commit_config(const char *k, const char *v, void *cb)
return git_status_config(k, v, s);
}
int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
{
struct argv_array hook_env = ARGV_ARRAY_INIT;
va_list args;
int ret;
argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
argv_array_push(&hook_env, "GIT_EDITOR=:");
va_start(args, name);
ret = run_hook_ve(hook_env.argv,name, args);
va_end(args);
argv_array_clear(&hook_env);
return ret;
}
int cmd_commit(int argc, const char **argv, const char *prefix)
{
const char *argv_gc_auto[] = {"gc", "--auto", NULL};
@ -1536,8 +1535,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
/* end commit contents options */
OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
@ -1693,7 +1690,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
"not exceeded, and then \"git restore --staged :/\" to recover."));
if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
write_commit_graph_reachable(the_repository->objects->odb, 0, NULL))
write_commit_graph_reachable(get_object_directory(), 0, NULL))
return 1;
repo_rerere(the_repository, 0);

View file

@ -29,11 +29,10 @@ static int use_worktree_config;
static struct git_config_source given_config_source;
static int actions, type;
static char *default_value;
static int end_nul;
static int end_null;
static int respect_includes_opt = -1;
static struct config_options config_options;
static int show_origin;
static int show_scope;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
@ -152,11 +151,10 @@ static struct option builtin_config_options[] = {
OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
OPT_GROUP(N_("Other")),
OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")),
OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
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_END(),
};
@ -180,34 +178,22 @@ static void check_argc(int argc, int min, int max)
static void show_config_origin(struct strbuf *buf)
{
const char term = end_nul ? '\0' : '\t';
const char term = end_null ? '\0' : '\t';
strbuf_addstr(buf, current_config_origin_type());
strbuf_addch(buf, ':');
if (end_nul)
if (end_null)
strbuf_addstr(buf, current_config_name());
else
quote_c_style(current_config_name(), buf, NULL, 0);
strbuf_addch(buf, term);
}
static void show_config_scope(struct strbuf *buf)
{
const char term = end_nul ? '\0' : '\t';
const char *scope = config_scope_name(current_config_scope());
strbuf_addstr(buf, N_(scope));
strbuf_addch(buf, term);
}
static int show_all_config(const char *key_, const char *value_, void *cb)
{
if (show_origin || show_scope) {
if (show_origin) {
struct strbuf buf = STRBUF_INIT;
if (show_scope)
show_config_scope(&buf);
if (show_origin)
show_config_origin(&buf);
show_config_origin(&buf);
/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
@ -227,8 +213,6 @@ struct strbuf_list {
static int format_config(struct strbuf *buf, const char *key_, const char *value_)
{
if (show_scope)
show_config_scope(buf);
if (show_origin)
show_config_origin(buf);
if (show_keys)
@ -638,7 +622,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
!strcmp(given_config_source.file, "-")) {
given_config_source.file = NULL;
given_config_source.use_stdin = 1;
given_config_source.scope = CONFIG_SCOPE_COMMAND;
}
if (use_global_config) {
@ -654,8 +637,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
*/
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;
@ -665,13 +646,11 @@ int cmd_config(int argc, const char **argv, const char *prefix)
free(xdg_config);
}
}
else if (use_system_config) {
else if (use_system_config)
given_config_source.file = git_etc_gitconfig();
given_config_source.scope = CONFIG_SCOPE_SYSTEM;
} else if (use_local_config) {
else if (use_local_config)
given_config_source.file = git_pathdup("config");
given_config_source.scope = CONFIG_SCOPE_LOCAL;
} else if (use_worktree_config) {
else if (use_worktree_config) {
struct worktree **worktrees = get_worktrees(0);
if (repository_format_worktree_config)
given_config_source.file = git_pathdup("config.worktree");
@ -683,18 +662,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
"section in \"git help worktree\" for details"));
else
given_config_source.file = git_pathdup("config");
given_config_source.scope = CONFIG_SCOPE_LOCAL;
free_worktrees(worktrees);
} else if (given_config_source.file) {
if (!is_absolute_path(given_config_source.file) && prefix)
given_config_source.file =
prefix_filename(prefix, given_config_source.file);
given_config_source.scope = CONFIG_SCOPE_COMMAND;
} else if (given_config_source.blob) {
given_config_source.scope = CONFIG_SCOPE_COMMAND;
}
if (respect_includes_opt == -1)
config_options.respect_includes = !given_config_source.file;
else
@ -704,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
config_options.git_dir = get_git_dir();
}
if (end_nul) {
if (end_null) {
term = '\0';
delim = '\n';
key_delim = '\n';

View file

@ -15,6 +15,7 @@
#include "argv-array.h"
#include "run-command.h"
#include "object-store.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
@ -63,22 +64,19 @@ static const char *prio_names[] = {
};
static int commit_name_neq(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *entry,
const void *entry_or_key,
const void *peeled)
{
const struct commit_name *cn1, *cn2;
cn1 = container_of(eptr, const struct commit_name, entry);
cn2 = container_of(entry_or_key, const struct commit_name, entry);
const struct commit_name *cn1 = entry;
const struct commit_name *cn2 = entry_or_key;
return !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled);
}
static inline struct commit_name *find_commit_name(const struct object_id *peeled)
{
return hashmap_get_entry_from_hash(&names, oidhash(peeled), peeled,
struct commit_name, entry);
return hashmap_get_from_hash(&names, oidhash(peeled), peeled);
}
static int replace_name(struct commit_name *e,
@ -125,8 +123,8 @@ static void add_to_known_names(const char *path,
if (!e) {
e = xmalloc(sizeof(struct commit_name));
oidcpy(&e->peeled, peeled);
hashmap_entry_init(&e->entry, oidhash(peeled));
hashmap_add(&names, &e->entry);
hashmap_entry_init(e, oidhash(peeled));
hashmap_add(&names, e);
e->path = NULL;
}
e->tag = tag;
@ -315,7 +313,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
*/
append_name(n, dst);
if (longformat)
append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
return;
@ -332,8 +330,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit_name *n;
init_commit_names(&commit_names);
hashmap_for_each_entry(&names, &iter, n,
entry /* member name */) {
n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
c = lookup_commit_reference_gently(the_repository,
&n->peeled, 1);
if (c)
@ -376,25 +374,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (!(c->object.flags & t->flag_within))
t->depth++;
}
/* Stop if last remaining path already covered by best candidate(s) */
if (annotated_cnt && !list) {
int best_depth = INT_MAX;
unsigned best_within = 0;
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match];
if (t->depth < best_depth) {
best_depth = t->depth;
best_within = t->flag_within;
} else if (t->depth == best_depth) {
best_within |= t->flag_within;
}
}
if ((c->object.flags & best_within) == best_within) {
if (debug)
fprintf(stderr, _("finished search at %s\n"),
oid_to_hex(&c->object.oid));
break;
}
if (debug)
fprintf(stderr, _("finished search at %s\n"),
oid_to_hex(&c->object.oid));
break;
}
while (parents) {
struct commit *p = parents->item;

View file

@ -125,15 +125,12 @@ struct working_tree_entry {
};
static int working_tree_entry_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *entry,
const void *entry_or_key,
const void *unused_keydata)
{
const struct working_tree_entry *a, *b;
a = container_of(eptr, const struct working_tree_entry, entry);
b = container_of(entry_or_key, const struct working_tree_entry, entry);
const struct working_tree_entry *a = entry;
const struct working_tree_entry *b = entry_or_key;
return strcmp(a->path, b->path);
}
@ -148,14 +145,12 @@ struct pair_entry {
};
static int pair_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *entry,
const void *entry_or_key,
const void *unused_keydata)
{
const struct pair_entry *a, *b;
a = container_of(eptr, const struct pair_entry, entry);
b = container_of(entry_or_key, const struct pair_entry, entry);
const struct pair_entry *a = entry;
const struct pair_entry *b = entry_or_key;
return strcmp(a->path, b->path);
}
@ -166,14 +161,14 @@ static void add_left_or_right(struct hashmap *map, const char *path,
struct pair_entry *e, *existing;
FLEX_ALLOC_STR(e, path, path);
hashmap_entry_init(&e->entry, strhash(path));
existing = hashmap_get_entry(map, e, entry, NULL);
hashmap_entry_init(e, strhash(path));
existing = hashmap_get(map, e, NULL);
if (existing) {
free(e);
e = existing;
} else {
e->left[0] = e->right[0] = '\0';
hashmap_add(map, &e->entry);
hashmap_add(map, e);
}
strlcpy(is_right ? e->right : e->left, content, PATH_MAX);
}
@ -184,14 +179,12 @@ struct path_entry {
};
static int path_entry_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *entry,
const void *entry_or_key,
const void *key)
{
const struct path_entry *a, *b;
a = container_of(eptr, const struct path_entry, entry);
b = container_of(entry_or_key, const struct path_entry, entry);
const struct path_entry *a = entry;
const struct path_entry *b = entry_or_key;
return strcmp(a->path, key ? key : b->path);
}
@ -241,8 +234,8 @@ static void changed_files(struct hashmap *result, const char *index_path,
while (!strbuf_getline_nul(&buf, fp)) {
struct path_entry *entry;
FLEX_ALLOC_STR(entry, path, buf.buf);
hashmap_entry_init(&entry->entry, strhash(buf.buf));
hashmap_add(result, &entry->entry);
hashmap_entry_init(entry, strhash(buf.buf));
hashmap_add(result, entry);
}
fclose(fp);
if (finish_command(&diff_files))
@ -468,13 +461,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
/* Avoid duplicate working_tree entries */
FLEX_ALLOC_STR(entry, path, dst_path);
hashmap_entry_init(&entry->entry, strhash(dst_path));
if (hashmap_get(&working_tree_dups, &entry->entry,
NULL)) {
hashmap_entry_init(entry, strhash(dst_path));
if (hashmap_get(&working_tree_dups, entry, NULL)) {
free(entry);
continue;
}
hashmap_add(&working_tree_dups, &entry->entry);
hashmap_add(&working_tree_dups, entry);
if (!use_wt_file(workdir, dst_path, &roid)) {
if (checkout_path(rmode, &roid, dst_path,
@ -538,8 +530,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* temporary file to both the left and right directories to show the
* change in the recorded SHA1 for the submodule.
*/
hashmap_for_each_entry(&submodules, &iter, entry,
entry /* member name */) {
hashmap_iter_init(&submodules, &iter);
while ((entry = hashmap_iter_next(&iter))) {
if (*entry->left) {
add_path(&ldir, ldir_len, entry->path);
ensure_leading_directories(ldir.buf);
@ -557,8 +549,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* shows only the link itself, not the contents of the link target.
* This loop replicates that behavior.
*/
hashmap_for_each_entry(&symlinks2, &iter, entry,
entry /* member name */) {
hashmap_iter_init(&symlinks2, &iter);
while ((entry = hashmap_iter_next(&iter))) {
if (*entry->left) {
add_path(&ldir, ldir_len, entry->path);
ensure_leading_directories(ldir.buf);

View file

@ -40,7 +40,6 @@ static int no_data;
static int full_tree;
static int reference_excluded_commits;
static int show_original_ids;
static int mark_tags;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
@ -127,15 +126,10 @@ struct anonymized_entry {
};
static int anonymized_entry_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *va, const void *vb,
const void *unused_keydata)
{
const struct anonymized_entry *a, *b;
a = container_of(eptr, const struct anonymized_entry, hash);
b = container_of(entry_or_key, const struct anonymized_entry, hash);
const struct anonymized_entry *a = va, *b = vb;
return a->orig_len != b->orig_len ||
memcmp(a->orig, b->orig, a->orig_len);
}
@ -154,10 +148,10 @@ static const void *anonymize_mem(struct hashmap *map,
if (!map->cmpfn)
hashmap_init(map, anonymized_entry_cmp, NULL, 0);
hashmap_entry_init(&key.hash, memhash(orig, *len));
hashmap_entry_init(&key, memhash(orig, *len));
key.orig = orig;
key.orig_len = *len;
ret = hashmap_get_entry(map, &key, hash, NULL);
ret = hashmap_get(map, &key, NULL);
if (!ret) {
ret = xmalloc(sizeof(*ret));
@ -166,7 +160,7 @@ static const void *anonymize_mem(struct hashmap *map,
ret->orig_len = *len;
ret->anon = generate(orig, len);
ret->anon_len = *len;
hashmap_put(map, &ret->hash);
hashmap_put(map, ret);
}
*len = ret->anon_len;
@ -293,8 +287,7 @@ static void export_blob(const struct object_id *oid)
buf = read_object_file(oid, &type, &size);
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
type_name(type)) < 0)
if (check_object_signature(oid, buf, size, type_name(type)) < 0)
die("oid mismatch in blob %s", oid_to_hex(oid));
object = parse_object_buffer(the_repository, oid, type,
size, buf, &eaten);
@ -849,39 +842,25 @@ static void handle_tag(const char *name, struct tag *tag)
free(buf);
return;
case REWRITE:
if (tagged->type == OBJ_TAG && !mark_tags) {
die(_("Error: Cannot export nested tags unless --mark-tags is specified."));
} else if (tagged->type == OBJ_COMMIT) {
p = rewrite_commit((struct commit *)tagged);
if (!p) {
printf("reset %s\nfrom %s\n\n",
name, oid_to_hex(&null_oid));
free(buf);
return;
}
tagged_mark = get_object_mark(&p->object);
} else {
/* tagged->type is either OBJ_BLOB or OBJ_TAG */
tagged_mark = get_object_mark(tagged);
if (tagged->type != OBJ_COMMIT) {
die("tag %s tags unexported %s!",
oid_to_hex(&tag->object.oid),
type_name(tagged->type));
}
p = rewrite_commit((struct commit *)tagged);
if (!p) {
printf("reset %s\nfrom %s\n\n",
name, oid_to_hex(&null_oid));
free(buf);
return;
}
tagged_mark = get_object_mark(&p->object);
}
}
if (tagged->type == OBJ_TAG) {
printf("reset %s\nfrom %s\n\n",
name, oid_to_hex(&null_oid));
}
skip_prefix(name, "refs/tags/", &name);
printf("tag %s\n", name);
if (mark_tags) {
mark_next_object(&tag->object);
printf("mark :%"PRIu32"\n", last_idnum);
}
if (tagged_mark)
printf("from :%d\n", tagged_mark);
else
printf("from %s\n", oid_to_hex(&tagged->oid));
if (starts_with(name, "refs/tags/"))
name += 10;
printf("tag %s\nfrom :%d\n", name, tagged_mark);
if (show_original_ids)
printf("original-oid %s\n", oid_to_hex(&tag->object.oid));
printf("%.*s%sdata %d\n%.*s\n",
@ -1068,16 +1047,11 @@ static void export_marks(char *file)
error("Unable to write marks file %s.", file);
}
static void import_marks(char *input_file, int check_exists)
static void import_marks(char *input_file)
{
char line[512];
FILE *f;
struct stat sb;
FILE *f = xfopen(input_file, "r");
if (check_exists && stat(input_file, &sb))
return;
f = xfopen(input_file, "r");
while (fgets(line, sizeof(line), f)) {
uint32_t mark;
char *line_end, *mark_end;
@ -1141,9 +1115,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
struct rev_info revs;
struct object_array commits = OBJECT_ARRAY_INIT;
struct commit *commit;
char *export_filename = NULL,
*import_filename = NULL,
*import_filename_if_exists = NULL;
char *export_filename = NULL, *import_filename = NULL;
uint32_t lastimportid;
struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP;
@ -1163,10 +1135,6 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
N_("Dump marks to this file")),
OPT_STRING(0, "import-marks", &import_filename, N_("file"),
N_("Import marks from this file")),
OPT_STRING(0, "import-marks-if-exists",
&import_filename_if_exists,
N_("file"),
N_("Import marks from this file if it exists")),
OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
N_("Fake a tagger when tags lack one")),
OPT_BOOL(0, "full-tree", &full_tree,
@ -1181,8 +1149,6 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
&reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
OPT_BOOL(0, "show-original-ids", &show_original_ids,
N_("Show original object ids of blobs/commits")),
OPT_BOOL(0, "mark-tags", &mark_tags,
N_("Label tags with mark ids")),
OPT_END()
};
@ -1216,12 +1182,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (use_done_feature)
printf("feature done\n");
if (import_filename && import_filename_if_exists)
die(_("Cannot pass both --import-marks and --import-marks-if-exists"));
if (import_filename)
import_marks(import_filename, 0);
else if (import_filename_if_exists)
import_marks(import_filename_if_exists, 1);
import_marks(import_filename);
lastimportid = last_idnum;
if (import_filename && revs.prune_data.nr)

View file

@ -7,7 +7,6 @@
#include "refs.h"
#include "refspec.h"
#include "object-store.h"
#include "oidset.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
@ -24,9 +23,6 @@
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@ -54,13 +50,11 @@ static int fetch_prune_tags_config = -1; /* unspecified */
static int prune_tags = -1; /* unspecified */
#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
static int all, append, dry_run, force, keep, multiple, update_head_ok;
static int verbosity, deepen_relative, set_upstream;
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
static int progress = -1;
static int enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
static int max_jobs = -1, submodule_fetch_jobs_config = -1;
static int fetch_parallel_config = 1;
static int max_children = 1;
static enum transport_family family;
static const char *depth;
static const char *deepen_since;
@ -77,7 +71,6 @@ static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int fetch_write_commit_graph = -1;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@ -103,20 +96,13 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "submodule.fetchjobs")) {
submodule_fetch_jobs_config = parse_submodule_fetchjobs(k, v);
max_children = parse_submodule_fetchjobs(k, v);
return 0;
} else if (!strcmp(k, "fetch.recursesubmodules")) {
recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
return 0;
}
if (!strcmp(k, "fetch.parallel")) {
fetch_parallel_config = git_config_int(k, v);
if (fetch_parallel_config < 0)
die(_("fetch.parallel cannot be negative"));
return 0;
}
return git_default_config(k, v, cb);
}
@ -137,8 +123,6 @@ static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "all", &all,
N_("fetch from all remotes")),
OPT_BOOL(0, "set-upstream", &set_upstream,
N_("set upstream for git pull/fetch")),
OPT_BOOL('a', "append", &append,
N_("append to .git/FETCH_HEAD instead of overwriting")),
OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
@ -150,7 +134,7 @@ static struct option builtin_fetch_options[] = {
N_("fetch all tags and associated objects"), TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
OPT_INTEGER('j', "jobs", &max_jobs,
OPT_INTEGER('j', "jobs", &max_children,
N_("number of submodules fetched in parallel")),
OPT_BOOL('p', "prune", &prune,
N_("prune remote-tracking branches no longer on remote")),
@ -199,8 +183,6 @@ static struct option builtin_fetch_options[] = {
N_("run 'gc --auto' after fetching")),
OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
N_("check for forced-updates on all updated branches")),
OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
N_("write the commit-graph after fetching")),
OPT_END()
};
@ -257,31 +239,32 @@ static void add_merge_config(struct ref **head,
}
}
static void create_fetch_oidset(struct ref **head, struct oidset *out)
static int will_fetch(struct ref **head, const unsigned char *sha1)
{
struct ref *rm = *head;
while (rm) {
oidset_insert(out, &rm->old_oid);
if (hasheq(rm->old_oid.hash, sha1))
return 1;
rm = rm->next;
}
return 0;
}
struct refname_hash_entry {
struct hashmap_entry ent;
struct hashmap_entry ent; /* must be the first member */
struct object_id oid;
int ignore;
char refname[FLEX_ARRAY];
};
static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *e1_,
const void *e2_,
const void *keydata)
{
const struct refname_hash_entry *e1, *e2;
const struct refname_hash_entry *e1 = e1_;
const struct refname_hash_entry *e2 = e2_;
e1 = container_of(eptr, const struct refname_hash_entry, ent);
e2 = container_of(entry_or_key, const struct refname_hash_entry, ent);
return strcmp(e1->refname, keydata ? keydata : e2->refname);
}
@ -293,9 +276,9 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
size_t len = strlen(refname);
FLEX_ALLOC_MEM(ent, refname, refname, len);
hashmap_entry_init(&ent->ent, strhash(refname));
hashmap_entry_init(ent, strhash(refname));
oidcpy(&ent->oid, oid);
hashmap_add(map, &ent->ent);
hashmap_add(map, ent);
return ent;
}
@ -330,16 +313,13 @@ static void find_non_local_tags(const struct ref *refs,
{
struct hashmap existing_refs;
struct hashmap remote_refs;
struct oidset fetch_oids = OIDSET_INIT;
struct string_list remote_refs_list = STRING_LIST_INIT_NODUP;
struct string_list_item *remote_ref_item;
const struct ref *ref;
struct refname_hash_entry *item = NULL;
const int quick_flags = OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT;
refname_hash_init(&existing_refs);
refname_hash_init(&remote_refs);
create_fetch_oidset(head, &fetch_oids);
for_each_ref(add_one_refname, &existing_refs);
for (ref = refs; ref; ref = ref->next) {
@ -354,10 +334,11 @@ static void find_non_local_tags(const struct ref *refs,
*/
if (ends_with(ref->name, "^{}")) {
if (item &&
!has_object_file_with_flags(&ref->old_oid, quick_flags) &&
!oidset_contains(&fetch_oids, &ref->old_oid) &&
!has_object_file_with_flags(&item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
!has_object_file_with_flags(&ref->old_oid,
OBJECT_INFO_QUICK) &&
!will_fetch(head, ref->old_oid.hash) &&
!has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
!will_fetch(head, item->oid.hash))
clear_item(item);
item = NULL;
continue;
@ -370,8 +351,8 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
!has_object_file_with_flags(&item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
!has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
!will_fetch(head, item->oid.hash))
clear_item(item);
item = NULL;
@ -384,15 +365,15 @@ static void find_non_local_tags(const struct ref *refs,
item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);
string_list_insert(&remote_refs_list, ref->name);
}
hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
hashmap_free(&existing_refs, 1);
/*
* We may have a final lightweight tag that needs to be
* checked to see if it needs fetching.
*/
if (item &&
!has_object_file_with_flags(&item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
!has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
!will_fetch(head, item->oid.hash))
clear_item(item);
/*
@ -402,10 +383,8 @@ static void find_non_local_tags(const struct ref *refs,
for_each_string_list_item(remote_ref_item, &remote_refs_list) {
const char *refname = remote_ref_item->string;
struct ref *rm;
unsigned int hash = strhash(refname);
item = hashmap_get_entry_from_hash(&remote_refs, hash, refname,
struct refname_hash_entry, ent);
item = hashmap_get_from_hash(&remote_refs, strhash(refname), refname);
if (!item)
BUG("unseen remote ref?");
@ -419,9 +398,8 @@ static void find_non_local_tags(const struct ref *refs,
**tail = rm;
*tail = &rm->next;
}
hashmap_free_entries(&remote_refs, struct refname_hash_entry, ent);
hashmap_free(&remote_refs, 1);
string_list_clear(&remote_refs_list, 0);
oidset_clear(&fetch_oids);
}
static struct ref *get_ref_map(struct remote *remote,
@ -538,18 +516,17 @@ static struct ref *get_ref_map(struct remote *remote,
if (rm->peer_ref) {
const char *refname = rm->peer_ref->name;
struct refname_hash_entry *peer_item;
unsigned int hash = strhash(refname);
peer_item = hashmap_get_entry_from_hash(&existing_refs,
hash, refname,
struct refname_hash_entry, ent);
peer_item = hashmap_get_from_hash(&existing_refs,
strhash(refname),
refname);
if (peer_item) {
struct object_id *old_oid = &peer_item->oid;
oidcpy(&rm->peer_ref->old_oid, old_oid);
}
}
}
hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
hashmap_free(&existing_refs, 1);
return ref_map;
}
@ -906,17 +883,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
url = xstrdup("foreign");
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
if (filter_options.choice)
/*
* Since a filter is specified, objects indirectly
* referenced by refs are allowed to be absent.
*/
opt.check_refs_are_promisor_objects_only = 1;
rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
if (check_connected(iterate_ref_map, &rm, NULL)) {
rc = error(_("%s did not send all necessary objects\n"), url);
goto abort;
}
@ -966,12 +934,18 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
kind = "";
what = "";
}
else if (skip_prefix(rm->name, "refs/heads/", &what))
else if (starts_with(rm->name, "refs/heads/")) {
kind = "branch";
else if (skip_prefix(rm->name, "refs/tags/", &what))
what = rm->name + 11;
}
else if (starts_with(rm->name, "refs/tags/")) {
kind = "tag";
else if (skip_prefix(rm->name, "refs/remotes/", &what))
what = rm->name + 10;
}
else if (starts_with(rm->name, "refs/remotes/")) {
kind = "remote-tracking branch";
what = rm->name + 13;
}
else {
kind = "";
what = rm->name;
@ -1080,8 +1054,7 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist.
*/
for (r = rm; r; r = r->next) {
if (!has_object_file_with_flags(&r->old_oid,
OBJECT_INFO_SKIP_FETCH_OBJECT))
if (!has_object_file(&r->old_oid))
return -1;
}
@ -1092,11 +1065,8 @@ static int check_exist_and_connected(struct ref *ref_map)
static int fetch_refs(struct transport *transport, struct ref *ref_map)
{
int ret = check_exist_and_connected(ref_map);
if (ret) {
trace2_region_enter("fetch", "fetch_refs", the_repository);
if (ret)
ret = transport_fetch_refs(transport, ref_map);
trace2_region_leave("fetch", "fetch_refs", the_repository);
}
if (!ret)
/*
* Keep the new pack's ".keep" file around to allow the caller
@ -1112,14 +1082,11 @@ static int consume_refs(struct transport *transport, struct ref *ref_map)
{
int connectivity_checked = transport->smart_options
? transport->smart_options->connectivity_checked : 0;
int ret;
trace2_region_enter("fetch", "consume_refs", the_repository);
ret = store_updated_refs(transport->url,
transport->remote->name,
connectivity_checked,
ref_map);
int ret = store_updated_refs(transport->url,
transport->remote->name,
connectivity_checked,
ref_map);
transport_unlock_pack(transport);
trace2_region_leave("fetch", "consume_refs", the_repository);
return ret;
}
@ -1271,10 +1238,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
if (update_shallow)
set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
if (filter_options.choice) {
const char *spec =
expand_list_objects_filter_spec(&filter_options);
set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER, spec);
struct strbuf expanded_filter_spec = STRBUF_INIT;
expand_list_objects_filter_spec(&filter_options,
&expanded_filter_spec);
set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
expanded_filter_spec.buf);
set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
strbuf_release(&expanded_filter_spec);
}
if (negotiation_tip.nr) {
if (transport->smart_options)
@ -1364,11 +1334,9 @@ static int do_fetch(struct transport *transport,
argv_array_push(&ref_prefixes, "refs/tags/");
}
if (must_list_refs) {
trace2_region_enter("fetch", "remote_refs", the_repository);
if (must_list_refs)
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
trace2_region_leave("fetch", "remote_refs", the_repository);
} else
else
remote_refs = NULL;
argv_array_clear(&ref_prefixes);
@ -1399,51 +1367,6 @@ static int do_fetch(struct transport *transport,
retcode = 1;
goto cleanup;
}
if (set_upstream) {
struct branch *branch = branch_get("HEAD");
struct ref *rm;
struct ref *source_ref = NULL;
/*
* We're setting the upstream configuration for the
* current branch. The relevant upstream is the
* fetched branch that is meant to be merged with the
* current one, i.e. the one fetched to FETCH_HEAD.
*
* When there are several such branches, consider the
* request ambiguous and err on the safe side by doing
* nothing and just emit a warning.
*/
for (rm = ref_map; rm; rm = rm->next) {
if (!rm->peer_ref) {
if (source_ref) {
warning(_("multiple branches detected, incompatible with --set-upstream"));
goto skip;
} else {
source_ref = rm;
}
}
}
if (source_ref) {
if (!strcmp(source_ref->name, "HEAD") ||
starts_with(source_ref->name, "refs/heads/"))
install_branch_config(0,
branch->name,
transport->remote->name,
source_ref->name);
else if (starts_with(source_ref->name, "refs/remotes/"))
warning(_("not setting upstream for a remote remote-tracking branch"));
else if (starts_with(source_ref->name, "refs/tags/"))
warning(_("not setting upstream for a remote tag"));
else
warning(_("unknown branch type"));
} else {
warning(_("no source branch found.\n"
"you need to specify exactly one branch with the --set-upstream option."));
}
}
skip:
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@ -1540,62 +1463,7 @@ static void add_options_to_argv(struct argv_array *argv)
}
/* Fetch multiple remotes in parallel */
struct parallel_fetch_state {
const char **argv;
struct string_list *remotes;
int next, result;
};
static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
void *cb, void **task_cb)
{
struct parallel_fetch_state *state = cb;
char *remote;
if (state->next < 0 || state->next >= state->remotes->nr)
return 0;
remote = state->remotes->items[state->next++].string;
*task_cb = remote;
argv_array_pushv(&cp->args, state->argv);
argv_array_push(&cp->args, remote);
cp->git_cmd = 1;
if (verbosity >= 0)
printf(_("Fetching %s\n"), remote);
return 1;
}
static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
{
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
state->result = error(_("Could not fetch %s"), remote);
return 0;
}
static int fetch_finished(int result, struct strbuf *out,
void *cb, void *task_cb)
{
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
if (result) {
strbuf_addf(out, _("could not fetch '%s' (exit code: %d)\n"),
remote, result);
state->result = -1;
}
return 0;
}
static int fetch_multiple(struct string_list *list, int max_children)
static int fetch_multiple(struct string_list *list)
{
int i, result = 0;
struct argv_array argv = ARGV_ARRAY_INIT;
@ -1606,38 +1474,23 @@ static int fetch_multiple(struct string_list *list, int max_children)
return errcode;
}
argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc", NULL);
add_options_to_argv(&argv);
if (max_children != 1 && list->nr != 1) {
struct parallel_fetch_state state = { argv.argv, list, 0, 0 };
argv_array_push(&argv, "--end-of-options");
result = run_processes_parallel_tr2(max_children,
&fetch_next_remote,
&fetch_failed_to_start,
&fetch_finished,
&state,
"fetch", "parallel/fetch");
if (!result)
result = state.result;
} else
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
argv_array_push(&argv, name);
if (verbosity >= 0)
printf(_("Fetching %s\n"), name);
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
error(_("Could not fetch %s"), name);
result = 1;
}
argv_array_pop(&argv);
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
argv_array_push(&argv, name);
if (verbosity >= 0)
printf(_("Fetching %s\n"), name);
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
error(_("Could not fetch %s"), name);
result = 1;
}
argv_array_pop(&argv);
}
argv_array_clear(&argv);
return !!result;
return result;
}
/*
@ -1657,27 +1510,37 @@ static inline void fetch_one_setup_partial(struct remote *remote)
* If no prior partial clone/fetch and the current fetch DID NOT
* request a partial-fetch, do a normal fetch.
*/
if (!has_promisor_remote() && !filter_options.choice)
if (!repository_format_partial_clone && !filter_options.choice)
return;
/*
* If this is a partial-fetch request, we enable partial on
* this repo if not already enabled and remember the given
* filter-spec as the default for subsequent fetches to this
* remote.
* If this is the FIRST partial-fetch request, we enable partial
* on this repo and remember the given filter-spec as the default
* for subsequent fetches to this remote.
*/
if (filter_options.choice) {
if (!repository_format_partial_clone && filter_options.choice) {
partial_clone_register(remote->name, &filter_options);
return;
}
/*
* We are currently limited to only ONE promisor remote and only
* allow partial-fetches from the promisor remote.
*/
if (strcmp(remote->name, repository_format_partial_clone)) {
if (filter_options.choice)
die(_("--filter can only be used with the remote "
"configured in extensions.partialClone"));
return;
}
/*
* Do a partial-fetch from the promisor remote using either the
* explicitly given filter-spec or inherit the filter-spec from
* the config.
*/
if (!filter_options.choice)
partial_clone_get_default_filter_spec(&filter_options, remote->name);
partial_clone_get_default_filter_spec(&filter_options);
return;
}
@ -1763,13 +1626,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
packet_trace_identity("fetch");
fetch_if_missing = 0;
/* Record the command line for the reflog */
strbuf_addstr(&default_rla, "fetch");
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
&recurse_submodules);
fetch_config_from_gitmodules(&max_children, &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
@ -1797,7 +1661,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (depth || deepen_since || deepen_not.nr)
deepen = 1;
if (filter_options.choice && !has_promisor_remote())
if (filter_options.choice && !repository_format_partial_clone)
die("--filter can only be used when extensions.partialClone is set");
if (all) {
@ -1831,31 +1695,19 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
if (remote) {
if (filter_options.choice || has_promisor_remote())
if (filter_options.choice || repository_format_partial_clone)
fetch_one_setup_partial(remote);
result = fetch_one(remote, argc, argv, prune_tags_ok);
} else {
int max_children = max_jobs;
if (filter_options.choice)
die(_("--filter can only be used with the remote "
"configured in extensions.partialclone"));
if (max_children < 0)
max_children = fetch_parallel_config;
/* TODO should this also die if we have a previous partial-clone? */
result = fetch_multiple(&list, max_children);
result = fetch_multiple(&list);
}
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
struct argv_array options = ARGV_ARRAY_INIT;
int max_children = max_jobs;
if (max_children < 0)
max_children = submodule_fetch_jobs_config;
if (max_children < 0)
max_children = fetch_parallel_config;
add_options_to_argv(&options);
result = fetch_populated_submodules(the_repository,
@ -1870,20 +1722,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
string_list_clear(&list, 0);
prepare_repo_settings(the_repository);
if (fetch_write_commit_graph > 0 ||
(fetch_write_commit_graph < 0 &&
the_repository->settings.fetch_write_commit_graph)) {
int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
if (progress)
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
write_commit_graph_reachable(the_repository->objects->odb,
commit_graph_flags,
NULL);
}
close_object_store(the_repository->objects);
if (enable_auto_gc) {

View file

@ -106,7 +106,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
int i, len = strlen(line);
struct origin_data *origin_data;
char *src;
const char *origin, *tag_name;
const char *origin;
struct src_data *src_data;
struct string_list_item *item;
int pulling_head = 0;
@ -162,13 +162,14 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (pulling_head) {
origin = src;
src_data->head_status |= 1;
} else if (skip_prefix(line, "branch ", &origin)) {
} else if (starts_with(line, "branch ")) {
origin_data->is_local_branch = 1;
origin = line + 7;
string_list_append(&src_data->branch, origin);
src_data->head_status |= 2;
} else if (skip_prefix(line, "tag ", &tag_name)) {
} else if (starts_with(line, "tag ")) {
origin = line;
string_list_append(&src_data->tag, tag_name);
string_list_append(&src_data->tag, origin + 4);
src_data->head_status |= 2;
} else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
string_list_append(&src_data->r_branch, origin);

View file

@ -50,20 +50,40 @@ static int name_objects;
#define ERROR_REFS 010
#define ERROR_COMMIT_GRAPH 020
static const char *describe_object(const struct object_id *oid)
static const char *describe_object(struct object *obj)
{
return fsck_describe_object(&fsck_walk_options, oid);
static struct strbuf bufs[] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
};
static int b = 0;
struct strbuf *buf;
char *name = NULL;
if (name_objects)
name = lookup_decoration(fsck_walk_options.object_names, obj);
buf = bufs + b;
b = (b + 1) % ARRAY_SIZE(bufs);
strbuf_reset(buf);
strbuf_addstr(buf, oid_to_hex(&obj->oid));
if (name)
strbuf_addf(buf, " (%s)", name);
return buf->buf;
}
static const char *printable_type(const struct object_id *oid,
enum object_type type)
static const char *printable_type(struct object *obj)
{
const char *ret;
if (type == OBJ_NONE)
type = oid_object_info(the_repository, oid, NULL);
if (obj->type == OBJ_NONE) {
enum object_type type = oid_object_info(the_repository,
&obj->oid, NULL);
if (type > 0)
object_as_type(the_repository, obj, type, 0);
}
ret = type_name(type);
ret = type_name(obj->type);
if (!ret)
ret = _("unknown");
@ -98,32 +118,26 @@ static int objerror(struct object *obj, const char *err)
errors_found |= ERROR_OBJECT;
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid), err);
printable_type(obj), describe_object(obj), err);
return -1;
}
static int fsck_error_func(struct fsck_options *o,
const struct object_id *oid,
enum object_type object_type,
int msg_type, const char *message)
struct object *obj, int type, const char *message)
{
switch (msg_type) {
switch (type) {
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("warning in %s %s: %s"),
printable_type(oid, object_type),
describe_object(oid), message);
printable_type(obj), describe_object(obj), message);
return 0;
case FSCK_ERROR:
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(oid, object_type),
describe_object(oid), message);
printable_type(obj), describe_object(obj), message);
return 1;
default:
BUG("%d (FSCK_IGNORE?) should never trigger this callback",
msg_type);
BUG("%d (FSCK_IGNORE?) should never trigger this callback", type);
}
}
@ -141,8 +155,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
if (!obj) {
/* ... these references to parent->fld are safe here */
printf_ln(_("broken link from %7s %s"),
printable_type(&parent->oid, parent->type),
describe_object(&parent->oid));
printable_type(parent), describe_object(parent));
printf_ln(_("broken link from %7s %s"),
(type == OBJ_ANY ? _("unknown") : type_name(type)),
_("unknown"));
@ -170,10 +183,10 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
if (parent && !has_object_file(&obj->oid)) {
printf_ln(_("broken link from %7s %s\n"
" to %7s %s"),
printable_type(&parent->oid, parent->type),
describe_object(&parent->oid),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
printable_type(parent),
describe_object(parent),
printable_type(obj),
describe_object(obj));
errors_found |= ERROR_REACHABLE;
}
return 1;
@ -279,9 +292,8 @@ static void check_reachable_object(struct object *obj)
return;
if (has_object_pack(&obj->oid))
return; /* it is in pack - forget about it */
printf_ln(_("missing %s %s"),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
printf_ln(_("missing %s %s"), printable_type(obj),
describe_object(obj));
errors_found |= ERROR_REACHABLE;
return;
}
@ -306,9 +318,8 @@ static void check_unreachable_object(struct object *obj)
* since this is something that is prunable.
*/
if (show_unreachable) {
printf_ln(_("unreachable %s %s"),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
printf_ln(_("unreachable %s %s"), printable_type(obj),
describe_object(obj));
return;
}
@ -326,13 +337,12 @@ static void check_unreachable_object(struct object *obj)
*/
if (!(obj->flags & USED)) {
if (show_dangling)
printf_ln(_("dangling %s %s"),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
printf_ln(_("dangling %s %s"), printable_type(obj),
describe_object(obj));
if (write_lost_and_found) {
char *filename = git_pathdup("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
describe_object(&obj->oid));
describe_object(obj));
FILE *f;
if (safe_create_leading_directories_const(filename)) {
@ -345,7 +355,7 @@ static void check_unreachable_object(struct object *obj)
if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
die_errno(_("could not write '%s'"), filename);
} else
fprintf(f, "%s\n", describe_object(&obj->oid));
fprintf(f, "%s\n", describe_object(obj));
if (fclose(f))
die_errno(_("could not finish '%s'"),
filename);
@ -364,7 +374,7 @@ static void check_unreachable_object(struct object *obj)
static void check_object(struct object *obj)
{
if (verbose)
fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
fprintf_ln(stderr, _("Checking %s"), describe_object(obj));
if (obj->flags & REACHABLE)
check_reachable_object(obj);
@ -422,8 +432,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (verbose)
fprintf_ln(stderr, _("Checking %s %s"),
printable_type(&obj->oid, obj->type),
describe_object(&obj->oid));
printable_type(obj), describe_object(obj));
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, _("broken links"));
@ -436,7 +445,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (!commit->parents && show_root)
printf_ln(_("root %s"),
describe_object(&commit->object.oid));
describe_object(&commit->object));
}
if (obj->type == OBJ_TAG) {
@ -444,10 +453,10 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (show_tags && tag->tagged) {
printf_ln(_("tagged %s %s (%s) in %s"),
printable_type(&tag->tagged->oid, tag->tagged->type),
describe_object(&tag->tagged->oid),
printable_type(tag->tagged),
describe_object(tag->tagged),
tag->tag,
describe_object(&tag->object.oid));
describe_object(&tag->object));
}
}
@ -490,10 +499,10 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
if (!is_null_oid(oid)) {
obj = lookup_object(the_repository, oid);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp)
fsck_put_object_name(&fsck_walk_options, oid,
"%s@{%"PRItime"}",
refname, timestamp);
if (timestamp && name_objects)
add_decoration(fsck_walk_options.object_names,
obj,
xstrfmt("%s@{%"PRItime"}", refname, timestamp));
obj->flags |= USED;
mark_object_reachable(obj);
} else if (!is_promisor_object(oid)) {
@ -557,8 +566,9 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
}
default_refs++;
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options,
oid, "%s", refname);
if (name_objects)
add_decoration(fsck_walk_options.object_names,
obj, xstrdup(refname));
mark_object_reachable(obj);
return 0;
@ -732,7 +742,9 @@ static int fsck_cache_tree(struct cache_tree *it)
return 1;
}
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
if (name_objects)
add_decoration(fsck_walk_options.object_names,
obj, xstrdup(":"));
mark_object_reachable(obj);
if (obj->type != OBJ_TREE)
err |= objerror(obj, _("non-tree in cache-tree"));
@ -818,7 +830,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (name_objects)
fsck_enable_object_names(&fsck_walk_options);
fsck_walk_options.object_names =
xcalloc(1, sizeof(struct decoration));
git_config(fsck_config, NULL);
@ -877,8 +890,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options, &oid,
"%s", arg);
if (name_objects)
add_decoration(fsck_walk_options.object_names,
obj, xstrdup(arg));
mark_object_reachable(obj);
continue;
}
@ -914,8 +928,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
continue;
obj = &blob->object;
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options, &obj->oid,
":%s", active_cache[i]->name);
if (name_objects)
add_decoration(fsck_walk_options.object_names,
obj,
xstrfmt(":%s", active_cache[i]->name));
mark_object_reachable(obj);
}
if (active_cache_tree)

View file

@ -27,7 +27,6 @@
#include "pack-objects.h"
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
#define FAILED_RUN "failed to run %s"
@ -42,6 +41,7 @@ static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
static int gc_write_commit_graph;
static int detach_auto = 1;
static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
@ -148,6 +148,7 @@ static void gc_config(void)
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
@ -458,7 +459,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
/*
* Returns 0 if there was no previous error and gc can proceed, 1 if
* gc should not proceed due to an error in the last run. Prints a
* message and returns -1 if an error occurred while reading gc.log
* message and returns -1 if an error occured while reading gc.log
*/
static int report_last_gc_error(void)
{
@ -601,7 +602,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (detach_auto) {
int ret = report_last_gc_error();
if (ret < 0)
/* an I/O error occurred, already reported */
/* an I/O error occured, already reported */
exit(128);
if (ret == 1)
/* Last gc --auto failed. Skip this one. */
@ -660,7 +661,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
argv_array_push(&prune, prune_expire);
if (quiet)
argv_array_push(&prune, "--no-progress");
if (has_promisor_remote())
if (repository_format_partial_clone)
argv_array_push(&prune,
"--exclude-promisor-objects");
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
@ -684,11 +685,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
clean_pack_garbage();
}
prepare_repo_settings(the_repository);
if (the_repository->settings.gc_write_commit_graph == 1)
write_commit_graph_reachable(the_repository->objects->odb,
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL);
if (gc_write_commit_graph &&
write_commit_graph_reachable(get_object_directory(),
!quiet && !daemonized ? COMMIT_GRAPH_PROGRESS : 0,
NULL))
return 1;
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "

View file

@ -24,7 +24,6 @@
#include "submodule.h"
#include "submodule-config.h"
#include "object-store.h"
#include "packfile.h"
static char const * const grep_usage[] = {
N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
@ -33,6 +32,7 @@ static char const * const grep_usage[] = {
static int recurse_submodules;
#define GREP_NUM_THREADS_DEFAULT 8
static int num_threads;
static pthread_t *threads;
@ -91,11 +91,8 @@ static pthread_cond_t cond_result;
static int skip_first_line;
static void add_work(struct grep_opt *opt, struct grep_source *gs)
static void add_work(struct grep_opt *opt, const struct grep_source *gs)
{
if (opt->binary != GREP_BINARY_TEXT)
grep_source_load_driver(gs, opt->repo->index);
grep_lock();
while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
@ -103,6 +100,9 @@ static void add_work(struct grep_opt *opt, struct grep_source *gs)
}
todo[todo_end].source = *gs;
if (opt->binary != GREP_BINARY_TEXT)
grep_source_load_driver(&todo[todo_end].source,
opt->repo->index);
todo[todo_end].done = 0;
strbuf_reset(&todo[todo_end].out);
todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
@ -200,12 +200,12 @@ static void start_threads(struct grep_opt *opt)
int i;
pthread_mutex_init(&grep_mutex, NULL);
pthread_mutex_init(&grep_read_mutex, NULL);
pthread_mutex_init(&grep_attr_mutex, NULL);
pthread_cond_init(&cond_add, NULL);
pthread_cond_init(&cond_write, NULL);
pthread_cond_init(&cond_result, NULL);
grep_use_locks = 1;
enable_obj_read_lock();
for (i = 0; i < ARRAY_SIZE(todo); i++) {
strbuf_init(&todo[i].out, 0);
@ -257,12 +257,12 @@ static int wait_all(void)
free(threads);
pthread_mutex_destroy(&grep_mutex);
pthread_mutex_destroy(&grep_read_mutex);
pthread_mutex_destroy(&grep_attr_mutex);
pthread_cond_destroy(&cond_add);
pthread_cond_destroy(&cond_write);
pthread_cond_destroy(&cond_result);
grep_use_locks = 0;
disable_obj_read_lock();
return hit;
}
@ -295,6 +295,16 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)
return st;
}
static void *lock_and_read_oid_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
{
void *data;
grep_read_lock();
data = read_object_file(oid, type, size);
grep_read_unlock();
return data;
}
static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
const char *filename, int tree_name_len,
const char *path)
@ -393,32 +403,34 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
static int grep_submodule(struct grep_opt *opt,
const struct pathspec *pathspec,
const struct object_id *oid,
const char *filename, const char *path, int cached)
const char *filename, const char *path)
{
struct repository subrepo;
struct repository *superproject = opt->repo;
const struct submodule *sub;
const struct submodule *sub = submodule_from_path(superproject,
&null_oid, path);
struct grep_opt subopt;
int hit;
sub = submodule_from_path(superproject, &null_oid, path);
if (!is_submodule_active(superproject, path))
return 0;
if (repo_submodule_init(&subrepo, superproject, sub))
return 0;
/*
* NEEDSWORK: repo_read_gitmodules() might call
* add_to_alternates_memory() via config_from_gitmodules(). This
* operation causes a race condition with concurrent object readings
* performed by the worker threads. That's why we need obj_read_lock()
* here. It should be removed once it's no longer necessary to add the
* subrepo's odbs to the in-memory alternates list.
* NEEDSWORK: submodules functions need to be protected because they
* access the object store via config_from_gitmodules(): the latter
* uses get_oid() which, for now, relies on the global the_repository
* object.
*/
obj_read_lock();
repo_read_gitmodules(&subrepo, 0);
grep_read_lock();
if (!is_submodule_active(superproject, path)) {
grep_read_unlock();
return 0;
}
if (repo_submodule_init(&subrepo, superproject, sub)) {
grep_read_unlock();
return 0;
}
repo_read_gitmodules(&subrepo);
/*
* NEEDSWORK: This adds the submodule's object directory to the list of
@ -431,7 +443,7 @@ static int grep_submodule(struct grep_opt *opt,
* object.
*/
add_to_alternates_memory(subrepo.objects->odb->path);
obj_read_unlock();
grep_read_unlock();
memcpy(&subopt, opt, sizeof(subopt));
subopt.repo = &subrepo;
@ -443,12 +455,14 @@ static int grep_submodule(struct grep_opt *opt,
unsigned long size;
struct strbuf base = STRBUF_INIT;
obj_read_lock();
object = parse_object_or_die(oid, oid_to_hex(oid));
obj_read_unlock();
grep_read_lock();
data = read_object_with_reference(&subrepo,
&object->oid, tree_type,
&size, NULL);
grep_read_unlock();
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&object->oid));
@ -461,7 +475,7 @@ static int grep_submodule(struct grep_opt *opt,
strbuf_release(&base);
free(data);
} else {
hit = grep_cache(&subopt, pathspec, cached);
hit = grep_cache(&subopt, pathspec, 1);
}
repo_clear(&subrepo);
@ -509,8 +523,7 @@ static int grep_cache(struct grep_opt *opt,
}
} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
submodule_path_match(repo->index, pathspec, name.buf, NULL)) {
hit |= grep_submodule(opt, pathspec, NULL, ce->name,
ce->name, cached);
hit |= grep_submodule(opt, pathspec, NULL, ce->name, ce->name);
} else {
continue;
}
@ -573,7 +586,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
data = read_object_file(&entry.oid, &type, &size);
data = lock_and_read_oid_file(&entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid));
@ -585,8 +598,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
free(data);
} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
hit |= grep_submodule(opt, pathspec, &entry.oid,
base->buf, base->buf + tn_len,
1); /* ignored */
base->buf, base->buf + tn_len);
}
strbuf_setlen(base, old_baselen);
@ -611,9 +623,12 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct strbuf base;
int hit, len;
grep_read_lock();
data = read_object_with_reference(opt->repo,
&obj->oid, tree_type,
&size, NULL);
grep_read_unlock();
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
@ -642,18 +657,13 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
for (i = 0; i < nr; i++) {
struct object *real_obj;
obj_read_lock();
real_obj = deref_tag(opt->repo, list->objects[i].item,
NULL, 0);
obj_read_unlock();
/* load the gitmodules file for this rev */
if (recurse_submodules) {
submodule_free(opt->repo);
obj_read_lock();
gitmodules_config_oid(&real_obj->oid);
obj_read_unlock();
}
if (grep_object(opt, pathspec, real_obj, list->objects[i].name,
list->objects[i].path)) {
@ -946,9 +956,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
/* die the same way as if we did it at the beginning */
setup_git_directory();
}
/* Ignore --recurse-submodules if --no-index is given or implied */
if (!use_index)
recurse_submodules = 0;
/*
* skip a -- separator; we know it cannot be
@ -1053,10 +1060,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
pathspec.recursive = 1;
pathspec.recurse_submodules = !!recurse_submodules;
if (recurse_submodules && untracked)
die(_("--untracked not supported with --recurse-submodules"));
if (show_in_pager) {
if (list.nr || cached || show_in_pager) {
if (num_threads > 1)
warning(_("invalid option combination, ignoring --threads"));
num_threads = 1;
@ -1066,7 +1070,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
} else if (num_threads < 0)
die(_("invalid number of threads specified (%d)"), num_threads);
else if (num_threads == 0)
num_threads = HAVE_THREADS ? online_cpus() : 1;
num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1;
if (num_threads > 1) {
if (!HAVE_THREADS)
@ -1075,17 +1079,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
&& (opt.pre_context || opt.post_context ||
opt.file_break || opt.funcbody))
skip_first_line = 1;
/*
* Pre-read gitmodules (if not read already) and force eager
* initialization of packed_git to prevent racy lazy
* reading/initialization once worker threads are started.
*/
if (recurse_submodules)
repo_read_gitmodules(the_repository, 1);
if (startup_info->have_repository)
(void)get_packed_git(the_repository);
start_threads(&opt);
} else {
/*
@ -1115,11 +1108,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf, "+/%s%s",
strcmp("less", pager) ? "" : "*",
opt.pattern_list->pattern);
string_list_append(&path_list,
strbuf_detach(&buf, NULL));
string_list_append(&path_list, buf.buf);
strbuf_detach(&buf, NULL);
}
}
if (recurse_submodules && (!use_index || untracked))
die(_("option not supported with --recurse-submodules"));
if (!show_in_pager && !opt.status_only)
setup_pager();
@ -1149,6 +1145,5 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
run_pager(&opt, prefix);
clear_pathspec(&pathspec);
free_grep_patterns(&opt);
grep_destroy();
return !hit;
}

View file

@ -14,7 +14,7 @@
#include "thread-utils.h"
#include "packfile.h"
#include "object-store.h"
#include "promisor-remote.h"
#include "fetch-object.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@ -757,8 +757,7 @@ static int check_collison(struct object_entry *entry)
memset(&data, 0, sizeof(data));
data.entry = entry;
data.st = open_istream(the_repository, &entry->idx.oid, &type, &size,
NULL);
data.st = open_istream(&entry->idx.oid, &type, &size, NULL);
if (!data.st)
return -1;
if (size != entry->size || type != entry->type)
@ -949,7 +948,7 @@ static void resolve_delta(struct object_entry *delta_obj,
free(delta_data);
if (!result->data)
bad_object(delta_obj->idx.offset, _("failed to apply delta"));
hash_object_file(the_hash_algo, result->data, result->size,
hash_object_file(result->data, result->size,
type_name(delta_obj->real_type), &delta_obj->idx.oid);
sha1_object(result->data, NULL, result->size, delta_obj->real_type,
&delta_obj->idx.oid);
@ -1004,9 +1003,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
base->obj->real_type))
die("REF_DELTA at offset %"PRIuMAX" already resolved (duplicate base %s?)",
(uintmax_t)child->idx.offset,
oid_to_hex(&base->obj->idx.oid));
BUG("child->real_type != OBJ_REF_DELTA");
resolve_delta(child, base, result);
if (base->ref_first == base->ref_last && base->ofs_last == -1)
@ -1355,7 +1352,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
sorted_by_pos[i] = &ref_deltas[i];
QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
if (has_promisor_remote()) {
if (repository_format_partial_clone) {
/*
* Prefetch the delta bases.
*/
@ -1369,8 +1366,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
oid_array_append(&to_fetch, &d->oid);
}
if (to_fetch.nr)
promisor_remote_get_direct(the_repository,
to_fetch.oid, to_fetch.nr);
fetch_objects(repository_format_partial_clone,
to_fetch.oid, to_fetch.nr);
oid_array_clear(&to_fetch);
}
@ -1386,9 +1383,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
if (!base_obj->data)
continue;
if (check_object_signature(the_repository, &d->oid,
base_obj->data, base_obj->size,
type_name(type)))
if (check_object_signature(&d->oid, base_obj->data,
base_obj->size, type_name(type)))
die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
base_obj->obj = append_obj_to_pack(f, d->oid.hash,
base_obj->data, base_obj->size, type);
@ -1494,11 +1490,11 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
}
if (!from_stdin) {
printf("%s\n", hash_to_hex(hash));
printf("%s\n", sha1_to_hex(hash));
} else {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s\t%s\n", report, hash_to_hex(hash));
strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);

View file

@ -37,7 +37,6 @@
#include "range-diff.h"
#define MAIL_DEFAULT_WRAP 72
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@ -208,7 +207,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
rev->show_notes = 1;
if (rev->show_notes)
load_display_notes(&rev->notes_opt);
init_display_notes(&rev->notes_opt);
if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
rev->diffopt.filter || rev->diffopt.flags.follow_renames)
@ -628,7 +627,6 @@ int cmd_show(int argc, const char **argv, const char *prefix)
break;
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
struct object_id *oid = get_tagged_oid(t);
if (rev.shown_one)
putchar('\n');
@ -640,10 +638,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.shown_one = 1;
if (ret)
break;
o = parse_object(the_repository, oid);
o = parse_object(the_repository, &t->tagged->oid);
if (!o)
ret = error(_("could not read object %s"),
oid_to_hex(oid));
oid_to_hex(&t->tagged->oid));
objects[i].item = o;
i--;
break;
@ -766,56 +764,28 @@ static void add_header(const char *value)
item->string[len] = '\0';
}
enum cover_setting {
#define THREAD_SHALLOW 1
#define THREAD_DEEP 2
static int thread;
static int do_signoff;
static int base_auto;
static char *from;
static const char *signature = git_version_string;
static const char *signature_file;
static int config_cover_letter;
static const char *config_output_directory;
enum {
COVER_UNSET,
COVER_OFF,
COVER_ON,
COVER_AUTO
};
enum thread_level {
THREAD_UNSET,
THREAD_SHALLOW,
THREAD_DEEP
};
enum cover_from_description {
COVER_FROM_NONE,
COVER_FROM_MESSAGE,
COVER_FROM_SUBJECT,
COVER_FROM_AUTO
};
static enum thread_level thread;
static int do_signoff;
static int base_auto;
static char *from;
static const char *signature = git_version_string;
static const char *signature_file;
static enum cover_setting config_cover_letter;
static const char *config_output_directory;
static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
static int show_notes;
static struct display_notes_opt notes_opt;
static enum cover_from_description parse_cover_from_description(const char *arg)
{
if (!arg || !strcmp(arg, "default"))
return COVER_FROM_MESSAGE;
else if (!strcmp(arg, "none"))
return COVER_FROM_NONE;
else if (!strcmp(arg, "message"))
return COVER_FROM_MESSAGE;
else if (!strcmp(arg, "subject"))
return COVER_FROM_SUBJECT;
else if (!strcmp(arg, "auto"))
return COVER_FROM_AUTO;
else
die(_("%s: invalid cover from description mode"), arg);
}
static int git_format_config(const char *var, const char *value, void *cb)
{
struct rev_info *rev = cb;
if (!strcmp(var, "format.headers")) {
if (!value)
die(_("format.headers without value"));
@ -865,7 +835,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
thread = THREAD_SHALLOW;
return 0;
}
thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
thread = git_config_bool(var, value) && THREAD_SHALLOW;
return 0;
}
if (!strcmp(var, "format.signoff")) {
@ -902,17 +872,19 @@ static int git_format_config(const char *var, const char *value, void *cb)
return 0;
}
if (!strcmp(var, "format.notes")) {
struct strbuf buf = STRBUF_INIT;
int b = git_parse_maybe_bool(value);
if (b < 0)
enable_ref_display_notes(&notes_opt, &show_notes, value);
else if (b)
enable_default_display_notes(&notes_opt, &show_notes);
else
disable_display_notes(&notes_opt, &show_notes);
return 0;
}
if (!strcmp(var, "format.coverfromdescription")) {
cover_from_description_mode = parse_cover_from_description(value);
if (!b)
return 0;
rev->show_notes = 1;
if (b < 0) {
strbuf_addstr(&buf, value);
expand_notes_ref(&buf);
string_list_append(&rev->notes_opt.extra_notes_refs,
strbuf_detach(&buf, NULL));
} else {
rev->notes_opt.use_default_notes = 1;
}
return 0;
}
@ -1021,6 +993,20 @@ static void print_signature(FILE *file)
putc('\n', file);
}
static void add_branch_description(struct strbuf *buf, const char *branch_name)
{
struct strbuf desc = STRBUF_INIT;
if (!branch_name || !*branch_name)
return;
read_branch_desc(&desc, branch_name);
if (desc.len) {
strbuf_addch(buf, '\n');
strbuf_addbuf(buf, &desc);
strbuf_addch(buf, '\n');
}
strbuf_release(&desc);
}
static char *find_branch_name(struct rev_info *rev)
{
int i, positive = -1;
@ -1067,63 +1053,6 @@ static void show_diffstat(struct rev_info *rev,
fprintf(rev->diffopt.file, "\n");
}
static void prepare_cover_text(struct pretty_print_context *pp,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
int need_8bit_cte)
{
const char *subject = "*** SUBJECT HERE ***";
const char *body = "*** BLURB HERE ***";
struct strbuf description_sb = STRBUF_INIT;
struct strbuf subject_sb = STRBUF_INIT;
if (cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
if (branch_name && *branch_name)
read_branch_desc(&description_sb, branch_name);
if (!description_sb.len)
goto do_pp;
if (cover_from_description_mode == COVER_FROM_SUBJECT ||
cover_from_description_mode == COVER_FROM_AUTO)
body = format_subject(&subject_sb, description_sb.buf, " ");
if (cover_from_description_mode == COVER_FROM_MESSAGE ||
(cover_from_description_mode == COVER_FROM_AUTO &&
subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
body = description_sb.buf;
else
subject = subject_sb.buf;
do_pp:
pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
pp_remainder(pp, &body, sb, 0);
strbuf_release(&description_sb);
strbuf_release(&subject_sb);
}
static int get_notes_refs(struct string_list_item *item, void *arg)
{
argv_array_pushf(arg, "--notes=%s", item->string);
return 0;
}
static void get_notes_args(struct argv_array *arg, struct rev_info *rev)
{
if (!rev->show_notes) {
argv_array_push(arg, "--no-notes");
} else if (rev->notes_opt.use_default_notes > 0 ||
(rev->notes_opt.use_default_notes == -1 &&
!rev->notes_opt.extra_notes_refs.nr)) {
argv_array_push(arg, "--notes");
} else {
for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
}
}
static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct commit *origin,
int nr, struct commit **list,
@ -1131,6 +1060,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
int quiet)
{
const char *committer;
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
const char *msg;
struct shortlog log;
struct strbuf sb = STRBUF_INIT;
int i;
@ -1160,12 +1091,15 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
if (!branch_name)
branch_name = find_branch_name(rev);
msg = body;
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode.type = DATE_RFC2822;
pp.rev = rev;
pp.print_email_subject = 1;
pp_user_info(&pp, NULL, &sb, committer, encoding);
prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
pp_remainder(&pp, &msg, &sb, 0);
add_branch_description(&sb, branch_name);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
strbuf_release(&sb);
@ -1196,16 +1130,13 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
* can be added later if deemed desirable.
*/
struct diff_options opts;
struct argv_array other_arg = ARGV_ARRAY_INIT;
diff_setup(&opts);
opts.file = rev->diffopt.file;
opts.use_color = rev->diffopt.use_color;
diff_setup_done(&opts);
fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
get_notes_args(&other_arg, rev);
show_range_diff(rev->rdiff1, rev->rdiff2,
rev->creation_factor, 1, &opts, &other_arg);
argv_array_clear(&other_arg);
rev->creation_factor, 1, &opts);
}
}
@ -1317,9 +1248,9 @@ static int output_directory_callback(const struct option *opt, const char *arg,
static int thread_callback(const struct option *opt, const char *arg, int unset)
{
enum thread_level *thread = (enum thread_level *)opt->value;
int *thread = (int *)opt->value;
if (unset)
*thread = THREAD_UNSET;
*thread = 0;
else if (!arg || !strcmp(arg, "shallow"))
*thread = THREAD_SHALLOW;
else if (!strcmp(arg, "deep"))
@ -1366,7 +1297,7 @@ static int header_callback(const struct option *opt, const char *arg, int unset)
string_list_clear(&extra_to, 0);
string_list_clear(&extra_cc, 0);
} else {
add_header(arg);
add_header(arg);
}
return 0;
}
@ -1422,7 +1353,7 @@ static struct commit *get_base_commit(const char *base_commit,
base = lookup_commit_reference_by_name(base_commit);
if (!base)
die(_("unknown commit %s"), base_commit);
} else if ((base_commit && !strcmp(base_commit, "auto"))) {
} else if ((base_commit && !strcmp(base_commit, "auto")) || base_auto) {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
@ -1610,7 +1541,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int use_patch_format = 0;
int quiet = 0;
int reroll_count = -1;
char *cover_from_description_arg = NULL;
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
@ -1647,9 +1577,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 0, "rfc", &rev, NULL,
N_("Use [RFC PATCH] instead of [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
{ OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback },
@ -1713,11 +1640,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
extra_to.strdup_strings = 1;
extra_cc.strdup_strings = 1;
init_log_defaults();
init_display_notes(&notes_opt);
git_config(git_format_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
rev.show_notes = show_notes;
memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
git_config(git_format_config, &rev);
rev.commit_format = CMIT_FMT_EMAIL;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
@ -1729,9 +1653,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
if (base_auto)
base_commit = "auto";
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
@ -1747,9 +1668,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
PARSE_OPT_KEEP_DASHDASH);
if (cover_from_description_arg)
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
if (0 < reroll_count) {
struct strbuf sprefix = STRBUF_INIT;
strbuf_addf(&sprefix, "%s v%d",
@ -1836,7 +1754,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diffopt.flags.binary = 1;
if (rev.show_notes)
load_display_notes(&rev.notes_opt);
init_display_notes(&rev.notes_opt);
if (!output_directory && !use_stdout)
output_directory = config_output_directory;
@ -1847,26 +1765,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
setup_pager();
if (output_directory) {
int saved;
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
rev.diffopt.use_color = GIT_COLOR_NEVER;
if (use_stdout)
die(_("standard output, or directory, which one?"));
/*
* We consider <outdir> as 'outside of gitdir', therefore avoid
* applying adjust_shared_perm in s-c-l-d.
*/
saved = get_shared_repository();
set_shared_repository(0);
switch (safe_create_leading_directories_const(output_directory)) {
case SCLD_OK:
case SCLD_EXISTS:
break;
default:
die(_("could not create leading directories "
"of '%s'"), output_directory);
}
set_shared_repository(saved);
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
die_errno(_("could not create directory '%s'"),
output_directory);
@ -1995,7 +1897,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
memset(&bases, 0, sizeof(bases));
if (base_commit) {
if (base_commit || base_auto) {
struct commit *base = get_base_commit(base_commit, list, nr);
reset_revision_walk();
clear_object_flags(UNINTERESTING);

View file

@ -492,7 +492,7 @@ static int option_parse_exclude_from(const struct option *opt,
BUG_ON_OPT_NEG(unset);
exc_given = 1;
add_patterns_from_file(dir, arg);
add_excludes_from_file(dir, arg);
return 0;
}
@ -516,7 +516,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
int require_work_tree = 0, show_tag = 0, i;
const char *max_prefix;
struct dir_struct dir;
struct pattern_list *pl;
struct exclude_list *el;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct option builtin_ls_files_options[] = {
/* Think twice before adding "--nul" synonym to this */
@ -594,9 +594,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
ls_files_usage, 0);
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++) {
add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
}
if (show_tag || show_valid_bit || show_fsmonitor_bit) {
tag_cached = "H ";

View file

@ -1,4 +1,3 @@
#include "cache.h"
#include "builtin.h"
#include "commit.h"
#include "tag.h"
@ -64,9 +63,6 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
if (argc - i != 3) /* "--" "<head>" "<remote>" */
die(_("not handling anything other than two heads merge."));
if (repo_read_index_unmerged(the_repository))
die_resolve_conflict("merge");
o.branch1 = argv[++i];
o.branch2 = argv[++i];

View file

@ -180,9 +180,8 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
{
struct strbuf buf = STRBUF_INIT;
strbuf_make_traverse_path(&buf, info, n->path, n->pathlen);
return strbuf_detach(&buf, NULL);
char *path = xmallocz(traverse_path_len(info, n) + the_hash_algo->rawsz);
return make_traverse_path(path, info, n);
}
static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)

View file

@ -62,7 +62,6 @@ static int show_diffstat = 1, shortlog_len = -1, squash;
static int option_commit = -1;
static int option_edit = -1;
static int allow_trivial = 1, have_message, verify_signatures;
static int check_trust_level = 1;
static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
@ -82,7 +81,7 @@ static int show_progress = -1;
static int default_to_upstream = 1;
static int signoff;
static const char *sign_commit;
static int no_verify;
static int verify_msg = 1;
static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
@ -288,7 +287,7 @@ static struct option builtin_merge_options[] = {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
OPT_BOOL(0, "verify", &verify_msg, N_("verify commit-msg hook")),
OPT_END()
};
@ -632,8 +631,6 @@ static int git_merge_config(const char *k, const char *v, void *cb)
} else if (!strcmp(k, "commit.gpgsign")) {
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
} else if (!strcmp(k, "gpg.mintrustlevel")) {
check_trust_level = 0;
}
status = fmt_merge_msg_config(k, v, cb);
@ -691,13 +688,16 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
struct commit_list *remoteheads,
struct commit *head)
{
struct lock_file lock = LOCK_INIT;
const char *head_arg = "HEAD";
if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
return error(_("Unable to write index."));
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
struct lock_file lock = LOCK_INIT;
int clean, x;
struct commit *result;
struct commit_list *reversed = NULL;
@ -816,18 +816,6 @@ static void write_merge_heads(struct commit_list *);
static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
const char *index_file = get_index_file();
if (!no_verify && run_commit_hook(0 < option_edit, index_file, "pre-merge-commit", NULL))
abort_commit(remoteheads, NULL);
/*
* Re-read the index as pre-merge-commit hook could have updated it,
* and write it out as a tree. We must do this before we invoke
* the editor and after we invoke run_status above.
*/
if (find_hook("pre-merge-commit"))
discard_cache();
read_cache_from(index_file);
strbuf_addbuf(&msg, &merge_msg);
if (squash)
BUG("the control must not reach here under --squash");
@ -854,7 +842,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
abort_commit(remoteheads, NULL);
}
if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(),
if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(),
"commit-msg",
git_path_merge_msg(the_repository), NULL))
abort_commit(remoteheads, NULL);
@ -872,8 +860,12 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
struct lock_file lock = LOCK_INIT;
if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
return error(_("Unable to write index."));
write_tree_trivial(&result_tree);
@ -1400,8 +1392,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("Can merge only exactly one commit into empty head"));
if (verify_signatures)
verify_merge_signature(remoteheads->item, verbosity,
check_trust_level);
verify_merge_signature(remoteheads->item, verbosity);
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid, 0);
@ -1424,8 +1415,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verify_signatures) {
for (p = remoteheads; p; p = p->next) {
verify_merge_signature(p->item, verbosity,
check_trust_level);
verify_merge_signature(p->item, verbosity);
}
}

View file

@ -29,11 +29,8 @@ static int verify_object(const struct object_id *oid, const char *expected_type)
const struct object_id *repl = lookup_replace_object(the_repository, oid);
if (buffer) {
if (type == type_from_string(expected_type)) {
ret = check_object_signature(the_repository, repl,
buffer, size,
expected_type);
}
if (type == type_from_string(expected_type))
ret = check_object_signature(repl, buffer, size, expected_type);
free(buffer);
}
return ret;

View file

@ -6,25 +6,21 @@
#include "trace2.h"
static char const * const builtin_multi_pack_index_usage[] = {
N_("git multi-pack-index [<options>] (write|verify|expire|repack --batch-size=<size>)"),
N_("git multi-pack-index [--object-dir=<dir>] (write|verify|expire|repack --batch-size=<size>)"),
NULL
};
static struct opts_multi_pack_index {
const char *object_dir;
unsigned long batch_size;
int progress;
} opts;
int cmd_multi_pack_index(int argc, const char **argv,
const char *prefix)
{
unsigned flags = 0;
static struct option builtin_multi_pack_index_options[] = {
OPT_FILENAME(0, "object-dir", &opts.object_dir,
N_("object directory containing set of packfile and pack-index pairs")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
OPT_MAGNITUDE(0, "batch-size", &opts.batch_size,
N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
OPT_END(),
@ -32,15 +28,12 @@ int cmd_multi_pack_index(int argc, const char **argv,
git_config(git_default_config, NULL);
opts.progress = isatty(2);
argc = parse_options(argc, argv, prefix,
builtin_multi_pack_index_options,
builtin_multi_pack_index_usage, 0);
if (!opts.object_dir)
opts.object_dir = get_object_directory();
if (opts.progress)
flags |= MIDX_PROGRESS;
if (argc == 0)
usage_with_options(builtin_multi_pack_index_usage,
@ -54,17 +47,16 @@ int cmd_multi_pack_index(int argc, const char **argv,
trace2_cmd_mode(argv[0]);
if (!strcmp(argv[0], "repack"))
return midx_repack(the_repository, opts.object_dir,
(size_t)opts.batch_size, flags);
return midx_repack(the_repository, opts.object_dir, (size_t)opts.batch_size);
if (opts.batch_size)
die(_("--batch-size option is only for 'repack' subcommand"));
if (!strcmp(argv[0], "write"))
return write_midx_file(opts.object_dir, flags);
return write_midx_file(opts.object_dir);
if (!strcmp(argv[0], "verify"))
return verify_midx_file(the_repository, opts.object_dir, flags);
return verify_midx_file(the_repository, opts.object_dir);
if (!strcmp(argv[0], "expire"))
return expire_midx_packs(the_repository, opts.object_dir, flags);
return expire_midx_packs(the_repository, opts.object_dir);
die(_("unrecognized subcommand: %s"), argv[0]);
}

View file

@ -6,25 +6,20 @@
#include "tag.h"
#include "refs.h"
#include "parse-options.h"
#include "prio-queue.h"
#include "sha1-lookup.h"
#include "commit-slab.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
* changing this value
*/
#define CUTOFF_DATE_SLOP 86400
#define CUTOFF_DATE_SLOP 86400 /* one day */
struct rev_name {
char *tip_name;
typedef struct rev_name {
const char *tip_name;
timestamp_t taggerdate;
int generation;
int distance;
int from_tag;
};
} rev_name;
define_commit_slab(commit_rev_name, struct rev_name);
define_commit_slab(commit_rev_name, struct rev_name *);
static timestamp_t cutoff = TIME_MAX;
static struct commit_rev_name rev_names;
@ -32,16 +27,16 @@ static struct commit_rev_name rev_names;
/* How many generations are maximally preferred over _one_ merge traversal? */
#define MERGE_TRAVERSAL_WEIGHT 65535
static int is_valid_rev_name(const struct rev_name *name)
static struct rev_name *get_commit_rev_name(struct commit *commit)
{
return name && (name->generation || name->tip_name);
struct rev_name **slot = commit_rev_name_peek(&rev_names, commit);
return slot ? *slot : NULL;
}
static struct rev_name *get_commit_rev_name(const struct commit *commit)
static void set_commit_rev_name(struct commit *commit, struct rev_name *name)
{
struct rev_name *name = commit_rev_name_peek(&rev_names, commit);
return is_valid_rev_name(name) ? name : NULL;
*commit_rev_name_at(&rev_names, commit) = name;
}
static int is_better_name(struct rev_name *name,
@ -80,135 +75,68 @@ static int is_better_name(struct rev_name *name,
return 0;
}
static struct rev_name *create_or_update_name(struct commit *commit,
timestamp_t taggerdate,
int generation, int distance,
int from_tag)
{
struct rev_name *name = commit_rev_name_at(&rev_names, commit);
if (is_valid_rev_name(name)) {
if (!is_better_name(name, taggerdate, distance, from_tag))
return NULL;
/*
* This string might still be shared with ancestors
* (generation > 0). We can release it here regardless,
* because the new name that has just won will be better
* for them as well, so name_rev() will replace these
* stale pointers when it processes the parents.
*/
if (!name->generation)
free(name->tip_name);
}
name->taggerdate = taggerdate;
name->generation = generation;
name->distance = distance;
name->from_tag = from_tag;
return name;
}
static char *get_parent_name(const struct rev_name *name, int parent_number)
{
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);
} else {
strbuf_grow(&sb, len +
1 + decimal_width(parent_number));
strbuf_addf(&sb, "%.*s^%d", (int)len, name->tip_name,
parent_number);
}
return strbuf_detach(&sb, NULL);
}
static void name_rev(struct commit *start_commit,
static void name_rev(struct commit *commit,
const char *tip_name, timestamp_t taggerdate,
int from_tag, int deref)
int generation, int distance, int from_tag,
int deref)
{
struct prio_queue queue;
struct commit *commit;
struct commit **parents_to_queue = NULL;
size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
struct rev_name *start_name;
struct rev_name *name = get_commit_rev_name(commit);
struct commit_list *parents;
int parent_number = 1;
char *to_free = NULL;
parse_commit(start_commit);
if (start_commit->date < cutoff)
parse_commit(commit);
if (commit->date < cutoff)
return;
start_name = create_or_update_name(start_commit, taggerdate, 0, 0,
from_tag);
if (!start_name)
return;
if (deref)
start_name->tip_name = xstrfmt("%s^0", tip_name);
else
start_name->tip_name = xstrdup(tip_name);
if (deref) {
tip_name = to_free = xstrfmt("%s^0", tip_name);
memset(&queue, 0, sizeof(queue)); /* Use the prio_queue as LIFO */
prio_queue_put(&queue, start_commit);
while ((commit = prio_queue_get(&queue))) {
struct rev_name *name = get_commit_rev_name(commit);
struct commit_list *parents;
int parent_number = 1;
parents_to_queue_nr = 0;
for (parents = commit->parents;
parents;
parents = parents->next, parent_number++) {
struct commit *parent = parents->item;
struct rev_name *parent_name;
int generation, distance;
parse_commit(parent);
if (parent->date < cutoff)
continue;
if (parent_number > 1) {
generation = 0;
distance = name->distance + MERGE_TRAVERSAL_WEIGHT;
} else {
generation = name->generation + 1;
distance = name->distance + 1;
}
parent_name = create_or_update_name(parent, taggerdate,
generation,
distance, from_tag);
if (parent_name) {
if (parent_number > 1)
parent_name->tip_name =
get_parent_name(name,
parent_number);
else
parent_name->tip_name = name->tip_name;
ALLOC_GROW(parents_to_queue,
parents_to_queue_nr + 1,
parents_to_queue_alloc);
parents_to_queue[parents_to_queue_nr] = parent;
parents_to_queue_nr++;
}
}
/* The first parent must come out first from the prio_queue */
while (parents_to_queue_nr)
prio_queue_put(&queue,
parents_to_queue[--parents_to_queue_nr]);
if (generation)
die("generation: %d, but deref?", generation);
}
clear_prio_queue(&queue);
free(parents_to_queue);
if (name == NULL) {
name = xmalloc(sizeof(rev_name));
set_commit_rev_name(commit, name);
goto copy_data;
} else if (is_better_name(name, taggerdate, distance, from_tag)) {
copy_data:
name->tip_name = tip_name;
name->taggerdate = taggerdate;
name->generation = generation;
name->distance = distance;
name->from_tag = from_tag;
} else {
free(to_free);
return;
}
for (parents = commit->parents;
parents;
parents = parents->next, parent_number++) {
if (parent_number > 1) {
size_t len;
char *new_name;
strip_suffix(tip_name, "^0", &len);
if (generation > 0)
new_name = xstrfmt("%.*s~%d^%d", (int)len, tip_name,
generation, parent_number);
else
new_name = xstrfmt("%.*s^%d", (int)len, tip_name,
parent_number);
name_rev(parents->item, new_name, taggerdate, 0,
distance + MERGE_TRAVERSAL_WEIGHT,
from_tag, 0);
} else {
name_rev(parents->item, tip_name, taggerdate,
generation + 1, distance + 1,
from_tag, 0);
}
}
}
static int subpath_matches(const char *path, const char *filter)
@ -229,10 +157,10 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
{
if (shorten_unambiguous)
refname = shorten_unambiguous_ref(refname, 0);
else if (skip_prefix(refname, "refs/heads/", &refname))
; /* refname already advanced */
else
skip_prefix(refname, "refs/", &refname);
else if (starts_with(refname, "refs/heads/"))
refname = refname + 11;
else if (starts_with(refname, "refs/"))
refname = refname + 5;
return refname;
}
@ -247,10 +175,6 @@ static struct tip_table {
struct tip_table_entry {
struct object_id oid;
const char *refname;
struct commit *commit;
timestamp_t taggerdate;
unsigned int from_tag:1;
unsigned int deref:1;
} *table;
int nr;
int alloc;
@ -258,18 +182,13 @@ static struct tip_table {
} tip_table;
static void add_to_tip_table(const struct object_id *oid, const char *refname,
int shorten_unambiguous, struct commit *commit,
timestamp_t taggerdate, int from_tag, int deref)
int shorten_unambiguous)
{
refname = name_ref_abbrev(refname, shorten_unambiguous);
ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
oidcpy(&tip_table.table[tip_table.nr].oid, oid);
tip_table.table[tip_table.nr].refname = xstrdup(refname);
tip_table.table[tip_table.nr].commit = commit;
tip_table.table[tip_table.nr].taggerdate = taggerdate;
tip_table.table[tip_table.nr].from_tag = from_tag;
tip_table.table[tip_table.nr].deref = deref;
tip_table.nr++;
tip_table.sorted = 0;
}
@ -280,30 +199,12 @@ static int tipcmp(const void *a_, const void *b_)
return oidcmp(&a->oid, &b->oid);
}
static int cmp_by_tag_and_age(const void *a_, const void *b_)
{
const struct tip_table_entry *a = a_, *b = b_;
int cmp;
/* Prefer tags. */
cmp = b->from_tag - a->from_tag;
if (cmp)
return cmp;
/* Older is better. */
if (a->taggerdate < b->taggerdate)
return -1;
return a->taggerdate != b->taggerdate;
}
static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
{
struct object *o = parse_object(the_repository, oid);
struct name_ref_data *data = cb_data;
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
int from_tag = 0;
struct commit *commit = NULL;
timestamp_t taggerdate = TIME_MAX;
if (data->tags_only && !starts_with(path, "refs/tags/"))
@ -352,6 +253,8 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
return 0;
}
add_to_tip_table(oid, path, can_abbreviate_output);
while (o && o->type == OBJ_TAG) {
struct tag *t = (struct tag *) o;
if (!t->tagged)
@ -361,33 +264,16 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
taggerdate = t->date;
}
if (o && o->type == OBJ_COMMIT) {
commit = (struct commit *)o;
from_tag = starts_with(path, "refs/tags/");
struct commit *commit = (struct commit *)o;
int from_tag = starts_with(path, "refs/tags/");
if (taggerdate == TIME_MAX)
taggerdate = commit->date;
}
add_to_tip_table(oid, path, can_abbreviate_output, commit, taggerdate,
taggerdate = ((struct commit *)o)->date;
path = name_ref_abbrev(path, can_abbreviate_output);
name_rev(commit, xstrdup(path), taggerdate, 0, 0,
from_tag, deref);
return 0;
}
static void name_tips(void)
{
int i;
/*
* Try to set better names first, so that worse ones spread
* less.
*/
QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
for (i = 0; i < tip_table.nr; i++) {
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);
}
}
return 0;
}
static const unsigned char *nth_tip_table_ent(size_t ix, void *table_)
@ -419,11 +305,11 @@ static const char *get_exact_ref_match(const struct object *o)
static const char *get_rev_name(const struct object *o, struct strbuf *buf)
{
struct rev_name *n;
const struct commit *c;
struct commit *c;
if (o->type != OBJ_COMMIT)
return get_exact_ref_match(o);
c = (const struct commit *) o;
c = (struct commit *) o;
n = get_commit_rev_name(c);
if (!n)
return NULL;
@ -431,10 +317,11 @@ static const char *get_rev_name(const struct object *o, struct strbuf *buf)
if (!n->generation)
return n->tip_name;
else {
int len = strlen(n->tip_name);
if (len > 2 && !strcmp(n->tip_name + len - 2, "^0"))
len -= 2;
strbuf_reset(buf);
strbuf_addstr(buf, n->tip_name);
strbuf_strip_suffix(buf, "^0");
strbuf_addf(buf, "~%d", n->generation);
strbuf_addf(buf, "%.*s~%d", len, n->tip_name, n->generation);
return buf->buf;
}
}
@ -594,15 +481,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
add_object_array(object, *argv, &revs);
}
if (cutoff) {
/* check for undeflow */
if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
cutoff = cutoff - CUTOFF_DATE_SLOP;
else
cutoff = TIME_MIN;
}
if (cutoff)
cutoff = cutoff - CUTOFF_DATE_SLOP;
for_each_ref(name_ref, &data);
name_tips();
if (transform_stdin) {
char buffer[2048];

View file

@ -513,7 +513,7 @@ static int copy(int argc, const char **argv, const char *prefix)
}
}
if (argc < 1) {
if (argc < 2) {
error(_("too few parameters"));
usage_with_options(git_notes_copy_usage, options);
}
@ -622,7 +622,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
strbuf_grow(&d.buf, size + 1);
if (d.buf.len && prev_buf && size)
strbuf_insertstr(&d.buf, 0, "\n");
strbuf_insert(&d.buf, 0, "\n", 1);
if (prev_buf && size)
strbuf_insert(&d.buf, 0, prev_buf, size);
free(prev_buf);
@ -745,7 +745,7 @@ static int merge_commit(struct notes_merge_options *o)
memset(&pretty_ctx, 0, sizeof(pretty_ctx));
format_commit_message(partial, "%s", &msg, &pretty_ctx);
strbuf_trim(&msg);
strbuf_insertstr(&msg, 0, "notes: ");
strbuf_insert(&msg, 0, "notes: ", 7);
update_ref(msg.buf, o->local_ref, &oid,
is_null_oid(&parent_oid) ? NULL : &parent_oid,
0, UPDATE_REFS_DIE_ON_ERR);

View file

@ -92,11 +92,10 @@ static struct progress *progress_state;
static struct packed_git *reuse_packfile;
static uint32_t reuse_packfile_objects;
static struct bitmap *reuse_packfile_bitmap;
static off_t reuse_packfile_offset;
static int use_bitmap_index_default = 1;
static int use_bitmap_index = -1;
static int allow_pack_reuse = 1;
static enum {
WRITE_BITMAP_FALSE = 0,
WRITE_BITMAP_QUIET,
@ -164,7 +163,7 @@ static void *get_delta(struct object_entry *entry)
delta_buf = diff_delta(base_buf, base_size,
buf, size, &delta_size, 0);
/*
* We successfully computed this delta once but dropped it for
* We succesfully computed this delta once but dropped it for
* memory reasons. Something is very wrong if this time we
* recompute and create a different delta.
*/
@ -304,8 +303,7 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
if (!usable_delta) {
if (oe_type(entry) == OBJ_BLOB &&
oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
(st = open_istream(the_repository, &entry->idx.oid, &type,
&size, NULL)) != NULL)
(st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL)
buf = NULL;
else {
buf = read_object_file(&entry->idx.oid, &type, &size);
@ -612,12 +610,12 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
void *cb_data)
{
struct object_id peeled;
struct object_entry *entry = packlist_find(&to_pack, oid);
struct object_entry *entry = packlist_find(&to_pack, oid, NULL);
if (entry)
entry->tagged = 1;
if (!peel_ref(path, &peeled)) {
entry = packlist_find(&to_pack, &peeled);
entry = packlist_find(&to_pack, &peeled, NULL);
if (entry)
entry->tagged = 1;
}
@ -786,186 +784,57 @@ static struct object_entry **compute_write_order(void)
return wo;
}
/*
* A reused set of objects. All objects in a chunk have the same
* relative position in the original packfile and the generated
* packfile.
*/
static struct reused_chunk {
/* The offset of the first object of this chunk in the original
* packfile. */
off_t original;
/* The offset of the first object of this chunk in the generated
* packfile minus "original". */
off_t difference;
} *reused_chunks;
static int reused_chunks_nr;
static int reused_chunks_alloc;
static void record_reused_object(off_t where, off_t offset)
static off_t write_reused_pack(struct hashfile *f)
{
if (reused_chunks_nr && reused_chunks[reused_chunks_nr-1].difference == offset)
return;
unsigned char buffer[8192];
off_t to_write, total;
int fd;
ALLOC_GROW(reused_chunks, reused_chunks_nr + 1,
reused_chunks_alloc);
reused_chunks[reused_chunks_nr].original = where;
reused_chunks[reused_chunks_nr].difference = offset;
reused_chunks_nr++;
}
if (!is_pack_valid(reuse_packfile))
die(_("packfile is invalid: %s"), reuse_packfile->pack_name);
/*
* Binary search to find the chunk that "where" is in. Note
* that we're not looking for an exact match, just the first
* chunk that contains it (which implicitly ends at the start
* of the next chunk.
*/
static off_t find_reused_offset(off_t where)
{
int lo = 0, hi = reused_chunks_nr;
while (lo < hi) {
int mi = lo + ((hi - lo) / 2);
if (where == reused_chunks[mi].original)
return reused_chunks[mi].difference;
if (where < reused_chunks[mi].original)
hi = mi;
else
lo = mi + 1;
}
fd = git_open(reuse_packfile->pack_name);
if (fd < 0)
die_errno(_("unable to open packfile for reuse: %s"),
reuse_packfile->pack_name);
/*
* The first chunk starts at zero, so we can't have gone below
* there.
*/
assert(lo);
return reused_chunks[lo-1].difference;
}
if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
die_errno(_("unable to seek in reused packfile"));
static void write_reused_pack_one(size_t pos, struct hashfile *out,
struct pack_window **w_curs)
{
off_t offset, next, cur;
enum object_type type;
unsigned long size;
if (reuse_packfile_offset < 0)
reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
offset = reuse_packfile->revindex[pos].offset;
next = reuse_packfile->revindex[pos + 1].offset;
total = to_write = reuse_packfile_offset - sizeof(struct pack_header);
record_reused_object(offset, offset - hashfile_total(out));
while (to_write) {
int read_pack = xread(fd, buffer, sizeof(buffer));
cur = offset;
type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
assert(type >= 0);
if (read_pack <= 0)
die_errno(_("unable to read from reused packfile"));
if (type == OBJ_OFS_DELTA) {
off_t base_offset;
off_t fixup;
if (read_pack > to_write)
read_pack = to_write;
unsigned char header[MAX_PACK_OBJECT_HEADER];
unsigned len;
base_offset = get_delta_base(reuse_packfile, w_curs, &cur, type, offset);
assert(base_offset != 0);
/* Convert to REF_DELTA if we must... */
if (!allow_ofs_delta) {
int base_pos = find_revindex_position(reuse_packfile, base_offset);
struct object_id base_oid;
nth_packed_object_id(&base_oid, reuse_packfile,
reuse_packfile->revindex[base_pos].nr);
len = encode_in_pack_object_header(header, sizeof(header),
OBJ_REF_DELTA, size);
hashwrite(out, header, len);
hashwrite(out, base_oid.hash, 20);
copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
return;
}
/* Otherwise see if we need to rewrite the offset... */
fixup = find_reused_offset(offset) -
find_reused_offset(base_offset);
if (fixup) {
unsigned char ofs_header[10];
unsigned i, ofs_len;
off_t ofs = offset - base_offset - fixup;
len = encode_in_pack_object_header(header, sizeof(header),
OBJ_OFS_DELTA, size);
i = sizeof(ofs_header) - 1;
ofs_header[i] = ofs & 127;
while (ofs >>= 7)
ofs_header[--i] = 128 | (--ofs & 127);
ofs_len = sizeof(ofs_header) - i;
hashwrite(out, header, len);
hashwrite(out, ofs_header + sizeof(ofs_header) - ofs_len, ofs_len);
copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
return;
}
/* ...otherwise we have no fixup, and can write it verbatim */
}
copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
}
static size_t write_reused_pack_verbatim(struct hashfile *out,
struct pack_window **w_curs)
{
size_t pos = 0;
while (pos < reuse_packfile_bitmap->word_alloc &&
reuse_packfile_bitmap->words[pos] == (eword_t)~0)
pos++;
if (pos) {
off_t to_write;
written = (pos * BITS_IN_EWORD);
to_write = reuse_packfile->revindex[written].offset
- sizeof(struct pack_header);
/* We're recording one chunk, not one object. */
record_reused_object(sizeof(struct pack_header), 0);
hashflush(out);
copy_pack_data(out, reuse_packfile, w_curs,
sizeof(struct pack_header), to_write);
hashwrite(f, buffer, read_pack);
to_write -= read_pack;
/*
* We don't know the actual number of objects written,
* only how many bytes written, how many bytes total, and
* how many objects total. So we can fake it by pretending all
* objects we are writing are the same size. This gives us a
* smooth progress meter, and at the end it matches the true
* answer.
*/
written = reuse_packfile_objects *
(((double)(total - to_write)) / total);
display_progress(progress_state, written);
}
return pos;
}
static void write_reused_pack(struct hashfile *f)
{
size_t i = 0;
uint32_t offset;
struct pack_window *w_curs = NULL;
if (allow_ofs_delta)
i = write_reused_pack_verbatim(f, &w_curs);
for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
eword_t word = reuse_packfile_bitmap->words[i];
size_t pos = (i * BITS_IN_EWORD);
for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
if ((word >> offset) == 0)
break;
offset += ewah_bit_ctz64(word >> offset);
write_reused_pack_one(pos + offset, f, &w_curs);
display_progress(progress_state, ++written);
}
}
unuse_pack(&w_curs);
close(fd);
written = reuse_packfile_objects;
display_progress(progress_state, written);
return reuse_packfile_offset - sizeof(struct pack_header);
}
static const char no_split_warning[] = N_(
@ -998,9 +867,11 @@ static void write_pack_file(void)
offset = write_pack_header(f, nr_remaining);
if (reuse_packfile) {
off_t packfile_size;
assert(pack_to_stdout);
write_reused_pack(f);
offset = hashfile_total(f);
packfile_size = write_reused_pack(f);
offset += packfile_size;
}
nr_written = 0;
@ -1125,15 +996,12 @@ static int no_try_delta(const char *path)
* few lines later when we want to add the new entry.
*/
static int have_duplicate_entry(const struct object_id *oid,
int exclude)
int exclude,
uint32_t *index_pos)
{
struct object_entry *entry;
if (reuse_packfile_bitmap &&
bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid))
return 1;
entry = packlist_find(&to_pack, oid);
entry = packlist_find(&to_pack, oid, index_pos);
if (!entry)
return 0;
@ -1273,12 +1141,13 @@ static void create_object_entry(const struct object_id *oid,
uint32_t hash,
int exclude,
int no_try_delta,
uint32_t index_pos,
struct packed_git *found_pack,
off_t found_offset)
{
struct object_entry *entry;
entry = packlist_alloc(&to_pack, oid);
entry = packlist_alloc(&to_pack, oid->hash, index_pos);
entry->hash = hash;
oe_set_type(entry, type);
if (exclude)
@ -1302,10 +1171,11 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
{
struct packed_git *found_pack = NULL;
off_t found_offset = 0;
uint32_t index_pos;
display_progress(progress_state, ++nr_seen);
if (have_duplicate_entry(oid, exclude))
if (have_duplicate_entry(oid, exclude, &index_pos))
return 0;
if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
@ -1320,7 +1190,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
create_object_entry(oid, type, pack_name_hash(name),
exclude, name && no_try_delta(name),
found_pack, found_offset);
index_pos, found_pack, found_offset);
return 1;
}
@ -1329,15 +1199,17 @@ static int add_object_entry_from_bitmap(const struct object_id *oid,
int flags, uint32_t name_hash,
struct packed_git *pack, off_t offset)
{
uint32_t index_pos;
display_progress(progress_state, ++nr_seen);
if (have_duplicate_entry(oid, 0))
if (have_duplicate_entry(oid, 0, &index_pos))
return 0;
if (!want_object_in_pack(oid, 0, &pack, &offset))
return 0;
create_object_entry(oid, type, name_hash, 0, 0, pack, offset);
create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
return 1;
}
@ -1619,17 +1491,23 @@ static void cleanup_preferred_base(void)
* deltify other objects against, in order to avoid
* circular deltas.
*/
static int can_reuse_delta(const struct object_id *base_oid,
static int can_reuse_delta(const unsigned char *base_sha1,
struct object_entry *delta,
struct object_entry **base_out)
{
struct object_entry *base;
struct object_id base_oid;
if (!base_sha1)
return 0;
oidread(&base_oid, base_sha1);
/*
* First see if we're already sending the base (or it's explicitly in
* our "excluded" list).
*/
base = packlist_find(&to_pack, base_oid);
base = packlist_find(&to_pack, &base_oid, NULL);
if (base) {
if (!in_same_island(&delta->idx.oid, &base->idx.oid))
return 0;
@ -1642,9 +1520,9 @@ static int can_reuse_delta(const struct object_id *base_oid,
* even if it was buried too deep in history to make it into the
* packing list.
*/
if (thin && bitmap_has_oid_in_uninteresting(bitmap_git, base_oid)) {
if (thin && bitmap_has_oid_in_uninteresting(bitmap_git, &base_oid)) {
if (use_delta_islands) {
if (!in_same_island(&delta->idx.oid, base_oid))
if (!in_same_island(&delta->idx.oid, &base_oid))
return 0;
}
*base_out = NULL;
@ -1661,8 +1539,7 @@ static void check_object(struct object_entry *entry)
if (IN_PACK(entry)) {
struct packed_git *p = IN_PACK(entry);
struct pack_window *w_curs = NULL;
int have_base = 0;
struct object_id base_ref;
const unsigned char *base_ref = NULL;
struct object_entry *base_entry;
unsigned long used, used_0;
unsigned long avail;
@ -1703,13 +1580,9 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
return;
case OBJ_REF_DELTA:
if (reuse_delta && !entry->preferred_base) {
oidread(&base_ref,
use_pack(p, &w_curs,
entry->in_pack_offset + used,
NULL));
have_base = 1;
}
if (reuse_delta && !entry->preferred_base)
base_ref = use_pack(p, &w_curs,
entry->in_pack_offset + used, NULL);
entry->in_pack_header_size = used + the_hash_algo->rawsz;
break;
case OBJ_OFS_DELTA:
@ -1739,15 +1612,13 @@ static void check_object(struct object_entry *entry)
revidx = find_pack_revindex(p, ofs);
if (!revidx)
goto give_up;
if (!nth_packed_object_id(&base_ref, p, revidx->nr))
have_base = 1;
base_ref = nth_packed_object_sha1(p, revidx->nr);
}
entry->in_pack_header_size = used + used_0;
break;
}
if (have_base &&
can_reuse_delta(&base_ref, entry, &base_entry)) {
if (can_reuse_delta(base_ref, entry, &base_entry)) {
oe_set_type(entry, entry->in_pack_type);
SET_SIZE(entry, in_pack_size); /* delta size */
SET_DELTA_SIZE(entry, in_pack_size);
@ -1757,7 +1628,7 @@ static void check_object(struct object_entry *entry)
entry->delta_sibling_idx = base_entry->delta_child_idx;
SET_DELTA_CHILD(base_entry, entry);
} else {
SET_DELTA_EXT(entry, &base_ref);
SET_DELTA_EXT(entry, base_ref);
}
unuse_pack(&w_curs);
@ -2471,6 +2342,15 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
free(array);
}
static void try_to_free_from_threads(size_t size)
{
packing_data_lock(&to_pack);
release_pack_memory(size);
packing_data_unlock(&to_pack);
}
static try_to_free_t old_try_to_free_routine;
/*
* The main object list is split into smaller lists, each is handed to
* one worker.
@ -2511,10 +2391,12 @@ static void init_threaded_search(void)
pthread_mutex_init(&cache_mutex, NULL);
pthread_mutex_init(&progress_mutex, NULL);
pthread_cond_init(&progress_cond, NULL);
old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
}
static void cleanup_threaded_search(void)
{
set_try_to_free_routine(old_try_to_free_routine);
pthread_cond_destroy(&progress_cond);
pthread_mutex_destroy(&cache_mutex);
pthread_mutex_destroy(&progress_mutex);
@ -2686,13 +2568,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
free(p);
}
static int obj_is_packed(const struct object_id *oid)
{
return packlist_find(&to_pack, oid) ||
(reuse_packfile_bitmap &&
bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid));
}
static void add_tag_chain(const struct object_id *oid)
{
struct tag *tag;
@ -2704,7 +2579,7 @@ static void add_tag_chain(const struct object_id *oid)
* it was included via bitmaps, we would not have parsed it
* previously).
*/
if (obj_is_packed(oid))
if (packlist_find(&to_pack, oid, NULL))
return;
tag = lookup_tag(the_repository, oid);
@ -2728,7 +2603,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
if (starts_with(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, &peeled) && /* peelable? */
obj_is_packed(&peeled)) /* object packed? */
packlist_find(&to_pack, &peeled, NULL)) /* object packed? */
add_tag_chain(oid);
return 0;
}
@ -2796,7 +2671,6 @@ static void prepare_pack(int window, int depth)
if (nr_deltas && n > 1) {
unsigned nr_done = 0;
if (progress)
progress_state = start_progress(_("Compressing objects"),
nr_deltas);
@ -2841,8 +2715,8 @@ static int git_pack_config(const char *k, const char *v, void *cb)
use_bitmap_index_default = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "pack.allowpackreuse")) {
allow_pack_reuse = git_config_bool(k, v);
if (!strcmp(k, "pack.usesparse")) {
sparse = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "pack.threads")) {
@ -2929,7 +2803,7 @@ static void show_object(struct object *obj, const char *name, void *data)
for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
depth++;
ent = packlist_find(&to_pack, &obj->oid);
ent = packlist_find(&to_pack, &obj->oid, NULL);
if (ent && depth > oe_tree_depth(&to_pack, ent))
oe_set_tree_depth(&to_pack, ent, depth);
}
@ -3055,7 +2929,7 @@ static void add_objects_in_unpacked_packs(void)
in_pack.alloc);
for (i = 0; i < p->num_objects; i++) {
nth_packed_object_id(&oid, p, i);
nth_packed_object_oid(&oid, p, i);
o = lookup_unknown_object(&oid);
if (!(o->flags & OBJECT_ADDED))
mark_in_pack_object(o, p, &in_pack);
@ -3159,8 +3033,8 @@ static void loosen_unused_packed_objects(void)
die(_("cannot open pack index"));
for (i = 0; i < p->num_objects; i++) {
nth_packed_object_id(&oid, p, i);
if (!packlist_find(&to_pack, &oid) &&
nth_packed_object_oid(&oid, p, i);
if (!packlist_find(&to_pack, &oid, NULL) &&
!has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime))
if (force_object_loose(&oid, p->mtime))
@ -3176,8 +3050,8 @@ static void loosen_unused_packed_objects(void)
*/
static int pack_options_allow_reuse(void)
{
return allow_pack_reuse &&
pack_to_stdout &&
return pack_to_stdout &&
allow_ofs_delta &&
!ignore_packed_keep_on_disk &&
!ignore_packed_keep_in_core &&
(!local || !have_non_local_packs) &&
@ -3186,7 +3060,7 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
if (!(bitmap_git = prepare_bitmap_walk(revs)))
return -1;
if (pack_options_allow_reuse() &&
@ -3194,14 +3068,13 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
bitmap_git,
&reuse_packfile,
&reuse_packfile_objects,
&reuse_packfile_bitmap)) {
&reuse_packfile_offset)) {
assert(reuse_packfile_objects);
nr_result += reuse_packfile_objects;
display_progress(progress_state, nr_result);
}
traverse_bitmap_commit_list(bitmap_git, revs,
&add_object_entry_from_bitmap);
traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
return 0;
}
@ -3470,10 +3343,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0);
prepare_repo_settings(the_repository);
if (!sparse && the_repository->settings.pack_use_sparse != -1)
sparse = the_repository->settings.pack_use_sparse;
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
@ -3565,6 +3434,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (filter_options.choice) {
if (!pack_to_stdout)
die(_("cannot use --filter without --stdout"));
use_bitmap_index = 0;
}
/*
@ -3655,9 +3525,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (progress)
fprintf_ln(stderr,
_("Total %"PRIu32" (delta %"PRIu32"),"
" reused %"PRIu32" (delta %"PRIu32"),"
" pack-reused %"PRIu32),
written, written_delta, reused, reused_delta,
reuse_packfile_objects);
" reused %"PRIu32" (delta %"PRIu32")"),
written, written_delta, reused, reused_delta);
return 0;
}

View file

@ -1,12 +1,16 @@
#include "cache.h"
#include "builtin.h"
#include "config.h"
#include "diff.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
{
if (patchlen)
printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
char name[50];
if (!patchlen)
return;
memcpy(name, oid_to_hex(id), GIT_SHA1_HEXSZ + 1);
printf("%s %s\n", oid_to_hex(result), name);
}
static int remove_space(char *line)
@ -56,9 +60,9 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
{
int patchlen = 0, found_next = 0;
int before = -1, after = -1;
git_hash_ctx ctx;
git_SHA_CTX ctx;
the_hash_algo->init_fn(&ctx);
git_SHA1_Init(&ctx);
oidclr(result);
while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
@ -118,7 +122,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
/* Compute the sha without whitespace */
len = remove_space(line);
patchlen += len;
the_hash_algo->update_fn(&ctx, line, len);
git_SHA1_Update(&ctx, line, len);
}
if (!found_next)

View file

@ -15,7 +15,6 @@
#include "sha1-array.h"
#include "remote.h"
#include "dir.h"
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
#include "revision.h"
@ -27,6 +26,15 @@
#include "commit-reach.h"
#include "sequencer.h"
enum rebase_type {
REBASE_INVALID = -1,
REBASE_FALSE = 0,
REBASE_TRUE,
REBASE_PRESERVE,
REBASE_MERGES,
REBASE_INTERACTIVE
};
/**
* Parses the value of --rebase. If value is a false value, returns
* REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
@ -37,9 +45,22 @@
static enum rebase_type parse_config_rebase(const char *key, const char *value,
int fatal)
{
enum rebase_type v = rebase_parse_value(value);
if (v != REBASE_INVALID)
return v;
int v = git_parse_maybe_bool(value);
if (!v)
return REBASE_FALSE;
else if (v > 0)
return REBASE_TRUE;
else if (!strcmp(value, "preserve") || !strcmp(value, "p"))
return REBASE_PRESERVE;
else if (!strcmp(value, "merges") || !strcmp(value, "m"))
return REBASE_MERGES;
else if (!strcmp(value, "interactive") || !strcmp(value, "i"))
return REBASE_INTERACTIVE;
/*
* Please update _git_config() in git-completion.bash when you
* add new rebase modes.
*/
if (fatal)
die(_("Invalid value for %s: %s"), key, value);
@ -86,7 +107,6 @@ static char *opt_ff;
static char *opt_verify_signatures;
static int opt_autostash = -1;
static int config_autostash;
static int check_trust_level = 1;
static struct argv_array opt_strategies = ARGV_ARRAY_INIT;
static struct argv_array opt_strategy_opts = ARGV_ARRAY_INIT;
static char *opt_gpg_sign;
@ -109,7 +129,6 @@ static char *opt_refmap;
static char *opt_ipv4;
static char *opt_ipv6;
static int opt_show_forced_updates = -1;
static char *set_upstream;
static struct option pull_options[] = {
/* Shared options */
@ -224,9 +243,6 @@ static struct option pull_options[] = {
PARSE_OPT_NOARG),
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
N_("check for forced-updates on all updated branches")),
OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
N_("set upstream for git pull/fetch"),
PARSE_OPT_NOARG),
OPT_END()
};
@ -335,8 +351,6 @@ static enum rebase_type config_get_rebase(void)
*/
static int git_pull_config(const char *var, const char *value, void *cb)
{
int status;
if (!strcmp(var, "rebase.autostash")) {
config_autostash = git_config_bool(var, value);
return 0;
@ -344,14 +358,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
recurse_submodules = git_config_bool(var, value) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
return 0;
} else if (!strcmp(var, "gpg.mintrustlevel")) {
check_trust_level = 0;
}
status = git_gpg_config(var, value, cb);
if (status)
return status;
return git_default_config(var, value, cb);
}
@ -549,8 +556,6 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, "--show-forced-updates");
else if (opt_show_forced_updates == 0)
argv_array_push(&args, "--no-show-forced-updates");
if (set_upstream)
argv_array_push(&args, set_upstream);
if (repo) {
argv_array_push(&args, repo);
@ -576,8 +581,7 @@ static int pull_into_void(const struct object_id *merge_head,
die(_("unable to access commit %s"),
oid_to_hex(merge_head));
verify_merge_signature(commit, opt_verbosity,
check_trust_level);
verify_merge_signature(commit, opt_verbosity);
}
/*

View file

@ -64,7 +64,6 @@ static struct string_list push_options_config = STRING_LIST_INIT_DUP;
static const char *map_refspec(const char *ref,
struct remote *remote, struct ref *local_refs)
{
const char *branch_name;
struct ref *matched = NULL;
/* Does "ref" uniquely name our ref? */
@ -85,8 +84,8 @@ static const char *map_refspec(const char *ref,
}
if (push_default == PUSH_DEFAULT_UPSTREAM &&
skip_prefix(matched->name, "refs/heads/", &branch_name)) {
struct branch *branch = branch_get(branch_name);
starts_with(matched->name, "refs/heads/")) {
struct branch *branch = branch_get(matched->name + 11);
if (branch->merge_nr == 1 && branch->merge[0]->src) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s:%s",
@ -144,8 +143,8 @@ static int push_url_of_remote(struct remote *remote, const char ***url_p)
return remote->url_nr;
}
static NORETURN void die_push_simple(struct branch *branch,
struct remote *remote)
static NORETURN int die_push_simple(struct branch *branch,
struct remote *remote)
{
/*
* There's no point in using shorten_unambiguous_ref here,
@ -358,10 +357,8 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
trace2_region_enter("push", "transport_push", the_repository);
err = transport_push(the_repository, transport,
rs, flags, &reject_reasons);
trace2_region_leave("push", "transport_push", the_repository);
if (err != 0) {
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
error(_("failed to push some refs to '%s'"), transport->url);
@ -388,14 +385,30 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
}
static int do_push(const char *repo, int flags,
const struct string_list *push_options,
struct remote *remote)
const struct string_list *push_options)
{
int i, errs;
struct remote *remote = pushremote_get(repo);
const char **url;
int url_nr;
struct refspec *push_refspec = &rs;
if (!remote) {
if (repo)
die(_("bad repository '%s'"), repo);
die(_("No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote repository using\n"
"\n"
" git remote add <name> <url>\n"
"\n"
"and then push using the remote name\n"
"\n"
" git push <name>\n"));
}
if (remote->mirror)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (push_options->nr)
flags |= TRANSPORT_PUSH_OPTIONS;
@ -535,7 +548,6 @@ int cmd_push(int argc, const char **argv, const char *prefix)
struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
struct string_list *push_options;
const struct string_list_item *item;
struct remote *remote;
struct option options[] = {
OPT__VERBOSITY(&verbosity),
@ -590,6 +602,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)
die(_("--delete is incompatible with --all, --mirror and --tags"));
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
if (flags & TRANSPORT_PUSH_ALL) {
if (tags)
die(_("--all and --tags are incompatible"));
if (argc >= 2)
die(_("--all can't be combined with refspecs"));
}
if (flags & TRANSPORT_PUSH_MIRROR) {
if (tags)
die(_("--mirror and --tags are incompatible"));
if (argc >= 2)
die(_("--mirror can't be combined with refspecs"));
}
if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
die(_("--all and --mirror are incompatible"));
if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
@ -606,43 +632,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
set_refspecs(argv + 1, argc - 1, repo);
}
remote = pushremote_get(repo);
if (!remote) {
if (repo)
die(_("bad repository '%s'"), repo);
die(_("No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote repository using\n"
"\n"
" git remote add <name> <url>\n"
"\n"
"and then push using the remote name\n"
"\n"
" git push <name>\n"));
}
if (remote->mirror)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (flags & TRANSPORT_PUSH_ALL) {
if (tags)
die(_("--all and --tags are incompatible"));
if (argc >= 2)
die(_("--all can't be combined with refspecs"));
}
if (flags & TRANSPORT_PUSH_MIRROR) {
if (tags)
die(_("--mirror and --tags are incompatible"));
if (argc >= 2)
die(_("--mirror can't be combined with refspecs"));
}
if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
die(_("--all and --mirror are incompatible"));
for_each_string_list_item(item, push_options)
if (strchr(item->string, '\n'))
die(_("push options must not have new line characters"));
rc = do_push(repo, flags, push_options, remote);
rc = do_push(repo, flags, push_options);
string_list_clear(&push_options_cmdline, 0);
string_list_clear(&push_options_config, 0);
if (rc == -1)

View file

@ -15,16 +15,12 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
{
int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
struct diff_options diffopt = { NULL };
struct argv_array other_arg = ARGV_ARRAY_INIT;
int simple_color = -1;
struct option range_diff_options[] = {
OPT_INTEGER(0, "creation-factor", &creation_factor,
N_("Percentage by which creation is weighted")),
OPT_BOOL(0, "no-dual-color", &simple_color,
N_("use simple diff colors")),
OPT_PASSTHRU_ARGV(0, "notes", &other_arg,
N_("notes"), N_("passed to 'git log'"),
PARSE_OPT_OPTARG),
OPT_END()
};
struct option *options;
@ -82,9 +78,8 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
FREE_AND_NULL(options);
res = show_range_diff(range1.buf, range2.buf, creation_factor,
simple_color < 1, &diffopt, &other_arg);
simple_color < 1, &diffopt);
argv_array_clear(&other_arg);
strbuf_release(&range1);
strbuf_release(&range2);

View file

@ -185,7 +185,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (opts.reset || opts.merge || opts.prefix) {
if (read_cache_unmerged() && (opts.prefix || opts.merge))
die(_("You need to resolve your current index first"));
die("You need to resolve your current index first");
stage = opts.merge = 1;
}
resolve_undo_clear();

View file

@ -29,8 +29,8 @@
#include "rebase-interactive.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] "
"[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
"[<upstream>] [<branch>]"),
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
"--root [<branch>]"),
N_("git rebase --continue | --abort | --skip | --edit-todo"),
@ -44,22 +44,14 @@ static GIT_PATH_FUNC(merge_dir, "rebase-merge")
enum rebase_type {
REBASE_UNSPECIFIED = -1,
REBASE_APPLY,
REBASE_AM,
REBASE_MERGE,
REBASE_INTERACTIVE,
REBASE_PRESERVE_MERGES
};
enum empty_type {
EMPTY_UNSPECIFIED = -1,
EMPTY_DROP,
EMPTY_KEEP,
EMPTY_ASK
};
struct rebase_options {
enum rebase_type type;
enum empty_type empty;
const char *default_backend;
const char *state_dir;
struct commit *upstream;
const char *upstream_name;
@ -70,7 +62,7 @@ struct rebase_options {
const char *onto_name;
const char *revisions;
const char *switch_to;
int root, root_with_onto;
int root;
struct object_id *squash_onto;
struct commit *restrict_revision;
int dont_finish_rebase;
@ -85,6 +77,7 @@ struct rebase_options {
const char *action;
int signoff;
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
char *gpg_sign_opt;
int autostash;
@ -99,8 +92,6 @@ struct rebase_options {
#define REBASE_OPTIONS_INIT { \
.type = REBASE_UNSPECIFIED, \
.empty = EMPTY_UNSPECIFIED, \
.default_backend = "merge", \
.flags = REBASE_NO_QUIET, \
.git_am_opts = ARGV_ARRAY_INIT, \
.git_format_patch_opt = STRBUF_INIT \
@ -119,9 +110,6 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.allow_rerere_auto = opts->allow_rerere_autoupdate;
replay.allow_empty = 1;
replay.allow_empty_message = opts->allow_empty_message;
replay.drop_redundant_commits = (opts->empty == EMPTY_DROP);
replay.keep_redundant_commits = (opts->empty == EMPTY_KEEP);
replay.quiet = !(opts->flags & REBASE_NO_QUIET);
replay.verbose = opts->flags & REBASE_VERBOSE;
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
@ -129,11 +117,6 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
if (opts->strategy_opts)
parse_strategy_opts(&replay, opts->strategy_opts);
if (opts->squash_onto) {
oidcpy(&replay.squash_onto, opts->squash_onto);
replay.have_squash_onto = 1;
}
return replay;
}
@ -258,17 +241,21 @@ static int edit_todo_file(unsigned flags)
}
static int get_revision_ranges(struct commit *upstream, struct commit *onto,
struct object_id *orig_head, const char **head_hash,
const char **head_hash,
char **revisions, char **shortrevisions)
{
struct commit *base_rev = upstream ? upstream : onto;
const char *shorthead;
struct object_id orig_head;
*head_hash = find_unique_abbrev(orig_head, GIT_MAX_HEXSZ);
if (get_oid("HEAD", &orig_head))
return error(_("no HEAD?"));
*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);
*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
*head_hash);
shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);
if (upstream) {
const char *shortrev;
@ -322,8 +309,12 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
struct replay_opts replay = get_replay_opts(opts);
struct string_list commands = STRING_LIST_INIT_DUP;
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
&head_hash, &revisions, &shortrevisions))
if (prepare_branch_to_be_rebased(the_repository, &replay,
opts->switch_to))
return -1;
if (get_revision_ranges(opts->upstream, opts->onto, &head_hash,
&revisions, &shortrevisions))
return -1;
if (init_basic_state(&replay,
@ -341,8 +332,8 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
argv_array_pushl(&make_script_args, "", revisions, NULL);
if (opts->restrict_revision)
argv_array_pushf(&make_script_args, "^%s",
oid_to_hex(&opts->restrict_revision->object.oid));
argv_array_push(&make_script_args,
oid_to_hex(&opts->restrict_revision->object.oid));
ret = sequencer_make_script(the_repository, &todo_list.buf,
make_script_args.argc, make_script_args.argv,
@ -371,7 +362,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
return ret;
}
static int run_sequencer_rebase(struct rebase_options *opts,
static int run_rebase_interactive(struct rebase_options *opts,
enum action command)
{
unsigned flags = 0;
@ -379,10 +370,10 @@ static int run_sequencer_rebase(struct rebase_options *opts,
git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
flags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
flags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
switch (command) {
@ -442,21 +433,6 @@ static int run_sequencer_rebase(struct rebase_options *opts,
return ret;
}
static int parse_opt_keep_empty(const struct option *opt, const char *arg,
int unset)
{
struct rebase_options *opts = opt->value;
BUG_ON_OPT_ARG(arg);
/*
* If we ever want to remap --keep-empty to --empty=keep, insert:
* opts->empty = unset ? EMPTY_UNSPECIFIED : EMPTY_KEEP;
*/
opts->type = REBASE_MERGE;
return 0;
}
static const char * const builtin_rebase_interactive_usage[] = {
N_("git rebase--interactive [<options>]"),
NULL
@ -470,13 +446,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"),
REBASE_FORCE),
{ OPTION_CALLBACK, 'k', "keep-empty", &options, NULL,
N_("(DEPRECATED) keep empty commits"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
parse_opt_keep_empty },
OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message,
N_("allow commits with empty messages"),
PARSE_OPT_HIDDEN),
OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")),
OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
N_("allow commits with empty messages")),
OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")),
OPT_BOOL(0, "rebase-cousins", &opts.rebase_cousins,
N_("keep original branch points of cousins")),
@ -546,26 +518,28 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
warning(_("--[no-]rebase-cousins has no effect without "
"--rebase-merges"));
return !!run_sequencer_rebase(&opts, command);
return !!run_rebase_interactive(&opts, command);
}
static int is_merge(struct rebase_options *opts)
static int is_interactive(struct rebase_options *opts)
{
return opts->type == REBASE_MERGE ||
return opts->type == REBASE_INTERACTIVE ||
opts->type == REBASE_PRESERVE_MERGES;
}
static void imply_merge(struct rebase_options *opts, const char *option)
static void imply_interactive(struct rebase_options *opts, const char *option)
{
switch (opts->type) {
case REBASE_APPLY:
case REBASE_AM:
die(_("%s requires an interactive rebase"), option);
break;
case REBASE_MERGE:
case REBASE_INTERACTIVE:
case REBASE_PRESERVE_MERGES:
break;
case REBASE_MERGE:
/* we now implement --merge via --interactive */
default:
opts->type = REBASE_MERGE; /* implied */
opts->type = REBASE_INTERACTIVE; /* implied */
break;
}
}
@ -691,8 +665,8 @@ static int rebase_write_basic_state(struct rebase_options *opts)
opts->onto ? oid_to_hex(&opts->onto->object.oid) : "");
write_file(state_dir_path("orig-head", opts), "%s",
oid_to_hex(&opts->orig_head));
if (!(opts->flags & REBASE_NO_QUIET))
write_file(state_dir_path("quiet", opts), "%s", "");
write_file(state_dir_path("quiet", opts), "%s",
opts->flags & REBASE_NO_QUIET ? "" : "t");
if (opts->flags & REBASE_VERBOSE)
write_file(state_dir_path("verbose", opts), "%s", "");
if (opts->strategy)
@ -710,7 +684,7 @@ static int rebase_write_basic_state(struct rebase_options *opts)
write_file(state_dir_path("gpg_sign_opt", opts), "%s",
opts->gpg_sign_opt);
if (opts->signoff)
write_file(state_dir_path("signoff", opts), "--signoff");
write_file(state_dir_path("strategy", opts), "--signoff");
return 0;
}
@ -774,7 +748,7 @@ static int finish_rebase(struct rebase_options *opts)
* user should see them.
*/
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
if (opts->type == REBASE_MERGE) {
if (opts->type == REBASE_INTERACTIVE) {
struct replay_opts replay = REPLAY_OPTS_INIT;
replay.action = REPLAY_INTERACTIVE_REBASE;
@ -1037,8 +1011,7 @@ static int run_am(struct rebase_options *opts)
argv_array_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
"--full-index", "--cherry-pick", "--right-only",
"--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
"--no-cover-letter", "--pretty=mboxrd", "--topo-order",
"--no-base", NULL);
"--no-cover-letter", "--pretty=mboxrd", "--topo-order", NULL);
if (opts->git_format_patch_opt.len)
argv_array_split(&format_patch.args,
opts->git_format_patch_opt.buf);
@ -1107,8 +1080,8 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
int status;
const char *backend, *backend_func;
if (opts->type == REBASE_MERGE) {
/* Run sequencer-based rebase */
if (opts->type == REBASE_INTERACTIVE) {
/* Run builtin interactive rebase */
setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1);
if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
setenv("GIT_SEQUENCE_EDITOR", ":", 1);
@ -1121,11 +1094,11 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
opts->gpg_sign_opt = tmp;
}
status = run_sequencer_rebase(opts, action);
status = run_rebase_interactive(opts, action);
goto finished_rebase;
}
if (opts->type == REBASE_APPLY) {
if (opts->type == REBASE_AM) {
status = run_am(opts);
goto finished_rebase;
}
@ -1145,6 +1118,8 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
add_var(&script_snippet, "revisions", opts->revisions);
add_var(&script_snippet, "restrict_revision", opts->restrict_revision ?
oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
add_var(&script_snippet, "GIT_QUIET",
opts->flags & REBASE_NO_QUIET ? "" : "t");
sq_quote_argv_pretty(&buf, opts->git_am_opts.argv);
add_var(&script_snippet, "git_am_opt", buf.buf);
strbuf_release(&buf);
@ -1162,6 +1137,7 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
opts->allow_rerere_autoupdate ?
opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?
"--rerere-autoupdate" : "--no-rerere-autoupdate" : "");
add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
add_var(&script_snippet, "cmd", opts->cmd);
@ -1179,7 +1155,7 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
add_var(&script_snippet, "git_format_patch_opt",
opts->git_format_patch_opt.buf);
if (is_merge(opts) &&
if (is_interactive(opts) &&
!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
strbuf_addstr(&script_snippet,
"GIT_SEQUENCE_EDITOR=:; export GIT_SEQUENCE_EDITOR; ");
@ -1204,8 +1180,8 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
finished_rebase:
if (opts->dont_finish_rebase)
; /* do nothing */
else if (opts->type == REBASE_MERGE)
; /* merge backend cleans up after itself */
else if (opts->type == REBASE_INTERACTIVE)
; /* interactive rebase cleans up after itself */
else if (status == 0) {
if (!file_exists(state_dir_path("stopped-sha", opts)))
finish_rebase(opts);
@ -1263,10 +1239,6 @@ static int rebase_config(const char *var, const char *value, void *data)
return 0;
}
if (!strcmp(var, "rebase.backend")) {
return git_config_string(&opts->default_backend, var, value);
}
return git_default_config(var, value, data);
}
@ -1288,60 +1260,28 @@ static int is_linear_history(struct commit *from, struct commit *to)
return 1;
}
static int can_fast_forward(struct commit *onto, struct commit *upstream,
struct commit *restrict_revision,
struct object_id *head_oid, struct object_id *merge_base)
static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
struct object_id *merge_base)
{
struct commit *head = lookup_commit(the_repository, head_oid);
struct commit_list *merge_bases = NULL;
int res = 0;
struct commit_list *merge_bases;
int res;
if (!head)
goto done;
return 0;
merge_bases = get_merge_bases(onto, head);
if (!merge_bases || merge_bases->next) {
if (merge_bases && !merge_bases->next) {
oidcpy(merge_base, &merge_bases->item->object.oid);
res = oideq(merge_base, &onto->object.oid);
} else {
oidcpy(merge_base, &null_oid);
goto done;
res = 0;
}
oidcpy(merge_base, &merge_bases->item->object.oid);
if (!oideq(merge_base, &onto->object.oid))
goto done;
if (restrict_revision && !oideq(&restrict_revision->object.oid, merge_base))
goto done;
if (!upstream)
goto done;
free_commit_list(merge_bases);
merge_bases = get_merge_bases(upstream, head);
if (!merge_bases || merge_bases->next)
goto done;
if (!oideq(&onto->object.oid, &merge_bases->item->object.oid))
goto done;
res = 1;
done:
free_commit_list(merge_bases);
return res && is_linear_history(onto, head);
}
static int parse_opt_am(const struct option *opt, const char *arg, int unset)
{
struct rebase_options *opts = opt->value;
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
opts->type = REBASE_APPLY;
return 0;
}
/* -i followed by -m is still -i */
static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
{
@ -1350,7 +1290,7 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
if (!is_merge(opts))
if (!is_interactive(opts))
opts->type = REBASE_MERGE;
return 0;
@ -1365,35 +1305,12 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
opts->type = REBASE_MERGE;
opts->type = REBASE_INTERACTIVE;
opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
return 0;
}
static enum empty_type parse_empty_value(const char *value)
{
if (!strcasecmp(value, "drop"))
return EMPTY_DROP;
else if (!strcasecmp(value, "keep"))
return EMPTY_KEEP;
else if (!strcasecmp(value, "ask"))
return EMPTY_ASK;
die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value);
}
static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
{
struct rebase_options *options = opt->value;
enum empty_type value = parse_empty_value(arg);
BUG_ON_OPT_NEG(unset);
options->empty = value;
return 0;
}
static void NORETURN error_on_missing_default_upstream(void)
{
struct branch *current_branch = branch_get(NULL);
@ -1429,14 +1346,14 @@ static void set_reflog_action(struct rebase_options *options)
const char *env;
struct strbuf buf = STRBUF_INIT;
if (!is_merge(options))
if (!is_interactive(options))
return;
env = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
if (env && strcmp("rebase", env))
return; /* only override it if it is "rebase" */
strbuf_addf(&buf, "rebase (%s)", options->action);
strbuf_addf(&buf, "rebase -i (%s)", options->action);
setenv(GIT_REFLOG_ACTION_ENVIRONMENT, buf.buf, 1);
strbuf_release(&buf);
}
@ -1459,7 +1376,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct rebase_options options = REBASE_OPTIONS_INIT;
const char *branch_name;
int ret, flags, total_argc, in_progress = 0;
int keep_base = 0;
int ok_to_skip_pre_rebase = 0;
struct strbuf msg = STRBUF_INIT;
struct strbuf revisions = STRBUF_INIT;
@ -1474,18 +1390,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct object_id squash_onto;
char *squash_onto_name = NULL;
int reschedule_failed_exec = -1;
int allow_preemptive_ff = 1;
struct option builtin_rebase_options[] = {
OPT_STRING(0, "onto", &options.onto_name,
N_("revision"),
N_("rebase onto given branch instead of upstream")),
OPT_BOOL(0, "keep-base", &keep_base,
N_("use the merge-base of upstream and branch as the current base")),
OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
N_("allow pre-rebase hook to run")),
OPT_NEGBIT('q', "quiet", &options.flags,
N_("be quiet. implies --no-stat"),
REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),
OPT_BIT('v', "verbose", &options.flags,
N_("display a diffstat of what changed upstream"),
REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
@ -1526,10 +1439,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
OPT_CMDMODE(0, "show-current-patch", &action,
N_("show the patch file being applied or merged"),
ACTION_SHOW_CURRENT_PATCH),
{ OPTION_CALLBACK, 0, "apply", &options, NULL,
N_("use apply strategies to rebase"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
parse_opt_am },
{ OPTION_CALLBACK, 'm', "merge", &options, NULL,
N_("use merging strategies to rebase"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
@ -1538,18 +1447,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("let the user edit the list of commits to rebase"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
parse_opt_interactive },
OPT_SET_INT_F('p', "preserve-merges", &options.type,
N_("(DEPRECATED) try to recreate merges instead of "
"ignoring them"),
REBASE_PRESERVE_MERGES, PARSE_OPT_HIDDEN),
OPT_SET_INT('p', "preserve-merges", &options.type,
N_("(DEPRECATED) try to recreate merges instead of "
"ignoring them"), REBASE_PRESERVE_MERGES),
OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
OPT_CALLBACK_F(0, "empty", &options, "{drop,keep,ask}",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
{ OPTION_CALLBACK, 'k', "keep-empty", &options, NULL,
N_("(DEPRECATED) keep empty commits"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
parse_opt_keep_empty },
OPT_BOOL('k', "keep-empty", &options.keep_empty,
N_("preserve empty commits during rebase")),
OPT_BOOL(0, "autosquash", &options.autosquash,
N_("move commits that begin with "
"squash!/fixup! under -i")),
@ -1561,10 +1464,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
N_("add exec lines after each commit of the "
"editable list")),
OPT_BOOL_F(0, "allow-empty-message",
&options.allow_empty_message,
N_("allow rebasing commits with empty messages"),
PARSE_OPT_HIDDEN),
OPT_BOOL(0, "allow-empty-message",
&options.allow_empty_message,
N_("allow rebasing commits with empty messages")),
{OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
N_("mode"),
N_("try to rebase merges instead of skipping them"),
@ -1604,7 +1506,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("It looks like 'git am' is in progress. Cannot rebase."));
if (is_directory(apply_dir())) {
options.type = REBASE_APPLY;
options.type = REBASE_AM;
options.state_dir = apply_dir();
} else if (is_directory(merge_dir())) {
strbuf_reset(&buf);
@ -1616,7 +1518,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/interactive", merge_dir());
if(file_exists(buf.buf)) {
options.type = REBASE_MERGE;
options.type = REBASE_INTERACTIVE;
options.flags |= REBASE_INTERACTIVE_EXPLICIT;
} else
options.type = REBASE_MERGE;
@ -1645,23 +1547,16 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
warning(_("git rebase --preserve-merges is deprecated. "
"Use --rebase-merges instead."));
if (keep_base) {
if (options.onto_name)
die(_("cannot combine '--keep-base' with '--onto'"));
if (options.root)
die(_("cannot combine '--keep-base' with '--root'"));
}
if (action != ACTION_NONE && !in_progress)
die(_("No rebase in progress?"));
setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0);
if (action == ACTION_EDIT_TODO && !is_merge(&options))
if (action == ACTION_EDIT_TODO && !is_interactive(&options))
die(_("The --edit-todo action can only be used during "
"interactive rebase."));
if (trace2_is_enabled()) {
if (is_merge(&options))
if (is_interactive(&options))
trace2_cmd_mode("interactive");
else if (exec.nr)
trace2_cmd_mode("interactive-exec");
@ -1737,7 +1632,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
goto cleanup;
}
case ACTION_QUIT: {
if (options.type == REBASE_MERGE) {
if (options.type == REBASE_INTERACTIVE) {
struct replay_opts replay = REPLAY_OPTS_INIT;
replay.action = REPLAY_INTERACTIVE_REBASE;
@ -1786,20 +1681,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
(action != ACTION_NONE) ||
(exec.nr > 0) ||
options.autosquash) {
allow_preemptive_ff = 0;
}
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
if (!strcmp(option, "--committer-date-is-author-date") ||
!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
allow_preemptive_ff = 0;
options.flags |= REBASE_FORCE;
else if (skip_prefix(option, "-C", &p)) {
while (*p)
if (!isdigit(*(p++)))
@ -1819,8 +1707,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (!(options.flags & REBASE_NO_QUIET))
argv_array_push(&options.git_am_opts, "-q");
if (options.empty != EMPTY_UNSPECIFIED)
imply_merge(&options, "--empty");
if (options.keep_empty)
imply_interactive(&options, "--keep-empty");
if (gpg_sign) {
free(options.gpg_sign_opt);
@ -1830,7 +1718,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (exec.nr) {
int i;
imply_merge(&options, "--exec");
imply_interactive(&options, "--exec");
strbuf_reset(&buf);
for (i = 0; i < exec.nr; i++)
@ -1846,7 +1734,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
else if (strcmp("no-rebase-cousins", rebase_merges))
die(_("Unknown mode: %s"), rebase_merges);
options.rebase_merges = 1;
imply_merge(&options, "--rebase-merges");
imply_interactive(&options, "--rebase-merges");
}
if (strategy_options.nr) {
@ -1865,9 +1753,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.strategy) {
options.strategy = xstrdup(options.strategy);
switch (options.type) {
case REBASE_APPLY:
case REBASE_AM:
die(_("--strategy requires --merge or --interactive"));
case REBASE_MERGE:
case REBASE_INTERACTIVE:
case REBASE_PRESERVE_MERGES:
/* compatible */
break;
@ -1880,65 +1769,47 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
if (options.type == REBASE_MERGE)
imply_merge(&options, "--merge");
imply_interactive(&options, "--merge");
if (options.root && !options.onto_name)
imply_merge(&options, "--root without --onto");
imply_interactive(&options, "--root without --onto");
if (isatty(2) && options.flags & REBASE_NO_QUIET)
strbuf_addstr(&options.git_format_patch_opt, " --progress");
if (options.git_am_opts.argc || options.type == REBASE_APPLY) {
/* all am options except -q are compatible only with --apply */
for (i = options.git_am_opts.argc - 1; i >= 0; i--)
if (strcmp(options.git_am_opts.argv[i], "-q"))
break;
if (i >= 0) {
if (is_merge(&options))
die(_("cannot combine apply options with "
"merge options"));
else
options.type = REBASE_APPLY;
}
}
if (options.type == REBASE_UNSPECIFIED) {
if (!strcmp(options.default_backend, "merge"))
imply_merge(&options, "--merge");
else if (!strcmp(options.default_backend, "apply"))
options.type = REBASE_APPLY;
else
die(_("Unknown rebase backend: %s"),
options.default_backend);
}
switch (options.type) {
case REBASE_MERGE:
case REBASE_INTERACTIVE:
case REBASE_PRESERVE_MERGES:
options.state_dir = merge_dir();
break;
case REBASE_APPLY:
case REBASE_AM:
options.state_dir = apply_dir();
break;
default:
BUG("options.type was just set above; should be unreachable.");
/* the default rebase backend is `--am` */
options.type = REBASE_AM;
options.state_dir = apply_dir();
break;
}
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
options.empty = EMPTY_ASK;
else if (exec.nr > 0)
options.empty = EMPTY_KEEP;
else
options.empty = EMPTY_DROP;
}
if (reschedule_failed_exec > 0 && !is_merge(&options))
if (reschedule_failed_exec > 0 && !is_interactive(&options))
die(_("--reschedule-failed-exec requires "
"--exec or --interactive"));
if (reschedule_failed_exec >= 0)
options.reschedule_failed_exec = reschedule_failed_exec;
if (options.git_am_opts.argc) {
/* all am options except -q are compatible only with --am */
for (i = options.git_am_opts.argc - 1; i >= 0; i--)
if (strcmp(options.git_am_opts.argv[i], "-q"))
break;
if (is_interactive(&options) && i >= 0)
die(_("cannot combine am options with either "
"interactive or merge options"));
}
if (options.signoff) {
if (options.type == REBASE_PRESERVE_MERGES)
die("cannot combine '--signoff' with "
@ -1962,6 +1833,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"'--reschedule-failed-exec'"));
}
if (options.rebase_merges) {
if (strategy_options.nr)
die(_("cannot combine '--rebase-merges' with "
"'--strategy-option'"));
if (options.strategy)
die(_("cannot combine '--rebase-merges' with "
"'--strategy'"));
}
if (!options.root) {
if (argc < 1) {
struct branch *branch;
@ -1992,9 +1872,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.squash_onto = &squash_onto;
options.onto_name = squash_onto_name =
xstrdup(oid_to_hex(&squash_onto));
} else
options.root_with_onto = 1;
}
options.upstream_name = NULL;
options.upstream = NULL;
if (argc > 1)
@ -2004,22 +1882,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
/* Make sure the branch to rebase onto is valid. */
if (keep_base) {
strbuf_reset(&buf);
strbuf_addstr(&buf, options.upstream_name);
strbuf_addstr(&buf, "...");
options.onto_name = xstrdup(buf.buf);
} else if (!options.onto_name)
if (!options.onto_name)
options.onto_name = options.upstream_name;
if (strstr(options.onto_name, "...")) {
if (get_oid_mb(options.onto_name, &merge_base) < 0) {
if (keep_base)
die(_("'%s': need exactly one merge base with branch"),
options.upstream_name);
else
die(_("'%s': need exactly one merge base"),
options.onto_name);
}
if (get_oid_mb(options.onto_name, &merge_base) < 0)
die(_("'%s': need exactly one merge base"),
options.onto_name);
options.onto = lookup_commit_or_die(&merge_base,
options.onto_name);
} else {
@ -2044,11 +1912,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* Is it a local branch? */
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/heads/%s", branch_name);
if (!read_ref(buf.buf, &options.orig_head)) {
die_if_checked_out(buf.buf, 1);
if (!read_ref(buf.buf, &options.orig_head))
options.head_name = xstrdup(buf.buf);
/* If not is it a valid ref (branch or commit)? */
} else if (!get_oid(branch_name, &options.orig_head))
else if (!get_oid(branch_name, &options.orig_head))
options.head_name = NULL;
else
die(_("fatal: no such branch/commit '%s'"),
@ -2101,6 +1968,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
state_dir_path("autostash", &options);
struct child_process stash = CHILD_PROCESS_INIT;
struct object_id oid;
struct commit *head =
lookup_commit_reference(the_repository,
&options.orig_head);
argv_array_pushl(&stash.args,
"stash", "create", "autostash", NULL);
@ -2121,9 +1991,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.state_dir);
write_file(autostash, "%s", oid_to_hex(&oid));
printf(_("Created autostash: %s\n"), buf.buf);
if (reset_head(NULL, "reset --hard",
if (reset_head(&head->object.oid, "reset --hard",
NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
die(_("could not reset --hard"));
printf(_("HEAD is now at %s"),
find_unique_abbrev(&head->object.oid,
DEFAULT_ABBREV));
strbuf_reset(&buf);
pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
if (buf.len > 0)
printf(" %s", buf.buf);
putchar('\n');
if (discard_index(the_repository->index) < 0 ||
repo_read_index(the_repository) < 0)
@ -2144,25 +2022,31 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/*
* Check if we are already based on onto with linear history,
* in which case we could fast-forward without replacing the commits
* with new commits recreated by replaying their changes.
*
* Note that can_fast_forward() initializes merge_base, so we have to
* call it before checking allow_preemptive_ff.
* but this should be done only when upstream and onto are the same
* and if this is not an interactive rebase.
*/
if (can_fast_forward(options.onto, options.upstream, options.restrict_revision,
&options.orig_head, &merge_base) &&
allow_preemptive_ff) {
if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
!is_interactive(&options) && !options.restrict_revision &&
options.upstream &&
!oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
int flag;
if (!(options.flags & REBASE_FORCE)) {
/* Lazily switch to the target branch if needed... */
if (options.switch_to) {
struct object_id oid;
if (get_oid(options.switch_to, &oid) < 0) {
ret = !!error(_("could not parse '%s'"),
options.switch_to);
goto cleanup;
}
strbuf_reset(&buf);
strbuf_addf(&buf, "%s: checkout %s",
getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
options.switch_to);
if (reset_head(&options.orig_head, "checkout",
if (reset_head(&oid, "checkout",
options.head_name,
RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
NULL, buf.buf) < 0) {
@ -2227,7 +2111,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
diff_flush(&opts);
}
if (is_merge(&options))
if (is_interactive(&options))
goto run_rebase;
/* Detach HEAD and reset the tree */

View file

@ -27,7 +27,6 @@
#include "object-store.h"
#include "protocol.h"
#include "commit-reach.h"
#include "worktree.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@ -418,22 +417,24 @@ static int copy_to_sideband(int in, int out, void *arg)
return 0;
}
static void hmac(unsigned char *out,
#define HMAC_BLOCK_SIZE 64
static void hmac_sha1(unsigned char *out,
const char *key_in, size_t key_len,
const char *text, size_t text_len)
{
unsigned char key[GIT_MAX_BLKSZ];
unsigned char k_ipad[GIT_MAX_BLKSZ];
unsigned char k_opad[GIT_MAX_BLKSZ];
unsigned char key[HMAC_BLOCK_SIZE];
unsigned char k_ipad[HMAC_BLOCK_SIZE];
unsigned char k_opad[HMAC_BLOCK_SIZE];
int i;
git_hash_ctx ctx;
git_SHA_CTX ctx;
/* RFC 2104 2. (1) */
memset(key, '\0', GIT_MAX_BLKSZ);
if (the_hash_algo->blksz < key_len) {
the_hash_algo->init_fn(&ctx);
the_hash_algo->update_fn(&ctx, key_in, key_len);
the_hash_algo->final_fn(key, &ctx);
memset(key, '\0', HMAC_BLOCK_SIZE);
if (HMAC_BLOCK_SIZE < key_len) {
git_SHA1_Init(&ctx);
git_SHA1_Update(&ctx, key_in, key_len);
git_SHA1_Final(key, &ctx);
} else {
memcpy(key, key_in, key_len);
}
@ -445,29 +446,29 @@ static void hmac(unsigned char *out,
}
/* RFC 2104 2. (3) & (4) */
the_hash_algo->init_fn(&ctx);
the_hash_algo->update_fn(&ctx, k_ipad, sizeof(k_ipad));
the_hash_algo->update_fn(&ctx, text, text_len);
the_hash_algo->final_fn(out, &ctx);
git_SHA1_Init(&ctx);
git_SHA1_Update(&ctx, k_ipad, sizeof(k_ipad));
git_SHA1_Update(&ctx, text, text_len);
git_SHA1_Final(out, &ctx);
/* RFC 2104 2. (6) & (7) */
the_hash_algo->init_fn(&ctx);
the_hash_algo->update_fn(&ctx, k_opad, sizeof(k_opad));
the_hash_algo->update_fn(&ctx, out, the_hash_algo->rawsz);
the_hash_algo->final_fn(out, &ctx);
git_SHA1_Init(&ctx);
git_SHA1_Update(&ctx, k_opad, sizeof(k_opad));
git_SHA1_Update(&ctx, out, GIT_SHA1_RAWSZ);
git_SHA1_Final(out, &ctx);
}
static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
{
struct strbuf buf = STRBUF_INIT;
unsigned char hash[GIT_MAX_RAWSZ];
unsigned char sha1[GIT_SHA1_RAWSZ];
strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
hmac(hash, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
strbuf_release(&buf);
/* RFC 2104 5. HMAC-SHA1-80 */
strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, (int)the_hash_algo->hexsz, hash_to_hex(hash));
strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, GIT_SHA1_HEXSZ, sha1_to_hex(sha1));
return strbuf_detach(&buf, NULL);
}
@ -817,6 +818,16 @@ static int run_update_hook(struct command *cmd)
return finish_command(&proc);
}
static int is_ref_checked_out(const char *ref)
{
if (is_bare_repository())
return 0;
if (!head_name)
return 0;
return !strcmp(head_name, ref);
}
static char *refuse_unconfigured_deny_msg =
N_("By default, updating the current branch in a non-bare repository\n"
"is denied, because it will make the index and work tree inconsistent\n"
@ -959,7 +970,7 @@ static const char *push_to_deploy(unsigned char *sha1,
if (run_command(&child))
return "Working directory has staged changes";
read_tree[3] = hash_to_hex(sha1);
read_tree[3] = sha1_to_hex(sha1);
child_process_init(&child);
child.argv = read_tree;
child.env = env->argv;
@ -976,38 +987,28 @@ static const char *push_to_deploy(unsigned char *sha1,
static const char *push_to_checkout_hook = "push-to-checkout";
static const char *push_to_checkout(unsigned char *hash,
static const char *push_to_checkout(unsigned char *sha1,
struct argv_array *env,
const char *work_tree)
{
argv_array_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
if (run_hook_le(env->argv, push_to_checkout_hook,
hash_to_hex(hash), NULL))
sha1_to_hex(sha1), NULL))
return "push-to-checkout hook declined";
else
return NULL;
}
static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
static const char *update_worktree(unsigned char *sha1)
{
const char *retval, *work_tree, *git_dir = NULL;
const char *retval;
const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
struct argv_array env = ARGV_ARRAY_INIT;
if (worktree && worktree->path)
work_tree = worktree->path;
else if (git_work_tree_cfg)
work_tree = git_work_tree_cfg;
else
work_tree = "..";
if (is_bare_repository())
return "denyCurrentBranch = updateInstead needs a worktree";
if (worktree)
git_dir = get_worktree_git_dir(worktree);
if (!git_dir)
git_dir = get_git_dir();
argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
if (!find_hook(push_to_checkout_hook))
retval = push_to_deploy(sha1, &env, work_tree);
@ -1027,7 +1028,6 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct object_id *old_oid = &cmd->old_oid;
struct object_id *new_oid = &cmd->new_oid;
int do_update_worktree = 0;
const struct worktree *worktree = is_bare_repository() ? NULL : find_shared_symref("HEAD", name);
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@ -1039,7 +1039,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
free(namespaced_name);
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
if (worktree) {
if (is_ref_checked_out(namespaced_name)) {
switch (deny_current_branch) {
case DENY_IGNORE:
break;
@ -1071,7 +1071,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
return "deletion prohibited";
}
if (worktree || (head_name && !strcmp(namespaced_name, head_name))) {
if (head_name && !strcmp(namespaced_name, head_name)) {
switch (deny_delete_current) {
case DENY_IGNORE:
break;
@ -1120,7 +1120,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (do_update_worktree) {
ret = update_worktree(new_oid->hash, find_shared_symref("HEAD", name));
ret = update_worktree(new_oid->hash);
if (ret)
return ret;
}

View file

@ -560,16 +560,15 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
flags |= EXPIRE_REFLOGS_DRY_RUN;
else if (skip_prefix(arg, "--expire=", &arg)) {
if (parse_expiry_date(arg, &cb.cmd.expire_total))
else if (starts_with(arg, "--expire=")) {
if (parse_expiry_date(arg + 9, &cb.cmd.expire_total))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_TOTAL;
}
else if (skip_prefix(arg, "--expire-unreachable=", &arg)) {
if (parse_expiry_date(arg, &cb.cmd.expire_unreachable))
else if (starts_with(arg, "--expire-unreachable=")) {
if (parse_expiry_date(arg + 21, &cb.cmd.expire_unreachable))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_UNREACH;
}

View file

@ -6,7 +6,6 @@
#include "string-list.h"
#include "strbuf.h"
#include "run-command.h"
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
#include "object-store.h"
@ -249,8 +248,9 @@ static int add(int argc, const char **argv)
struct branch_info {
char *remote_name;
struct string_list merge;
enum rebase_type rebase;
char *push_remote_name;
enum {
NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES
} rebase;
};
static struct string_list branch_list = STRING_LIST_INIT_NODUP;
@ -264,69 +264,59 @@ static const char *abbrev_ref(const char *name, const char *prefix)
static int config_read_branches(const char *key, const char *value, void *cb)
{
const char *orig_key = key;
char *name;
struct string_list_item *item;
struct branch_info *info;
enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
size_t key_len;
if (starts_with(key, "branch.")) {
const char *orig_key = key;
char *name;
struct string_list_item *item;
struct branch_info *info;
enum { REMOTE, MERGE, REBASE } type;
size_t key_len;
if (!starts_with(key, "branch."))
return 0;
key += 7;
if (strip_suffix(key, ".remote", &key_len)) {
name = xmemdupz(key, key_len);
type = REMOTE;
} else if (strip_suffix(key, ".merge", &key_len)) {
name = xmemdupz(key, key_len);
type = MERGE;
} else if (strip_suffix(key, ".rebase", &key_len)) {
name = xmemdupz(key, key_len);
type = REBASE;
} else
return 0;
key += strlen("branch.");
if (strip_suffix(key, ".remote", &key_len))
type = REMOTE;
else if (strip_suffix(key, ".merge", &key_len))
type = MERGE;
else if (strip_suffix(key, ".rebase", &key_len))
type = REBASE;
else if (strip_suffix(key, ".pushremote", &key_len))
type = PUSH_REMOTE;
else
return 0;
name = xmemdupz(key, key_len);
item = string_list_insert(&branch_list, name);
item = string_list_insert(&branch_list, name);
if (!item->util)
item->util = xcalloc(1, sizeof(struct branch_info));
info = item->util;
switch (type) {
case REMOTE:
if (info->remote_name)
warning(_("more than one %s"), orig_key);
info->remote_name = xstrdup(value);
break;
case MERGE: {
char *space = strchr(value, ' ');
value = abbrev_branch(value);
while (space) {
char *merge;
merge = xstrndup(value, space - value);
string_list_append(&info->merge, merge);
value = abbrev_branch(space + 1);
space = strchr(value, ' ');
if (!item->util)
item->util = xcalloc(1, sizeof(struct branch_info));
info = item->util;
if (type == REMOTE) {
if (info->remote_name)
warning(_("more than one %s"), orig_key);
info->remote_name = xstrdup(value);
} else if (type == MERGE) {
char *space = strchr(value, ' ');
value = abbrev_branch(value);
while (space) {
char *merge;
merge = xstrndup(value, space - value);
string_list_append(&info->merge, merge);
value = abbrev_branch(space + 1);
space = strchr(value, ' ');
}
string_list_append(&info->merge, xstrdup(value));
} else {
int v = git_parse_maybe_bool(value);
if (v >= 0)
info->rebase = v;
else if (!strcmp(value, "preserve"))
info->rebase = NORMAL_REBASE;
else if (!strcmp(value, "merges"))
info->rebase = REBASE_MERGES;
else if (!strcmp(value, "interactive"))
info->rebase = INTERACTIVE_REBASE;
}
string_list_append(&info->merge, xstrdup(value));
break;
}
case REBASE:
/*
* Consider invalid values as false and check the
* truth value with >= REBASE_TRUE.
*/
info->rebase = rebase_parse_value(value);
break;
case PUSH_REMOTE:
if (info->push_remote_name)
warning(_("more than one %s"), orig_key);
info->push_remote_name = xstrdup(value);
break;
default:
BUG("unexpected type=%d", type);
}
return 0;
}
@ -615,56 +605,6 @@ static int migrate_file(struct remote *remote)
return 0;
}
struct push_default_info
{
const char *old_name;
enum config_scope scope;
struct strbuf origin;
int linenr;
};
static int config_read_push_default(const char *key, const char *value,
void *cb)
{
struct push_default_info* info = cb;
if (strcmp(key, "remote.pushdefault") ||
!value || strcmp(value, info->old_name))
return 0;
info->scope = current_config_scope();
strbuf_reset(&info->origin);
strbuf_addstr(&info->origin, current_config_name());
info->linenr = current_config_line();
return 0;
}
static void handle_push_default(const char* old_name, const char* new_name)
{
struct push_default_info push_default = {
old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };
git_config(config_read_push_default, &push_default);
if (push_default.scope >= CONFIG_SCOPE_COMMAND)
; /* pass */
else if (push_default.scope >= CONFIG_SCOPE_LOCAL) {
int result = git_config_set_gently("remote.pushDefault",
new_name);
if (new_name && result && result != CONFIG_NOTHING_SET)
die(_("could not set '%s'"), "remote.pushDefault");
else if (!new_name && result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), "remote.pushDefault");
} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {
/* warn */
warning(_("The %s configuration remote.pushDefault in:\n"
"\t%s:%d\n"
"now names the non-existent remote '%s'"),
config_scope_name(push_default.scope),
push_default.origin.buf, push_default.linenr,
old_name);
}
}
static int mv(int argc, const char **argv)
{
struct option options[] = {
@ -740,11 +680,6 @@ static int mv(int argc, const char **argv)
strbuf_addf(&buf, "branch.%s.remote", item->string);
git_config_set(buf.buf, rename.new_name);
}
if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushremote", item->string);
git_config_set(buf.buf, rename.new_name);
}
}
if (!refspec_updated)
@ -758,8 +693,9 @@ static int mv(int argc, const char **argv)
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
int flag = 0;
struct object_id oid;
read_ref_full(item->string, RESOLVE_REF_READING, NULL, &flag);
read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
if (!(flag & REF_ISSYMREF))
continue;
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
@ -800,9 +736,6 @@ static int mv(int argc, const char **argv)
die(_("creating '%s' failed"), buf.buf);
}
string_list_clear(&remote_branches, 1);
handle_push_default(rename.old_name, rename.new_name);
return 0;
}
@ -849,13 +782,6 @@ static int rm(int argc, const char **argv)
die(_("could not unset '%s'"), buf.buf);
}
}
if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushremote", item->string);
result = git_config_set_gently(buf.buf, NULL);
if (result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), buf.buf);
}
}
/*
@ -888,8 +814,6 @@ static int rm(int argc, const char **argv)
strbuf_addf(&buf, "remote.%s", remote->name);
if (git_config_rename_section(buf.buf, NULL) < 1)
return error(_("Could not remove config section '%s'"), buf.buf);
handle_push_default(remote->name, NULL);
}
return result;
@ -1020,7 +944,7 @@ static int add_local_to_show_info(struct string_list_item *branch_item, void *cb
return 0;
if ((n = strlen(branch_item->string)) > show_info->width)
show_info->width = n;
if (branch_info->rebase >= REBASE_TRUE)
if (branch_info->rebase)
show_info->any_rebase = 1;
item = string_list_insert(show_info->list, branch_item->string);
@ -1037,16 +961,16 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
int width = show_info->width + 4;
int i;
if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
if (branch_info->rebase && branch_info->merge.nr > 1) {
error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
item->string);
return 0;
}
printf(" %-*s ", show_info->width, item->string);
if (branch_info->rebase >= REBASE_TRUE) {
if (branch_info->rebase) {
const char *msg;
if (branch_info->rebase == REBASE_INTERACTIVE)
if (branch_info->rebase == INTERACTIVE_REBASE)
msg = _("rebases interactively onto remote %s");
else if (branch_info->rebase == REBASE_MERGES)
msg = _("rebases interactively (with merges) onto "

View file

@ -11,7 +11,6 @@
#include "midx.h"
#include "packfile.h"
#include "object-store.h"
#include "promisor-remote.h"
static int delta_base_offset = 1;
static int pack_kept_objects = -1;
@ -191,7 +190,7 @@ static int write_oid(const struct object_id *oid, struct packed_git *pack,
die(_("could not start pack-objects to repack promisor objects"));
}
xwrite(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz);
xwrite(cmd->in, oid_to_hex(oid), GIT_SHA1_HEXSZ);
xwrite(cmd->in, "\n", 1);
return 0;
}
@ -233,13 +232,6 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
/*
* pack-objects creates the .pack and .idx files, but not the
* .promisor file. Create the .promisor file, which is empty.
*
* NEEDSWORK: fetch-pack sometimes generates non-empty
* .promisor files containing the ref names and associated
* hashes at the point of generation of the corresponding
* packfile, but this would not preserve their contents. Maybe
* concatenate the contents of all .promisor files instead of
* just creating a new empty file.
*/
promisor_name = mkpathdup("%s-%s.promisor", packtmp,
line.buf);
@ -369,7 +361,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd.args, "--all");
argv_array_push(&cmd.args, "--reflog");
argv_array_push(&cmd.args, "--indexed-objects");
if (has_promisor_remote())
if (repository_format_partial_clone)
argv_array_push(&cmd.args, "--exclude-promisor-objects");
if (write_bitmaps > 0)
argv_array_push(&cmd.args, "--write-bitmap-index");
@ -569,7 +561,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
remove_temporary_files();
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0))
write_midx_file(get_object_directory(), 0);
write_midx_file(get_object_directory());
string_list_clear(&names, 0);
string_list_clear(&rollback, 0);

View file

@ -272,7 +272,7 @@ static int import_object(struct object_id *oid, enum object_type type,
return error(_("unable to spawn mktree"));
}
if (strbuf_read(&result, cmd.out, the_hash_algo->hexsz + 1) < 0) {
if (strbuf_read(&result, cmd.out, 41) < 0) {
error_errno(_("unable to read from mktree"));
close(fd);
close(cmd.out);
@ -358,15 +358,14 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
struct strbuf new_parents = STRBUF_INIT;
const char *parent_start, *parent_end;
int i;
const unsigned hexsz = the_hash_algo->hexsz;
/* find existing parents */
parent_start = buf->buf;
parent_start += hexsz + 6; /* "tree " + "hex sha1" + "\n" */
parent_start += GIT_SHA1_HEXSZ + 6; /* "tree " + "hex sha1" + "\n" */
parent_end = parent_start;
while (starts_with(parent_end, "parent "))
parent_end += hexsz + 8; /* "parent " + "hex sha1" + "\n" */
parent_end += 48; /* "parent " + "hex sha1" + "\n" */
/* prepare new parents */
for (i = 0; i < argc; i++) {
@ -409,8 +408,7 @@ static int check_one_mergetag(struct commit *commit,
struct tag *tag;
int i;
hash_object_file(the_hash_algo, extra->value, extra->len,
type_name(OBJ_TAG), &tag_oid);
hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
tag = lookup_tag(the_repository, &tag_oid);
if (!tag)
return error(_("bad mergetag in commit '%s'"), ref);
@ -423,7 +421,7 @@ static int check_one_mergetag(struct commit *commit,
if (get_oid(mergetag_data->argv[i], &oid) < 0)
return error(_("not a valid object name: '%s'"),
mergetag_data->argv[i]);
if (oideq(get_tagged_oid(tag), &oid))
if (oideq(&tag->tagged->oid, &oid))
return 0; /* found */
}

View file

@ -30,9 +30,8 @@
static const char * const git_reset_usage[] = {
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
N_("git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"),
N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
NULL
};
@ -285,8 +284,8 @@ static int git_reset_config(const char *var, const char *value, void *cb)
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
int patch_mode = 0, pathspec_file_nul = 0, unborn;
const char *rev, *pathspec_from_file = NULL;
int patch_mode = 0, unborn;
const char *rev;
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
@ -307,8 +306,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_BOOL('N', "intent-to-add", &intent_to_add,
N_("record only the fact that removed paths will be added later")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END()
};
@ -319,25 +316,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH);
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
if (pathspec_from_file) {
if (patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_FULL,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
oidcpy(&oid, the_hash_algo->empty_tree);
} else if (!pathspec.nr && !patch_mode) {
} else if (!pathspec.nr) {
struct commit *commit;
if (get_oid_committish(rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);

View file

@ -18,6 +18,7 @@
#include "reflog-walk.h"
#include "oidset.h"
#include "packfile.h"
#include "object-store.h"
static const char rev_list_usage[] =
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@ -253,26 +254,11 @@ static int finish_object(struct object *obj, const char *name, void *cb_data)
static void show_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
struct rev_info *revs = info->revs;
if (finish_object(obj, name, cb_data))
return;
display_progress(progress, ++progress_counter);
if (info->flags & REV_LIST_QUIET)
return;
if (revs->count) {
/*
* The object count is always accumulated in the .count_right
* field for traversal that is not a left-right traversal,
* and cmd_rev_list() made sure that a .count request that
* wants to count non-commit objects, which is handled by
* the show_object() callback, does not ask for .left_right.
*/
revs->count_right++;
return;
}
if (arg_show_object_names)
show_object_with_name(stdout, obj, name);
else
@ -379,79 +365,6 @@ static inline int parse_missing_action_value(const char *value)
return 0;
}
static int try_bitmap_count(struct rev_info *revs,
struct list_objects_filter_options *filter)
{
uint32_t commit_count = 0,
tag_count = 0,
tree_count = 0,
blob_count = 0;
int max_count;
struct bitmap_index *bitmap_git;
/* This function only handles counting, not general traversal. */
if (!revs->count)
return -1;
/*
* A bitmap result can't know left/right, etc, because we don't
* actually traverse.
*/
if (revs->left_right || revs->cherry_mark)
return -1;
/*
* If we're counting reachable objects, we can't handle a max count of
* commits to traverse, since we don't know which objects go with which
* commit.
*/
if (revs->max_count >= 0 &&
(revs->tag_objects || revs->tree_objects || revs->blob_objects))
return -1;
/*
* This must be saved before doing any walking, since the revision
* machinery will count it down to zero while traversing.
*/
max_count = revs->max_count;
bitmap_git = prepare_bitmap_walk(revs, filter);
if (!bitmap_git)
return -1;
count_bitmap_commit_list(bitmap_git, &commit_count,
revs->tree_objects ? &tree_count : NULL,
revs->blob_objects ? &blob_count : NULL,
revs->tag_objects ? &tag_count : NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;
printf("%d\n", commit_count + tree_count + blob_count + tag_count);
free_bitmap_index(bitmap_git);
return 0;
}
static int try_bitmap_traversal(struct rev_info *revs,
struct list_objects_filter_options *filter)
{
struct bitmap_index *bitmap_git;
/*
* We can't use a bitmap result with a traversal limit, since the set
* of commits we'd get would be essentially random.
*/
if (revs->max_count >= 0)
return -1;
bitmap_git = prepare_bitmap_walk(revs, filter);
if (!bitmap_git)
return -1;
traverse_bitmap_commit_list(bitmap_git, revs, &show_object_fast);
free_bitmap_index(bitmap_git);
return 0;
}
int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@ -558,6 +471,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
parse_list_objects_filter(&filter_options, arg);
if (filter_options.choice && !revs.blob_objects)
die(_("object filtering requires --objects"));
if (filter_options.choice == LOFC_SPARSE_OID &&
!filter_options.sparse_oid_value)
die(_("invalid sparse value '%s'"),
filter_options.filter_spec);
continue;
}
if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
@ -609,10 +526,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.show_notes)
die(_("rev-list does not support display of notes"));
if (revs.count &&
(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
(revs.left_right || revs.cherry_mark))
die(_("marked counting is incompatible with --objects"));
if (filter_options.choice && use_bitmap_index)
die(_("cannot combine --use-bitmap-index with object filtering"));
save_commit_buffer = (revs.verbose_header ||
revs.grep_filter.pattern_list ||
@ -623,11 +538,28 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (show_progress)
progress = start_delayed_progress(show_progress, 0);
if (use_bitmap_index) {
if (!try_bitmap_count(&revs, &filter_options))
return 0;
if (!try_bitmap_traversal(&revs, &filter_options))
return 0;
if (use_bitmap_index && !revs.prune) {
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
int max_count = revs.max_count;
struct bitmap_index *bitmap_git;
if ((bitmap_git = prepare_bitmap_walk(&revs))) {
count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;
printf("%d\n", commit_count);
free_bitmap_index(bitmap_git);
return 0;
}
} else if (revs.max_count < 0 &&
revs.tag_objects && revs.tree_objects && revs.blob_objects) {
struct bitmap_index *bitmap_git;
if ((bitmap_git = prepare_bitmap_walk(&revs))) {
traverse_bitmap_commit_list(bitmap_git, &show_object_fast);
free_bitmap_index(bitmap_git);
return 0;
}
}
}
if (prepare_revision_walk(&revs))

View file

@ -593,7 +593,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *name = NULL;
struct object_context unused;
struct strbuf buf = STRBUF_INIT;
const int hexsz = the_hash_algo->hexsz;
if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix);
@ -731,8 +730,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
abbrev = strtoul(arg, NULL, 10);
if (abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
else if (hexsz <= abbrev)
abbrev = hexsz;
else if (40 <= abbrev)
abbrev = 40;
continue;
}
if (!strcmp(arg, "--sq")) {
@ -803,8 +802,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *work_tree = get_git_work_tree();
if (work_tree)
puts(work_tree);
else
die("this operation must be run in a work tree");
continue;
}
if (!strcmp(arg, "--show-superproject-working-tree")) {
@ -921,17 +918,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
show_datestring("--min-age=", arg);
continue;
}
if (opt_with_value(arg, "--show-object-format", &arg)) {
const char *val = arg ? arg : "storage";
if (strcmp(val, "storage") &&
strcmp(val, "input") &&
strcmp(val, "output"))
die("unknown mode for --show-object-format: %s",
arg);
puts(the_hash_algo->name);
continue;
}
if (show_flag(arg) && verify)
die_no_single_rev(quiet);
continue;

View file

@ -235,8 +235,7 @@ static int check_local_mod(struct object_id *head, int index_only)
}
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
static int ignore_unmatch = 0, pathspec_file_nul;
static char *pathspec_from_file;
static int ignore_unmatch = 0;
static struct option builtin_rm_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
@ -246,8 +245,6 @@ static struct option builtin_rm_options[] = {
OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
N_("exit with a zero status even if nothing matched")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(),
};
@ -262,24 +259,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_rm_options,
builtin_rm_usage, 0);
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, argv);
if (pathspec_from_file) {
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (!pathspec.nr)
die(_("No pathspec was given. Which files should I remove?"));
if (!argc)
usage_with_options(builtin_rm_usage, builtin_rm_options);
if (!index_only)
setup_work_tree();
@ -289,6 +270,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die(_("index file corrupt"));
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
prefix, argv);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
seen = xcalloc(pathspec.nr, 1);

View file

@ -536,7 +536,7 @@ static void append_one_rev(const char *av)
append_ref(av, &revkey, 0);
return;
}
if (strpbrk(av, "*?[")) {
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
/* glob style match */
int saved_matches = ref_name_cnt;

View file

@ -11,7 +11,6 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
unsigned nr;
unsigned int version;
static unsigned int top_index[256];
const unsigned hashsz = the_hash_algo->rawsz;
if (argc != 1)
usage(show_index_usage);
@ -37,23 +36,23 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
}
if (version == 1) {
for (i = 0; i < nr; i++) {
unsigned int offset, entry[(GIT_MAX_RAWSZ + 4) / sizeof(unsigned int)];
unsigned int offset, entry[6];
if (fread(entry, 4 + hashsz, 1, stdin) != 1)
if (fread(entry, 4 + 20, 1, stdin) != 1)
die("unable to read entry %u/%u", i, nr);
offset = ntohl(entry[0]);
printf("%u %s\n", offset, hash_to_hex((void *)(entry+1)));
printf("%u %s\n", offset, sha1_to_hex((void *)(entry+1)));
}
} else {
unsigned off64_nr = 0;
struct {
struct object_id oid;
unsigned char sha1[20];
uint32_t crc;
uint32_t off;
} *entries;
ALLOC_ARRAY(entries, nr);
for (i = 0; i < nr; i++)
if (fread(entries[i].oid.hash, hashsz, 1, stdin) != 1)
if (fread(entries[i].sha1, 20, 1, stdin) != 1)
die("unable to read sha1 %u/%u", i, nr);
for (i = 0; i < nr; i++)
if (fread(&entries[i].crc, 4, 1, stdin) != 1)
@ -78,7 +77,7 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
}
printf("%" PRIuMAX " %s (%08"PRIx32")\n",
(uintmax_t) offset,
oid_to_hex(&entries[i].oid),
sha1_to_hex(entries[i].sha1),
ntohl(entries[i].crc));
}
free(entries);

View file

@ -1,631 +0,0 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
#include "parse-options.h"
#include "pathspec.h"
#include "repository.h"
#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
#include "cache.h"
#include "cache-tree.h"
#include "lockfile.h"
#include "resolve-undo.h"
#include "unpack-trees.h"
#include "wt-status.h"
#include "quote.h"
static const char *empty_base = "";
static char const * const builtin_sparse_checkout_usage[] = {
N_("git sparse-checkout (init|list|set|add|disable) <options>"),
NULL
};
static char *get_sparse_checkout_filename(void)
{
return git_pathdup("info/sparse-checkout");
}
static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
{
int i;
for (i = 0; i < pl->nr; i++) {
struct path_pattern *p = pl->patterns[i];
if (p->flags & PATTERN_FLAG_NEGATIVE)
fprintf(fp, "!");
fprintf(fp, "%s", p->pattern);
if (p->flags & PATTERN_FLAG_MUSTBEDIR)
fprintf(fp, "/");
fprintf(fp, "\n");
}
}
static int sparse_checkout_list(int argc, const char **argv)
{
struct pattern_list pl;
char *sparse_filename;
int res;
memset(&pl, 0, sizeof(pl));
pl.use_cone_patterns = core_sparse_checkout_cone;
sparse_filename = get_sparse_checkout_filename();
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
free(sparse_filename);
if (res < 0) {
warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
return 0;
}
if (pl.use_cone_patterns) {
int i;
struct pattern_entry *pe;
struct hashmap_iter iter;
struct string_list sl = STRING_LIST_INIT_DUP;
hashmap_for_each_entry(&pl.recursive_hashmap, &iter, pe, ent) {
/* pe->pattern starts with "/", skip it */
string_list_insert(&sl, pe->pattern + 1);
}
string_list_sort(&sl);
for (i = 0; i < sl.nr; i++) {
quote_c_style(sl.items[i].string, NULL, stdout, 0);
printf("\n");
}
return 0;
}
write_patterns_to_file(stdout, &pl);
clear_pattern_list(&pl);
return 0;
}
static int update_working_directory(struct pattern_list *pl)
{
int result = 0;
struct unpack_trees_options o;
struct lock_file lock_file = LOCK_INIT;
struct object_id oid;
struct tree *tree;
struct tree_desc t;
struct repository *r = the_repository;
if (repo_read_index_unmerged(r))
die(_("you need to resolve your current index first"));
if (get_oid("HEAD", &oid))
return 0;
tree = parse_tree_indirect(&oid);
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
memset(&o, 0, sizeof(o));
o.verbose_update = isatty(2);
o.merge = 1;
o.update = 1;
o.fn = oneway_merge;
o.head_idx = -1;
o.src_index = r->index;
o.dst_index = r->index;
o.skip_sparse_checkout = 0;
o.pl = pl;
o.keep_pattern_list = !!pl;
resolve_undo_clear_index(r->index);
setup_work_tree();
cache_tree_free(&r->index->cache_tree);
repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
core_apply_sparse_checkout = 1;
result = unpack_trees(1, &t, &o);
if (!result) {
prime_cache_tree(r, r->index, tree);
write_locked_index(r->index, &lock_file, COMMIT_LOCK);
} else
rollback_lock_file(&lock_file);
return result;
}
static char *escaped_pattern(char *pattern)
{
char *p = pattern;
struct strbuf final = STRBUF_INIT;
while (*p) {
if (is_glob_special(*p))
strbuf_addch(&final, '\\');
strbuf_addch(&final, *p);
p++;
}
return strbuf_detach(&final, NULL);
}
static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
{
int i;
struct pattern_entry *pe;
struct hashmap_iter iter;
struct string_list sl = STRING_LIST_INIT_DUP;
struct strbuf parent_pattern = STRBUF_INIT;
hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
continue;
if (!hashmap_contains_parent(&pl->recursive_hashmap,
pe->pattern,
&parent_pattern))
string_list_insert(&sl, pe->pattern);
}
string_list_sort(&sl);
string_list_remove_duplicates(&sl, 0);
fprintf(fp, "/*\n!/*/\n");
for (i = 0; i < sl.nr; i++) {
char *pattern = escaped_pattern(sl.items[i].string);
if (strlen(pattern))
fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
free(pattern);
}
string_list_clear(&sl, 0);
hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
if (!hashmap_contains_parent(&pl->recursive_hashmap,
pe->pattern,
&parent_pattern))
string_list_insert(&sl, pe->pattern);
}
strbuf_release(&parent_pattern);
string_list_sort(&sl);
string_list_remove_duplicates(&sl, 0);
for (i = 0; i < sl.nr; i++) {
char *pattern = escaped_pattern(sl.items[i].string);
fprintf(fp, "%s/\n", pattern);
free(pattern);
}
}
static int write_patterns_and_update(struct pattern_list *pl)
{
char *sparse_filename;
FILE *fp;
int fd;
struct lock_file lk = LOCK_INIT;
int result;
sparse_filename = get_sparse_checkout_filename();
if (safe_create_leading_directories(sparse_filename))
die(_("failed to create directory for sparse-checkout file"));
fd = hold_lock_file_for_update(&lk, sparse_filename,
LOCK_DIE_ON_ERROR);
result = update_working_directory(pl);
if (result) {
rollback_lock_file(&lk);
free(sparse_filename);
clear_pattern_list(pl);
update_working_directory(NULL);
return result;
}
fp = xfdopen(fd, "w");
if (core_sparse_checkout_cone)
write_cone_to_file(fp, pl);
else
write_patterns_to_file(fp, pl);
fflush(fp);
commit_lock_file(&lk);
free(sparse_filename);
clear_pattern_list(pl);
return 0;
}
enum sparse_checkout_mode {
MODE_NO_PATTERNS = 0,
MODE_ALL_PATTERNS = 1,
MODE_CONE_PATTERNS = 2,
};
static int set_config(enum sparse_checkout_mode mode)
{
const char *config_path;
if (git_config_set_gently("extensions.worktreeConfig", "true")) {
error(_("failed to set extensions.worktreeConfig setting"));
return 1;
}
config_path = git_path("config.worktree");
git_config_set_in_file_gently(config_path,
"core.sparseCheckout",
mode ? "true" : NULL);
git_config_set_in_file_gently(config_path,
"core.sparseCheckoutCone",
mode == MODE_CONE_PATTERNS ? "true" : NULL);
return 0;
}
static char const * const builtin_sparse_checkout_init_usage[] = {
N_("git sparse-checkout init [--cone]"),
NULL
};
static struct sparse_checkout_init_opts {
int cone_mode;
} init_opts;
static int sparse_checkout_init(int argc, const char **argv)
{
struct pattern_list pl;
char *sparse_filename;
int res;
struct object_id oid;
int mode;
struct strbuf pattern = STRBUF_INIT;
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
N_("initialize the sparse-checkout in cone mode")),
OPT_END(),
};
repo_read_index(the_repository);
require_clean_work_tree(the_repository,
N_("initialize sparse-checkout"), NULL, 1, 0);
argc = parse_options(argc, argv, NULL,
builtin_sparse_checkout_init_options,
builtin_sparse_checkout_init_usage, 0);
if (init_opts.cone_mode) {
mode = MODE_CONE_PATTERNS;
core_sparse_checkout_cone = 1;
} else
mode = MODE_ALL_PATTERNS;
if (set_config(mode))
return 1;
memset(&pl, 0, sizeof(pl));
sparse_filename = get_sparse_checkout_filename();
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
core_apply_sparse_checkout = 1;
return update_working_directory(NULL);
}
if (get_oid("HEAD", &oid)) {
FILE *fp;
/* assume we are in a fresh repo, but update the sparse-checkout file */
fp = xfopen(sparse_filename, "w");
if (!fp)
die(_("failed to open '%s'"), sparse_filename);
free(sparse_filename);
fprintf(fp, "/*\n!/*/\n");
fclose(fp);
return 0;
}
strbuf_addstr(&pattern, "/*");
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
strbuf_addstr(&pattern, "!/*/");
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
return write_patterns_and_update(&pl);
}
static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
{
struct pattern_entry *e = xmalloc(sizeof(*e));
e->patternlen = path->len;
e->pattern = strbuf_detach(path, NULL);
hashmap_entry_init(&e->ent,
ignore_case ?
strihash(e->pattern) :
strhash(e->pattern));
hashmap_add(&pl->recursive_hashmap, &e->ent);
while (e->patternlen) {
char *slash = strrchr(e->pattern, '/');
char *oldpattern = e->pattern;
size_t newlen;
if (slash == e->pattern)
break;
newlen = slash - e->pattern;
e = xmalloc(sizeof(struct pattern_entry));
e->patternlen = newlen;
e->pattern = xstrndup(oldpattern, newlen);
hashmap_entry_init(&e->ent,
ignore_case ?
strihash(e->pattern) :
strhash(e->pattern));
if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
hashmap_add(&pl->parent_hashmap, &e->ent);
}
}
static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
{
strbuf_trim(line);
strbuf_trim_trailing_dir_sep(line);
if (strbuf_normalize_path(line))
die(_("could not normalize path %s"), line->buf);
if (!line->len)
return;
if (line->buf[0] != '/')
strbuf_insertstr(line, 0, "/");
insert_recursive_pattern(pl, line);
}
static char const * const builtin_sparse_checkout_set_usage[] = {
N_("git sparse-checkout (set|add) (--stdin | <patterns>)"),
NULL
};
static struct sparse_checkout_set_opts {
int use_stdin;
} set_opts;
static void add_patterns_from_input(struct pattern_list *pl,
int argc, const char **argv)
{
int i;
if (core_sparse_checkout_cone) {
struct strbuf line = STRBUF_INIT;
hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
pl->use_cone_patterns = 1;
if (set_opts.use_stdin) {
struct strbuf unquoted = STRBUF_INIT;
while (!strbuf_getline(&line, stdin)) {
if (line.buf[0] == '"') {
strbuf_reset(&unquoted);
if (unquote_c_style(&unquoted, line.buf, NULL))
die(_("unable to unquote C-style string '%s'"),
line.buf);
strbuf_swap(&unquoted, &line);
}
strbuf_to_cone_pattern(&line, pl);
}
strbuf_release(&unquoted);
} else {
for (i = 0; i < argc; i++) {
strbuf_setlen(&line, 0);
strbuf_addstr(&line, argv[i]);
strbuf_to_cone_pattern(&line, pl);
}
}
} else {
if (set_opts.use_stdin) {
struct strbuf line = STRBUF_INIT;
while (!strbuf_getline(&line, stdin)) {
size_t len;
char *buf = strbuf_detach(&line, &len);
add_pattern(buf, empty_base, 0, pl, 0);
}
} else {
for (i = 0; i < argc; i++)
add_pattern(argv[i], empty_base, 0, pl, 0);
}
}
}
enum modify_type {
REPLACE,
ADD,
};
static void add_patterns_cone_mode(int argc, const char **argv,
struct pattern_list *pl)
{
struct strbuf buffer = STRBUF_INIT;
struct pattern_entry *pe;
struct hashmap_iter iter;
struct pattern_list existing;
char *sparse_filename = get_sparse_checkout_filename();
add_patterns_from_input(pl, argc, argv);
memset(&existing, 0, sizeof(existing));
existing.use_cone_patterns = core_sparse_checkout_cone;
if (add_patterns_from_file_to_list(sparse_filename, "", 0,
&existing, NULL))
die(_("unable to load existing sparse-checkout patterns"));
free(sparse_filename);
hashmap_for_each_entry(&existing.recursive_hashmap, &iter, pe, ent) {
if (!hashmap_contains_parent(&pl->recursive_hashmap,
pe->pattern, &buffer) ||
!hashmap_contains_parent(&pl->parent_hashmap,
pe->pattern, &buffer)) {
strbuf_reset(&buffer);
strbuf_addstr(&buffer, pe->pattern);
insert_recursive_pattern(pl, &buffer);
}
}
clear_pattern_list(&existing);
strbuf_release(&buffer);
}
static void add_patterns_literal(int argc, const char **argv,
struct pattern_list *pl)
{
char *sparse_filename = get_sparse_checkout_filename();
if (add_patterns_from_file_to_list(sparse_filename, "", 0,
pl, NULL))
die(_("unable to load existing sparse-checkout patterns"));
free(sparse_filename);
add_patterns_from_input(pl, argc, argv);
}
static int modify_pattern_list(int argc, const char **argv, enum modify_type m)
{
int result;
int changed_config = 0;
struct pattern_list pl;
memset(&pl, 0, sizeof(pl));
switch (m) {
case ADD:
if (core_sparse_checkout_cone)
add_patterns_cone_mode(argc, argv, &pl);
else
add_patterns_literal(argc, argv, &pl);
break;
case REPLACE:
add_patterns_from_input(&pl, argc, argv);
break;
}
if (!core_apply_sparse_checkout) {
set_config(MODE_ALL_PATTERNS);
core_apply_sparse_checkout = 1;
changed_config = 1;
}
result = write_patterns_and_update(&pl);
if (result && changed_config)
set_config(MODE_NO_PATTERNS);
clear_pattern_list(&pl);
return result;
}
static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
enum modify_type m)
{
static struct option builtin_sparse_checkout_set_options[] = {
OPT_BOOL(0, "stdin", &set_opts.use_stdin,
N_("read patterns from standard in")),
OPT_END(),
};
repo_read_index(the_repository);
require_clean_work_tree(the_repository,
N_("set sparse-checkout patterns"), NULL, 1, 0);
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_set_options,
builtin_sparse_checkout_set_usage,
PARSE_OPT_KEEP_UNKNOWN);
return modify_pattern_list(argc, argv, m);
}
static int sparse_checkout_disable(int argc, const char **argv)
{
struct pattern_list pl;
struct strbuf match_all = STRBUF_INIT;
repo_read_index(the_repository);
require_clean_work_tree(the_repository,
N_("disable sparse-checkout"), NULL, 1, 0);
memset(&pl, 0, sizeof(pl));
hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
pl.use_cone_patterns = 0;
core_apply_sparse_checkout = 1;
strbuf_addstr(&match_all, "/*");
add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
if (update_working_directory(&pl))
die(_("error while refreshing working directory"));
clear_pattern_list(&pl);
return set_config(MODE_NO_PATTERNS);
}
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
{
static struct option builtin_sparse_checkout_options[] = {
OPT_END(),
};
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_sparse_checkout_usage,
builtin_sparse_checkout_options);
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_options,
builtin_sparse_checkout_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
git_config(git_default_config, NULL);
if (argc > 0) {
if (!strcmp(argv[0], "list"))
return sparse_checkout_list(argc, argv);
if (!strcmp(argv[0], "init"))
return sparse_checkout_init(argc, argv);
if (!strcmp(argv[0], "set"))
return sparse_checkout_set(argc, argv, prefix, REPLACE);
if (!strcmp(argv[0], "add"))
return sparse_checkout_set(argc, argv, prefix, ADD);
if (!strcmp(argv[0], "disable"))
return sparse_checkout_disable(argc, argv);
}
usage_with_options(builtin_sparse_checkout_usage,
builtin_sparse_checkout_options);
}

View file

@ -27,7 +27,6 @@ static const char * const git_stash_usage[] = {
N_("git stash clear"),
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]]"),
N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [<message>]"),
@ -397,7 +396,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
const struct object_id *bases[1];
read_cache_preload(NULL);
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
if (refresh_cache(REFRESH_QUIET))
return -1;
if (write_cache_as_tree(&c_tree, 0, NULL))
@ -428,8 +427,6 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
return error(_("could not save index tree"));
reset_head();
discard_cache();
read_cache();
}
}
@ -484,12 +481,13 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (ret)
return -1;
/* read back the result of update_index() back from the disk */
discard_cache();
read_cache();
}
if (!quiet) {
if (quiet) {
if (refresh_cache(REFRESH_QUIET))
warning("could not refresh index");
} else {
struct child_process cp = CHILD_PROCESS_INIT;
/*
@ -499,10 +497,6 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
*/
cp.git_cmd = 1;
cp.dir = prefix;
argv_array_pushf(&cp.env_array, GIT_WORK_TREE_ENVIRONMENT"=%s",
absolute_path(get_git_work_tree()));
argv_array_pushf(&cp.env_array, GIT_DIR_ENVIRONMENT"=%s",
absolute_path(get_git_dir()));
argv_array_push(&cp.args, "status");
run_command(&cp);
}
@ -999,9 +993,9 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
{
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_add_i = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
struct index_state istate = { NULL };
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf);
@ -1015,19 +1009,16 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
}
/* Find out what the user wants. */
old_repo_index_file = the_repository->index_file;
the_repository->index_file = stash_index_path.buf;
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
ret = run_add_interactive(NULL, "--patch=stash", ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
setenv(INDEX_ENVIRONMENT, old_index_env, 1);
else
unsetenv(INDEX_ENVIRONMENT);
FREE_AND_NULL(old_index_env);
cp_add_i.git_cmd = 1;
argv_array_pushl(&cp_add_i.args, "add--interactive", "--patch=stash",
"--", NULL);
add_pathspecs(&cp_add_i.args, ps);
argv_array_pushf(&cp_add_i.env_array, "GIT_INDEX_FILE=%s",
stash_index_path.buf);
if (run_command(&cp_add_i)) {
ret = -1;
goto done;
}
/* State of the working tree. */
if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0,
@ -1091,9 +1082,8 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
}
cp_upd_index.git_cmd = 1;
argv_array_pushl(&cp_upd_index.args, "update-index",
"--ignore-skip-worktree-entries",
"-z", "--add", "--remove", "--stdin", NULL);
argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
"--remove", "--stdin", NULL);
argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
stash_index_path.buf);
@ -1139,10 +1129,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
prepare_fallback_ident("git stash", "git@stash");
read_cache_preload(NULL);
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0) < 0) {
ret = -1;
goto done;
}
refresh_cache(REFRESH_QUIET);
if (get_oid("HEAD", &info->b_commit)) {
if (!quiet)
@ -1303,7 +1290,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
free(ps_matched);
}
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0)) {
if (refresh_cache(REFRESH_QUIET)) {
ret = -1;
goto done;
}
@ -1396,7 +1383,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
argv_array_pushl(&cp.args, "reset", "--hard", "-q",
"--no-recurse-submodules", NULL);
NULL);
if (run_command(&cp)) {
ret = -1;
goto done;
@ -1452,17 +1439,13 @@ done:
return ret;
}
static int push_stash(int argc, const char **argv, const char *prefix,
int push_assumed)
static int push_stash(int argc, const char **argv, const char *prefix)
{
int force_assume = 0;
int keep_index = -1;
int patch_mode = 0;
int include_untracked = 0;
int quiet = 0;
int pathspec_file_nul = 0;
const char *stash_msg = NULL;
const char *pathspec_from_file = NULL;
struct pathspec ps;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
@ -1476,45 +1459,16 @@ static int push_stash(int argc, const char **argv, const char *prefix,
N_("include ignore files"), 2),
OPT_STRING('m', "message", &stash_msg, N_("message"),
N_("stash message")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END()
};
if (argc) {
force_assume = !strcmp(argv[0], "-p");
if (argc)
argc = parse_options(argc, argv, prefix, options,
git_stash_push_usage,
PARSE_OPT_KEEP_DASHDASH);
}
if (argc) {
if (!strcmp(argv[0], "--")) {
argc--;
argv++;
} else if (push_assumed && !force_assume) {
die("subcommand wasn't specified; 'push' can't be assumed due to unexpected token '%s'",
argv[0]);
}
}
0);
parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
if (pathspec_from_file) {
if (patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
if (ps.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
parse_pathspec_file(&ps, 0,
PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
include_untracked);
}
@ -1584,6 +1538,7 @@ static int use_builtin_stash(void)
int cmd_stash(int argc, const char **argv, const char *prefix)
{
int i = -1;
pid_t pid = getpid();
const char *index_file;
struct argv_array args = ARGV_ARRAY_INIT;
@ -1616,7 +1571,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
(uintmax_t)pid);
if (!argc)
return !!push_stash(0, NULL, prefix, 0);
return !!push_stash(0, NULL, prefix);
else if (!strcmp(argv[0], "apply"))
return !!apply_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "clear"))
@ -1636,15 +1591,45 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
else if (!strcmp(argv[0], "create"))
return !!create_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "push"))
return !!push_stash(argc, argv, prefix, 0);
return !!push_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "save"))
return !!save_stash(argc, argv, prefix);
else if (*argv[0] != '-')
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
git_stash_usage, options);
/* Assume 'stash push' */
if (strcmp(argv[0], "-p")) {
while (++i < argc && strcmp(argv[i], "--")) {
/*
* `akpqu` is a string which contains all short options,
* except `-m` which is verified separately.
*/
if ((strlen(argv[i]) == 2) && *argv[i] == '-' &&
strchr("akpqu", argv[i][1]))
continue;
if (!strcmp(argv[i], "--all") ||
!strcmp(argv[i], "--keep-index") ||
!strcmp(argv[i], "--no-keep-index") ||
!strcmp(argv[i], "--patch") ||
!strcmp(argv[i], "--quiet") ||
!strcmp(argv[i], "--include-untracked"))
continue;
/*
* `-m` and `--message=` are verified separately because
* they need to be immediately followed by a string
* (i.e.`-m"foobar"` or `--message="foobar"`).
*/
if (starts_with(argv[i], "-m") ||
starts_with(argv[i], "--message="))
continue;
usage_with_options(git_stash_usage, options);
}
}
argv_array_push(&args, "push");
argv_array_pushv(&args, argv);
return !!push_stash(args.argc, args.argv, prefix, 1);
return !!push_stash(args.argc, args.argv, prefix);
}

View file

@ -19,8 +19,6 @@
#include "diffcore.h"
#include "diff.h"
#include "object-store.h"
#include "dir.h"
#include "advice.h"
#define OPT_QUIET (1 << 0)
#define OPT_CACHED (1 << 1)
@ -426,7 +424,7 @@ static int module_list(int argc, const char **argv, const char *prefix)
const struct cache_entry *ce = list.entries[i];
if (ce_stage(ce))
printf("%06o %s U\t", ce->ce_mode, oid_to_hex(&null_oid));
printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1));
else
printf("%06o %s %d\t", ce->ce_mode,
oid_to_hex(&ce->oid), ce_stage(ce));
@ -782,8 +780,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
struct argv_array diff_files_args = ARGV_ARRAY_INIT;
struct rev_info rev;
int diff_files_result;
struct strbuf buf = STRBUF_INIT;
const char *git_dir;
if (!submodule_from_path(the_repository, &null_oid, path))
die(_("no submodule mapping found in .gitmodules for path '%s'"),
@ -796,26 +792,17 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
goto cleanup;
}
strbuf_addf(&buf, "%s/.git", path);
git_dir = read_gitfile(buf.buf);
if (!git_dir)
git_dir = buf.buf;
if (!is_submodule_active(the_repository, path) ||
!is_git_directory(git_dir)) {
if (!is_submodule_active(the_repository, path)) {
print_status(flags, '-', path, ce_oid, displaypath);
strbuf_release(&buf);
goto cleanup;
}
strbuf_release(&buf);
argv_array_pushl(&diff_files_args, "diff-files",
"--ignore-submodules=dirty", "--quiet", "--",
path, NULL);
git_config(git_diff_basic_config, NULL);
repo_init_revisions(the_repository, &rev, NULL);
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
diff_files_args.argc = setup_revisions(diff_files_args.argc,
diff_files_args.argv,
@ -1235,7 +1222,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
static int clone_submodule(const char *path, const char *gitdir, const char *url,
const char *depth, struct string_list *reference, int dissociate,
int quiet, int progress, int single_branch)
int quiet, int progress)
{
struct child_process cp = CHILD_PROCESS_INIT;
@ -1257,10 +1244,6 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
argv_array_push(&cp.args, "--dissociate");
if (gitdir && *gitdir)
argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
if (single_branch >= 0)
argv_array_push(&cp.args, single_branch ?
"--single-branch" :
"--no-single-branch");
argv_array_push(&cp.args, "--");
argv_array_push(&cp.args, url);
@ -1285,13 +1268,6 @@ struct submodule_alternate_setup {
#define SUBMODULE_ALTERNATE_SETUP_INIT { NULL, \
SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
static const char alternate_error_advice[] = N_(
"An alternate computed from a superproject's alternate is invalid.\n"
"To allow Git to clone without an alternate in such a case, set\n"
"submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
"'--reference-if-able' instead of '--reference'."
);
static int add_possible_reference_from_superproject(
struct object_directory *odb, void *sas_cb)
{
@ -1323,8 +1299,6 @@ static int add_possible_reference_from_superproject(
} else {
switch (sas->error_mode) {
case SUBMODULE_ALTERNATE_ERROR_DIE:
if (advice_submodule_alternate_error_strategy_die)
advise(_(alternate_error_advice));
die(_("submodule '%s' cannot add alternate: %s"),
sas->submodule_name, err.buf);
case SUBMODULE_ALTERNATE_ERROR_INFO:
@ -1385,9 +1359,8 @@ static int module_clone(int argc, const char **argv, const char *prefix)
char *p, *path = NULL, *sm_gitdir;
struct strbuf sb = STRBUF_INIT;
struct string_list reference = STRING_LIST_INIT_NODUP;
int dissociate = 0, require_init = 0;
int dissociate = 0;
char *sm_alternate = NULL, *error_strategy = NULL;
int single_branch = -1;
struct option module_clone_options[] = {
OPT_STRING(0, "prefix", &prefix,
@ -1413,17 +1386,12 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
OPT_BOOL(0, "progress", &progress,
N_("force cloning progress")),
OPT_BOOL(0, "require-init", &require_init,
N_("disallow cloning into non-empty directory")),
OPT_BOOL(0, "single-branch", &single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
"[--reference <repository>] [--name <name>] [--depth <depth>] "
"[--single-branch] "
"--url <url> --path <path>"),
NULL
};
@ -1445,10 +1413,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
} else
path = xstrdup(path);
if (validate_submodule_git_dir(sm_gitdir, name) < 0)
die(_("refusing to create/use '%s' in another submodule's "
"git dir"), sm_gitdir);
if (!file_exists(sm_gitdir)) {
if (safe_create_leading_directories_const(sm_gitdir) < 0)
die(_("could not create directory '%s'"), sm_gitdir);
@ -1456,12 +1420,10 @@ static int module_clone(int argc, const char **argv, const char *prefix)
prepare_possible_alternates(name, &reference);
if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
quiet, progress, single_branch))
quiet, progress))
die(_("clone of '%s' into submodule path '%s' failed"),
url, path);
} else {
if (require_init && !access(path, X_OK) && !is_empty_dir(path))
die(_("directory not empty: '%s'"), path);
if (safe_create_leading_directories_const(path) < 0)
die(_("could not create directory '%s'"), path);
strbuf_addf(&sb, "%s/index", sm_gitdir);
@ -1516,8 +1478,6 @@ static void determine_submodule_update_strategy(struct repository *r,
die(_("Invalid update mode '%s' configured for submodule path '%s'"),
val, path);
} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
if (sub->update_strategy.type == SM_UPDATE_COMMAND)
BUG("how did we read update = !command from .gitmodules?");
out->type = sub->update_strategy.type;
out->command = sub->update_strategy.command;
} else
@ -1576,11 +1536,9 @@ struct submodule_update_clone {
int recommend_shallow;
struct string_list references;
int dissociate;
unsigned require_init;
const char *depth;
const char *recursive_prefix;
const char *prefix;
int single_branch;
/* to be consumed by git-submodule.sh */
struct update_clone_data *update_clone;
@ -1595,14 +1553,10 @@ struct submodule_update_clone {
int max_jobs;
};
#define SUBMODULE_UPDATE_CLONE_INIT { \
.list = MODULE_LIST_INIT, \
.update = SUBMODULE_UPDATE_STRATEGY_INIT, \
.recommend_shallow = -1, \
.references = STRING_LIST_INIT_DUP, \
.single_branch = -1, \
.max_jobs = 1, \
}
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
NULL, NULL, NULL, \
NULL, 0, 0, 0, NULL, 0, 0, 1}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@ -1727,8 +1681,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_pushl(&child->args, "--prefix", suc->prefix, NULL);
if (suc->recommend_shallow && sub->recommend_shallow == 1)
argv_array_push(&child->args, "--depth=1");
if (suc->require_init)
argv_array_push(&child->args, "--require-init");
argv_array_pushl(&child->args, "--path", sub->path, NULL);
argv_array_pushl(&child->args, "--name", sub->name, NULL);
argv_array_pushl(&child->args, "--url", url, NULL);
@ -1741,10 +1693,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_push(&child->args, "--dissociate");
if (suc->depth)
argv_array_push(&child->args, suc->depth);
if (suc->single_branch >= 0)
argv_array_push(&child->args, suc->single_branch ?
"--single-branch" :
"--no-single-branch");
cleanup:
strbuf_reset(&displaypath_sb);
@ -1922,15 +1870,11 @@ static int update_clone(int argc, const char **argv, const char *prefix)
OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
OPT_BOOL(0, "progress", &suc.progress,
N_("force cloning progress")),
OPT_BOOL(0, "require-init", &suc.require_init,
N_("disallow cloning into non-empty directory")),
OPT_BOOL(0, "single-branch", &suc.single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
N_("git submodule--helper update_clone [--prefix=<path>] [<path>...]"),
NULL
};
suc.prefix = prefix;

View file

@ -24,7 +24,6 @@ static off_t consumed_bytes;
static off_t max_input_size;
static git_hash_ctx ctx;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static struct progress *progress;
/*
* When running under --strict mode, objects whose reachability are
@ -93,7 +92,6 @@ static void use(int bytes)
consumed_bytes += bytes;
if (max_input_size && consumed_bytes > max_input_size)
die(_("pack exceeds maximum allowed size"));
display_throughput(progress, consumed_bytes);
}
static void *get_data(unsigned long size)
@ -265,8 +263,7 @@ static void write_object(unsigned nr, enum object_type type,
} else {
struct object *obj;
int eaten;
hash_object_file(the_hash_algo, buf, size, type_name(type),
&obj_list[nr].oid);
hash_object_file(buf, size, type_name(type), &obj_list[nr].oid);
added_object(nr, type, buf, size);
obj = parse_object_buffer(the_repository, &obj_list[nr].oid,
type, size, buf,
@ -487,6 +484,7 @@ static void unpack_one(unsigned nr)
static void unpack_all(void)
{
int i;
struct progress *progress = NULL;
struct pack_header *hdr = fill(sizeof(struct pack_header));
nr_objects = ntohl(hdr->hdr_entries);

View file

@ -35,7 +35,6 @@ static int verbose;
static int mark_valid_only;
static int mark_skip_worktree_only;
static int mark_fsmonitor_only;
static int ignore_skip_worktree_entries;
#define MARK_FLAG 1
#define UNMARK_FLAG 2
static struct strbuf mtime_dir = STRBUF_INIT;
@ -382,8 +381,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
* so updating it does not make sense.
* On the other hand, removing it from index should work
*/
if (!ignore_skip_worktree_entries && allow_remove &&
remove_file_from_cache(path))
if (allow_remove && remove_file_from_cache(path))
return error("%s: cannot remove from the index", path);
return 0;
}
@ -968,7 +966,6 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;
strbuf_getline_fn getline_fn;
int parseopt_state = PARSE_OPT_UNKNOWN;
struct repository *r = the_repository;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
N_("continue refresh even when index needs update"),
@ -1016,8 +1013,6 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
N_("clear skip-worktree bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries,
N_("do not touch index-only entries")),
OPT_SET_INT(0, "info-only", &info_only,
N_("add to index only; do not add content to object database"), 1),
OPT_SET_INT(0, "force-remove", &force_remove,
@ -1185,12 +1180,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
remove_split_index(&the_index);
}
prepare_repo_settings(r);
switch (untracked_cache) {
case UC_UNSPECIFIED:
break;
case UC_DISABLE:
if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
if (git_config_get_untracked_cache() == 1)
warning(_("core.untrackedCache is set to true; "
"remove or change it, if you really want to "
"disable the untracked cache"));
@ -1202,7 +1196,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
return !test_if_untracked_cache_is_supported();
case UC_ENABLE:
case UC_FORCE:
if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE)
if (git_config_get_untracked_cache() == 0)
warning(_("core.untrackedCache is set to false; "
"remove or change it, if you really want to "
"enable the untracked cache"));

View file

@ -10,6 +10,7 @@
#include "run-command.h"
#include "sigchain.h"
#include "submodule.h"
#include "refs.h"
#include "utf8.h"
#include "worktree.h"
@ -234,7 +235,14 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts)
die(_("'%s' already exists"), path);
worktrees = get_worktrees(0);
wt = find_worktree_by_path(worktrees, path);
/*
* find_worktree()'s suffix matching may undesirably find the main
* rather than a linked worktree (for instance, when the basenames
* of the main worktree and the one being created are the same).
* We're only interested in linked worktrees, so skip the main
* worktree with +1.
*/
wt = find_worktree(worktrees + 1, NULL, path);
if (!wt)
goto done;
@ -342,7 +350,7 @@ static int add_worktree(const char *path, const char *refname,
*/
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
write_file(sb.buf, "%s", oid_to_hex(&null_oid));
write_file(sb.buf, "%s", sha1_to_hex(null_sha1));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@ -369,7 +377,7 @@ static int add_worktree(const char *path, const char *refname,
if (opts->checkout) {
cp.argv = NULL;
argv_array_clear(&cp.args);
argv_array_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
argv_array_pushl(&cp.args, "reset", "--hard", NULL);
if (opts->quiet)
argv_array_push(&cp.args, "--quiet");
cp.env = child_env.argv;
@ -872,7 +880,7 @@ static void check_clean_worktree(struct worktree *wt,
original_path);
ret = xread(cp.out, buf, sizeof(buf));
if (ret)
die(_("'%s' contains modified or untracked files, use --force to delete it"),
die(_("'%s' is dirty, use --force to delete it"),
original_path);
close(cp.out);
ret = finish_command(&cp);