Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c226
-rw-r--r--builtin/am.c270
-rw-r--r--builtin/apply.c4
-rw-r--r--builtin/archive.c7
-rw-r--r--builtin/bisect.c (renamed from builtin/bisect--helper.c)461
-rw-r--r--builtin/blame.c56
-rw-r--r--builtin/branch.c344
-rw-r--r--builtin/bugreport.c23
-rw-r--r--builtin/bundle.c125
-rw-r--r--builtin/cat-file.c209
-rw-r--r--builtin/check-attr.c34
-rw-r--r--builtin/check-ignore.c8
-rw-r--r--builtin/check-mailmap.c4
-rw-r--r--builtin/check-ref-format.c6
-rw-r--r--builtin/checkout--worker.c2
-rw-r--r--builtin/checkout-index.c42
-rw-r--r--builtin/checkout.c242
-rw-r--r--builtin/clean.c29
-rw-r--r--builtin/clone.c200
-rw-r--r--builtin/column.c7
-rw-r--r--builtin/commit-graph.c68
-rw-r--r--builtin/commit-tree.c30
-rw-r--r--builtin/commit.c188
-rw-r--r--builtin/config.c140
-rw-r--r--builtin/count-objects.c16
-rw-r--r--builtin/credential-cache--daemon.c30
-rw-r--r--builtin/credential-cache.c6
-rw-r--r--builtin/credential-store.c37
-rw-r--r--builtin/credential.c2
-rw-r--r--builtin/describe.c62
-rw-r--r--builtin/diagnose.c6
-rw-r--r--builtin/diff-files.c24
-rw-r--r--builtin/diff-index.c23
-rw-r--r--builtin/diff-tree.c27
-rw-r--r--builtin/diff.c136
-rw-r--r--builtin/difftool.c69
-rw-r--r--builtin/env--helper.c100
-rw-r--r--builtin/fast-export.c136
-rw-r--r--builtin/fast-import.c43
-rw-r--r--builtin/fetch-pack.c9
-rw-r--r--builtin/fetch.c878
-rw-r--r--builtin/fmt-merge-msg.c1
-rw-r--r--builtin/for-each-ref.c71
-rw-r--r--builtin/for-each-repo.c27
-rw-r--r--builtin/fsck.c199
-rw-r--r--builtin/fsmonitor--daemon.c51
-rw-r--r--builtin/gc.c541
-rw-r--r--builtin/get-tar-commit-id.c10
-rw-r--r--builtin/grep.c105
-rw-r--r--builtin/hash-object.c16
-rw-r--r--builtin/help.c14
-rw-r--r--builtin/hook.c7
-rw-r--r--builtin/index-pack.c48
-rw-r--r--builtin/init-db.c497
-rw-r--r--builtin/interpret-trailers.c35
-rw-r--r--builtin/log.c226
-rw-r--r--builtin/ls-files.c277
-rw-r--r--builtin/ls-remote.c22
-rw-r--r--builtin/ls-tree.c355
-rw-r--r--builtin/mailinfo.c5
-rw-r--r--builtin/mailsplit.c4
-rw-r--r--builtin/merge-base.c18
-rw-r--r--builtin/merge-file.c96
-rw-r--r--builtin/merge-index.c26
-rw-r--r--builtin/merge-ours.c6
-rw-r--r--builtin/merge-recursive.c17
-rw-r--r--builtin/merge-tree.c152
-rw-r--r--builtin/merge.c220
-rw-r--r--builtin/mktag.c20
-rw-r--r--builtin/mktree.c5
-rw-r--r--builtin/multi-pack-index.c8
-rw-r--r--builtin/mv.c65
-rw-r--r--builtin/name-rev.c69
-rw-r--r--builtin/notes.c213
-rw-r--r--builtin/pack-objects.c372
-rw-r--r--builtin/pack-redundant.c9
-rw-r--r--builtin/pack-refs.c32
-rw-r--r--builtin/patch-id.c122
-rw-r--r--builtin/prune-packed.c1
-rw-r--r--builtin/prune.c27
-rw-r--r--builtin/pull.c185
-rw-r--r--builtin/push.c147
-rw-r--r--builtin/range-diff.c19
-rw-r--r--builtin/read-tree.c51
-rw-r--r--builtin/rebase.c660
-rw-r--r--builtin/receive-pack.c110
-rw-r--r--builtin/reflog.c26
-rw-r--r--builtin/remote-ext.c8
-rw-r--r--builtin/remote-fd.c4
-rw-r--r--builtin/remote.c68
-rw-r--r--builtin/repack.c940
-rw-r--r--builtin/replace.c40
-rw-r--r--builtin/replay.c446
-rw-r--r--builtin/rerere.c8
-rw-r--r--builtin/reset.c114
-rw-r--r--builtin/rev-list.c124
-rw-r--r--builtin/rev-parse.c67
-rw-r--r--builtin/revert.c50
-rw-r--r--builtin/rm.c45
-rw-r--r--builtin/send-pack.c47
-rw-r--r--builtin/shortlog.c103
-rw-r--r--builtin/show-branch.c63
-rw-r--r--builtin/show-index.c5
-rw-r--r--builtin/show-ref.c295
-rw-r--r--builtin/sparse-checkout.c159
-rw-r--r--builtin/stash.c223
-rw-r--r--builtin/stripspace.c10
-rw-r--r--builtin/submodule--helper.c349
-rw-r--r--builtin/symbolic-ref.c24
-rw-r--r--builtin/tag.c122
-rw-r--r--builtin/unpack-file.c13
-rw-r--r--builtin/unpack-objects.c30
-rw-r--r--builtin/update-index.c216
-rw-r--r--builtin/update-ref.c30
-rw-r--r--builtin/update-server-info.c7
-rw-r--r--builtin/upload-archive.c7
-rw-r--r--builtin/upload-pack.c9
-rw-r--r--builtin/var.c200
-rw-r--r--builtin/verify-commit.c21
-rw-r--r--builtin/verify-pack.c5
-rw-r--r--builtin/verify-tag.c20
-rw-r--r--builtin/worktree.c386
-rw-r--r--builtin/write-tree.c13
123 files changed, 8191 insertions, 5596 deletions
diff --git a/builtin/add.c b/builtin/add.c
index f84372964c..ada7719561 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -3,19 +3,22 @@
*
* Copyright (C) 2006 Linus Torvalds
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
-#include "config.h"
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
#include "lockfile.h"
+#include "editor.h"
#include "dir.h"
+#include "gettext.h"
#include "pathspec.h"
-#include "exec-cmd.h"
-#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
#include "diff.h"
-#include "diffcore.h"
+#include "read-cache.h"
+#include "repository.h"
#include "revision.h"
#include "bulk-checkin.h"
#include "strvec.h"
@@ -33,17 +36,12 @@ static int pathspec_file_nul;
static int include_sparse;
static const char *pathspec_from_file;
-struct update_callback_data {
- int flags;
- int add_errors;
-};
-
static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
{
int i, ret = 0;
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ struct cache_entry *ce = the_index.cache[i];
int err;
if (!include_sparse &&
@@ -55,7 +53,7 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
continue;
if (!show_only)
- err = chmod_cache_entry(ce, flip);
+ err = chmod_index_entry(&the_index, ce, flip);
else
err = S_ISREG(ce->ce_mode) ? 0 : -1;
@@ -66,101 +64,12 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
return ret;
}
-static int fix_unmerged_status(struct diff_filepair *p,
- struct update_callback_data *data)
-{
- if (p->status != DIFF_STATUS_UNMERGED)
- return p->status;
- if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
- /*
- * This is not an explicit add request, and the
- * path is missing from the working tree (deleted)
- */
- return DIFF_STATUS_DELETED;
- else
- /*
- * Either an explicit add request, or path exists
- * in the working tree. An attempt to explicitly
- * add a path that does not exist in the working tree
- * will be caught as an error by the caller immediately.
- */
- return DIFF_STATUS_MODIFIED;
-}
-
-static void update_callback(struct diff_queue_struct *q,
- struct diff_options *opt, void *cbdata)
-{
- int i;
- struct update_callback_data *data = cbdata;
-
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- const char *path = p->one->path;
-
- if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
- continue;
-
- switch (fix_unmerged_status(p, data)) {
- default:
- die(_("unexpected diff status %c"), p->status);
- case DIFF_STATUS_MODIFIED:
- case DIFF_STATUS_TYPE_CHANGED:
- if (add_file_to_index(&the_index, path, data->flags)) {
- if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
- die(_("updating files failed"));
- data->add_errors++;
- }
- break;
- case DIFF_STATUS_DELETED:
- if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
- break;
- if (!(data->flags & ADD_CACHE_PRETEND))
- remove_file_from_index(&the_index, path);
- if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
- printf(_("remove '%s'\n"), path);
- break;
- }
- }
-}
-
-int add_files_to_cache(const char *prefix,
- const struct pathspec *pathspec, int flags)
-{
- struct update_callback_data data;
- struct rev_info rev;
-
- memset(&data, 0, sizeof(data));
- data.flags = flags;
-
- repo_init_revisions(the_repository, &rev, prefix);
- setup_revisions(0, NULL, &rev, NULL);
- if (pathspec)
- copy_pathspec(&rev.prune_data, pathspec);
- rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
- rev.diffopt.format_callback = update_callback;
- rev.diffopt.format_callback_data = &data;
- rev.diffopt.flags.override_submodule_config = 1;
- rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
-
- /*
- * Use an ODB transaction to optimize adding multiple objects.
- * This function is invoked from commands other than 'add', which
- * may not have their own transaction active.
- */
- begin_odb_transaction();
- run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
- end_odb_transaction();
-
- release_revisions(&rev);
- return !!data.add_errors;
-}
-
static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
{
int i, retval = 0;
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ struct cache_entry *ce = the_index.cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
@@ -172,7 +81,8 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
continue; /* do not touch non blobs */
if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
- retval |= add_file_to_cache(ce->name, flags | ADD_CACHE_RENORMALIZE);
+ retval |= add_file_to_index(&the_index, ce->name,
+ flags | ADD_CACHE_RENORMALIZE);
}
return retval;
@@ -237,59 +147,14 @@ static int refresh(int verbose, const struct pathspec *pathspec)
return ret;
}
-int run_add_interactive(const char *revision, const char *patch_mode,
- const struct pathspec *pathspec)
-{
- int status, i;
- struct strvec argv = STRVEC_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))
- use_builtin_add_i = 1;
-
- if (use_builtin_add_i != 0) {
- 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);
- }
-
- strvec_push(&argv, "add--interactive");
- if (patch_mode)
- strvec_push(&argv, patch_mode);
- if (revision)
- strvec_push(&argv, revision);
- strvec_push(&argv, "--");
- for (i = 0; i < pathspec->nr; i++)
- /* pass original pathspec, to be re-parsed */
- strvec_push(&argv, pathspec->items[i].original);
-
- status = run_command_v_opt(argv.v, RUN_GIT_CMD);
- strvec_clear(&argv);
- return status;
-}
-
int interactive_add(const char **argv, const char *prefix, int patch)
{
struct pathspec pathspec;
+ int unused;
+
+ if (!git_config_get_bool("add.interactive.usebuiltin", &unused))
+ warning(_("the add.interactive.useBuiltin setting has been removed!\n"
+ "See its entry in 'git help config' for details."));
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
@@ -297,9 +162,10 @@ int interactive_add(const char **argv, const char *prefix, int patch)
PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
- return run_add_interactive(NULL,
- patch ? "--patch" : NULL,
- &pathspec);
+ if (patch)
+ return !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+ else
+ return !!run_add_i(the_repository, &pathspec);
}
static int edit_patch(int argc, const char **argv, const char *prefix)
@@ -312,8 +178,8 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
- if (read_cache() < 0)
- die(_("Could not read the index"));
+ if (repo_read_index(the_repository) < 0)
+ die(_("could not read the index"));
repo_init_revisions(the_repository, &rev, prefix);
rev.diffopt.context = 7;
@@ -325,22 +191,21 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
rev.diffopt.file = xfdopen(out, "w");
rev.diffopt.close_file = 1;
- if (run_diff_files(&rev, 0))
- die(_("Could not write patch"));
+ run_diff_files(&rev, 0);
if (launch_editor(file, NULL, NULL))
die(_("editing patch failed"));
if (stat(file, &st))
- die_errno(_("Could not stat '%s'"), file);
+ die_errno(_("could not stat '%s'"), file);
if (!st.st_size)
- die(_("Empty patch. Aborted."));
+ die(_("empty patch. aborted"));
child.git_cmd = 1;
strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
NULL);
if (run_command(&child))
- die(_("Could not apply '%s'"), file);
+ die(_("could not apply '%s'"), file);
unlink(file);
free(file);
@@ -363,6 +228,8 @@ static char *chmod_arg;
static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
+
/* if we are told to ignore, we are not adding removals */
*(int *)opt->value = !unset ? 0 : 1;
return 0;
@@ -397,7 +264,8 @@ static struct option builtin_add_options[] = {
OPT_END(),
};
-static int add_config(const char *var, const char *value, void *cb)
+static int add_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "add.ignoreerrors") ||
!strcmp(var, "add.ignore-errors")) {
@@ -405,7 +273,10 @@ static int add_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static const char embedded_advice[] = N_(
@@ -544,13 +415,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
*/
- parse_pathspec(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);
@@ -559,7 +430,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
- parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
+ parse_pathspec_file(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, pathspec_from_file, pathspec_file_nul);
@@ -587,7 +458,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));
- if (read_cache_preload(&pathspec) < 0)
+ if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
die(_("index file corrupt"));
die_in_unpopulated_submodule(&the_index, prefix);
@@ -630,7 +501,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
@@ -680,7 +552,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (add_renormalize)
exit_status |= renormalize_tracked_files(&pathspec, flags);
else
- exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+ exit_status |= add_files_to_cache(the_repository, prefix,
+ &pathspec, include_sparse,
+ flags);
if (add_new_files)
exit_status |= add_files(&dir, flags);
@@ -692,9 +566,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
finish:
if (write_locked_index(&the_index, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("Unable to write new index file"));
+ die(_("unable to write new index file"));
dir_clear(&dir);
- UNLEAK(pathspec);
+ clear_pathspec(&pathspec);
return exit_status;
}
diff --git a/builtin/am.c b/builtin/am.c
index 39fea24833..d1990d7edc 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -3,11 +3,15 @@
*
* Based on git-am.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
-#include "config.h"
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "exec-cmd.h"
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
#include "dir.h"
#include "run-command.h"
@@ -19,20 +23,21 @@
#include "refs.h"
#include "commit.h"
#include "diff.h"
-#include "diffcore.h"
#include "unpack-trees.h"
#include "branch.h"
+#include "object-name.h"
+#include "preload-index.h"
#include "sequencer.h"
#include "revision.h"
#include "merge-recursive.h"
#include "log-tree.h"
#include "notes-utils.h"
#include "rerere.h"
-#include "prompt.h"
#include "mailinfo.h"
#include "apply.h"
#include "string-list.h"
-#include "packfile.h"
+#include "pager.h"
+#include "path.h"
#include "repository.h"
#include "pretty.h"
@@ -83,9 +88,16 @@ enum signoff_type {
SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
};
-enum show_patch_type {
- SHOW_PATCH_RAW = 0,
- SHOW_PATCH_DIFF = 1,
+enum resume_type {
+ RESUME_FALSE = 0,
+ RESUME_APPLY,
+ RESUME_RESOLVED,
+ RESUME_SKIP,
+ RESUME_ABORT,
+ RESUME_QUIT,
+ RESUME_SHOW_PATCH_RAW,
+ RESUME_SHOW_PATCH_DIFF,
+ RESUME_ALLOW_EMPTY,
};
enum empty_action {
@@ -117,6 +129,7 @@ struct am_state {
/* various operating modes and command line options */
int interactive;
+ int no_verify;
int threeway;
int quiet;
int signoff; /* enum signoff_type */
@@ -472,10 +485,12 @@ static void am_destroy(const struct am_state *state)
*/
static int run_applypatch_msg_hook(struct am_state *state)
{
- int ret;
+ int ret = 0;
assert(state->msg);
- ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+
+ if (!state->no_verify)
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -492,24 +507,12 @@ static int run_applypatch_msg_hook(struct am_state *state)
*/
static int run_post_rewrite_hook(const struct am_state *state)
{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *hook = find_hook("post-rewrite");
- int ret;
-
- if (!hook)
- return 0;
-
- strvec_push(&cp.args, hook);
- strvec_push(&cp.args, "rebase");
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
- cp.stdout_to_stderr = 1;
- cp.trace2_hook_name = "post-rewrite";
+ strvec_push(&opt.args, "rebase");
+ opt.path_to_stdin = am_path(state, "rewritten");
- ret = run_command(&cp);
-
- close(cp.in);
- return ret;
+ return run_hooks_opt("post-rewrite", &opt);
}
/**
@@ -786,7 +789,7 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
* A split_mail_conv() callback that converts an StGit patch to an RFC2822
* message suitable for parsing with git-mailinfo.
*/
-static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr)
+static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
{
struct strbuf sb = STRBUF_INIT;
int subject_printed = 0;
@@ -869,7 +872,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,
* A split_patches_conv() callback that converts a mercurial patch to a RFC2822
* message suitable for parsing with git-mailinfo.
*/
-static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
+static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
{
struct strbuf sb = STRBUF_INIT;
int rc = 0;
@@ -1075,7 +1078,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
else
write_state_text(state, "applying", "");
- if (!get_oid("HEAD", &curr_head)) {
+ if (!repo_get_oid(the_repository, "HEAD", &curr_head)) {
write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
@@ -1118,7 +1121,7 @@ static void am_next(struct am_state *state)
unlink(am_path(state, "original-commit"));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
- if (!get_oid("HEAD", &head))
+ if (!repo_get_oid(the_repository, "HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&head));
else
write_state_text(state, "abort-safety", "");
@@ -1283,7 +1286,7 @@ static int parse_mail(struct am_state *state, const char *mail)
strbuf_addstr(&msg, "\n\n");
strbuf_addbuf(&msg, &mi.log_message);
- strbuf_stripspace(&msg, 0);
+ strbuf_stripspace(&msg, '\0');
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
@@ -1338,7 +1341,8 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
size_t ident_len;
struct ident_split id;
- buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+ buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+ get_commit_output_encoding());
ident_line = find_commit_header(buffer, "author", &ident_len);
if (!ident_line)
@@ -1370,7 +1374,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
state->msg = xstrdup(msg + 2);
state->msg_len = strlen(state->msg);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
/**
@@ -1411,9 +1415,9 @@ static void write_index_patch(const struct am_state *state)
struct rev_info rev_info;
FILE *fp;
- if (!get_oid("HEAD", &head)) {
+ if (!repo_get_oid(the_repository, "HEAD", &head)) {
struct commit *commit = lookup_commit_or_die(&head, "HEAD");
- tree = get_commit_tree(commit);
+ tree = repo_get_commit_tree(the_repository, commit);
} else
tree = lookup_tree(the_repository,
the_repository->hash_algo->empty_tree);
@@ -1429,7 +1433,7 @@ static void write_index_patch(const struct am_state *state)
rev_info.diffopt.close_file = 1;
add_pending_object(&rev_info, &tree->object, "");
diff_setup_done(&rev_info.diffopt);
- run_diff_index(&rev_info, 1);
+ run_diff_index(&rev_info, DIFF_INDEX_CACHED);
release_revisions(&rev_info);
}
@@ -1476,6 +1480,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
int res, opts_left;
int force_apply = 0;
int options = 0;
+ const char **apply_argv;
if (init_apply_state(&apply_state, the_repository, NULL))
BUG("init_apply_state() failed");
@@ -1483,7 +1488,14 @@ static int run_apply(const struct am_state *state, const char *index_file)
strvec_push(&apply_opts, "apply");
strvec_pushv(&apply_opts, state->git_apply_opts.v);
- opts_left = apply_parse_options(apply_opts.nr, apply_opts.v,
+ /*
+ * Build a copy that apply_parse_options() can rearrange.
+ * apply_opts.v keeps referencing the allocated strings for
+ * strvec_clear() to release.
+ */
+ DUP_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
+
+ opts_left = apply_parse_options(apply_opts.nr, apply_argv,
&apply_state, &force_apply, &options,
NULL);
@@ -1513,14 +1525,15 @@ static int run_apply(const struct am_state *state, const char *index_file)
strvec_clear(&apply_paths);
strvec_clear(&apply_opts);
clear_apply_state(&apply_state);
+ free(apply_argv);
if (res)
return res;
if (index_file) {
/* Reload index as apply_all_patches() will have modified it. */
- discard_cache();
- read_cache_from(index_file);
+ discard_index(&the_index);
+ read_index_from(&the_index, index_file, get_git_dir());
}
return 0;
@@ -1556,14 +1569,14 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
struct commit *result;
char *their_tree_name;
- if (get_oid("HEAD", &our_tree) < 0)
+ if (repo_get_oid(the_repository, "HEAD", &our_tree) < 0)
oidcpy(&our_tree, the_hash_algo->empty_tree);
if (build_fake_ancestor(state, index_path))
return error("could not build fake ancestor");
- discard_cache();
- read_cache_from(index_path);
+ discard_index(&the_index);
+ read_index_from(&the_index, index_path, get_git_dir());
if (write_index_as_tree(&orig_tree, &the_index, index_path, 0, NULL))
return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
@@ -1583,7 +1596,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
rev_info.diffopt.filter |= diff_filter_bit('M');
add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
diff_setup_done(&rev_info.diffopt);
- run_diff_index(&rev_info, 1);
+ run_diff_index(&rev_info, DIFF_INDEX_CACHED);
release_revisions(&rev_info);
}
@@ -1596,8 +1609,8 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
say(state, stdout, _("Falling back to patching base and 3-way merge..."));
- discard_cache();
- read_cache();
+ discard_index(&the_index);
+ repo_read_index(the_repository);
/*
* This is not so wrong. Depending on which base we picked, orig_tree
@@ -1640,13 +1653,13 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hooks("pre-applypatch"))
+ if (!state->no_verify && run_hooks("pre-applypatch"))
exit(1);
- if (write_cache_as_tree(&tree, 0, NULL))
+ if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
- if (!get_oid_commit("HEAD", &parent)) {
+ if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
old_oid = &parent;
commit_list_insert(lookup_commit(the_repository, &parent),
&parents);
@@ -1781,7 +1794,8 @@ 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)
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL) < 0)
die(_("unable to write index file"));
if (repo_index_has_changes(the_repository, NULL, &sb)) {
@@ -1930,7 +1944,7 @@ static void am_resolve(struct am_state *state, int allow_empty)
}
}
- if (unmerged_cache()) {
+ if (unmerged_index(&the_index)) {
printf_ln(_("You still have unmerged paths in your index.\n"
"You should 'git add' each file with resolved conflicts to mark them as such.\n"
"You might run `git rm` on a file to accept \"deleted by them\" for it."));
@@ -1967,9 +1981,9 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
if (parse_tree(head) || parse_tree(remote))
return -1;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
@@ -2007,7 +2021,7 @@ static int merge_tree(struct tree *tree)
if (parse_tree(tree))
return -1;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
@@ -2045,12 +2059,12 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
if (!remote_tree)
return error(_("Could not parse object '%s'."), oid_to_hex(remote));
- read_cache_unmerged();
+ repo_read_index_unmerged(the_repository);
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_cache_as_tree(&index, 0, NULL))
+ if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL))
return -1;
index_tree = parse_tree_indirect(&index);
@@ -2087,7 +2101,7 @@ static void am_skip(struct am_state *state)
am_rerere_clear();
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
oidcpy(&head, the_hash_algo->empty_tree);
if (clean_index(&head, &head))
@@ -2129,7 +2143,7 @@ static int safe_to_abort(const struct am_state *state)
oidclr(&abort_safety);
strbuf_release(&sb);
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
oidclr(&head);
if (oideq(&head, &abort_safety))
@@ -2162,7 +2176,7 @@ static void am_abort(struct am_state *state)
if (!has_curr_head)
oidcpy(&curr_head, the_hash_algo->empty_tree);
- has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
+ has_orig_head = !repo_get_oid(the_repository, "ORIG_HEAD", &orig_head);
if (!has_orig_head)
oidcpy(&orig_head, the_hash_algo->empty_tree);
@@ -2180,28 +2194,26 @@ 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, enum resume_type resume_mode)
{
struct strbuf sb = STRBUF_INIT;
const char *patch_path;
int len;
if (!is_null_oid(&state->orig_commit)) {
- const char *av[4] = { "show", NULL, "--", NULL };
- char *new_oid_str;
- int ret;
+ struct child_process cmd = CHILD_PROCESS_INIT;
- av[1] = new_oid_str = xstrdup(oid_to_hex(&state->orig_commit));
- ret = run_command_v_opt(av, RUN_GIT_CMD);
- free(new_oid_str);
- return ret;
+ strvec_pushl(&cmd.args, "show", oid_to_hex(&state->orig_commit),
+ "--", NULL);
+ cmd.git_cmd = 1;
+ return run_command(&cmd);
}
- switch (sub_mode) {
- case SHOW_PATCH_RAW:
+ switch (resume_mode) {
+ case RESUME_SHOW_PATCH_RAW:
patch_path = am_path(state, msgnum(state));
break;
- case SHOW_PATCH_DIFF:
+ case RESUME_SHOW_PATCH_DIFF:
patch_path = am_path(state, "patch");
break;
default:
@@ -2248,77 +2260,35 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
return 0;
}
-enum resume_type {
- RESUME_FALSE = 0,
- RESUME_APPLY,
- RESUME_RESOLVED,
- RESUME_SKIP,
- RESUME_ABORT,
- RESUME_QUIT,
- RESUME_SHOW_PATCH,
- RESUME_ALLOW_EMPTY,
-};
-
-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);
+ BUG_ON_OPT_NEG(unset);
+
+ if (!arg)
+ *opt_value = opt->defval;
+ else if (!strcmp(arg, "raw"))
+ *opt_value = RESUME_SHOW_PATCH_RAW;
+ else if (!strcmp(arg, "diff"))
+ *opt_value = RESUME_SHOW_PATCH_DIFF;
/*
* 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;
-
- BUG_ON_OPT_NEG(unset);
-
- 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 '%s': '%s'"),
- "--show-current-patch", arg);
- }
-
- if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
- return error(_("options '%s=%s' and '%s=%s' "
- "cannot be used together"),
- "--show-current-patch", "--show-current-patch", arg, valid_modes[resume->sub_mode]);
-
- resume->mode = RESUME_SHOW_PATCH;
- resume->sub_mode = new_value;
+ else
+ return error(_("invalid value for '%s': '%s'"),
+ "--show-current-patch", arg);
return 0;
}
-static int git_am_config(const char *k, const char *v, void *cb UNUSED)
-{
- int status;
-
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
-
- return git_default_config(k, v, NULL);
-}
-
int cmd_am(int argc, const char **argv, const char *prefix)
{
struct am_state state;
int binary = -1;
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
- struct resume_mode resume = { .mode = RESUME_FALSE };
+ enum resume_type resume_mode = RESUME_FALSE;
int in_progress;
int ret = 0;
@@ -2331,6 +2301,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('i', "interactive", &state.interactive,
N_("run interactively")),
+ OPT_BOOL('n', "no-verify", &state.no_verify,
+ N_("bypass pre-applypatch and applypatch-msg hooks")),
OPT_HIDDEN_BOOL('b', "binary", &binary,
N_("historical option -- no-op")),
OPT_BOOL('3', "3way", &state.threeway,
@@ -2347,12 +2319,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
OPT_BOOL('m', "message-id", &state.message_id,
N_("pass -m flag to git-mailinfo")),
- OPT_SET_INT_F(0, "keep-cr", &keep_cr,
- N_("pass --keep-cr flag to git-mailsplit for mbox format"),
- 1, PARSE_OPT_NONEG),
- OPT_SET_INT_F(0, "no-keep-cr", &keep_cr,
- N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
- 0, PARSE_OPT_NONEG),
+ OPT_SET_INT(0, "keep-cr", &keep_cr,
+ N_("pass --keep-cr flag to git-mailsplit for mbox format"),
+ 1),
OPT_BOOL('c', "scissors", &state.scissors,
N_("strip everything before a scissors line")),
OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
@@ -2390,27 +2359,27 @@ 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_mode,
N_("continue applying patches after resolving a conflict"),
RESUME_RESOLVED),
- OPT_CMDMODE('r', "resolved", &resume.mode,
+ OPT_CMDMODE('r', "resolved", &resume_mode,
N_("synonyms for --continue"),
RESUME_RESOLVED),
- OPT_CMDMODE(0, "skip", &resume.mode,
+ OPT_CMDMODE(0, "skip", &resume_mode,
N_("skip the current patch"),
RESUME_SKIP),
- OPT_CMDMODE(0, "abort", &resume.mode,
+ OPT_CMDMODE(0, "abort", &resume_mode,
N_("restore the original branch and abort the patching operation"),
RESUME_ABORT),
- OPT_CMDMODE(0, "quit", &resume.mode,
+ OPT_CMDMODE(0, "quit", &resume_mode,
N_("abort the patching operation but keep HEAD where it is"),
RESUME_QUIT),
- { OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
+ { 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, "allow-empty", &resume.mode,
+ parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW },
+ OPT_CMDMODE(0, "allow-empty", &resume_mode,
N_("record the empty patch as an empty commit"),
RESUME_ALLOW_EMPTY),
OPT_BOOL(0, "committer-date-is-author-date",
@@ -2422,7 +2391,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"),
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_CALLBACK_F(STOP_ON_EMPTY_COMMIT, "empty", &state.empty_type, "{stop,drop,keep}",
+ OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
N_("how to handle empty patches"),
PARSE_OPT_NONEG, am_option_parse_empty),
OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
@@ -2433,7 +2402,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(usage, options);
- git_config(git_am_config, NULL);
+ git_config(git_default_config, NULL);
am_state_init(&state);
@@ -2465,12 +2434,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_mode == 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_mode == RESUME_FALSE)
+ resume_mode = RESUME_APPLY;
if (state.signoff == SIGNOFF_EXPLICIT)
am_append_signoff(&state);
@@ -2484,7 +2453,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_mode == RESUME_ABORT || resume_mode == RESUME_QUIT) {
am_destroy(&state);
am_state_release(&state);
return 0;
@@ -2495,7 +2464,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
state.dir);
}
- if (resume.mode)
+ if (resume_mode)
die(_("Resolve operation not in progress, we are not resuming."));
for (i = 0; i < argc; i++) {
@@ -2513,7 +2482,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
strvec_clear(&paths);
}
- switch (resume.mode) {
+ switch (resume_mode) {
case RESUME_FALSE:
am_run(&state, 0);
break;
@@ -2522,7 +2491,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
break;
case RESUME_RESOLVED:
case RESUME_ALLOW_EMPTY:
- am_resolve(&state, resume.mode == RESUME_ALLOW_EMPTY ? 1 : 0);
+ am_resolve(&state, resume_mode == RESUME_ALLOW_EMPTY ? 1 : 0);
break;
case RESUME_SKIP:
am_skip(&state);
@@ -2534,8 +2503,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
am_rerere_clear();
am_destroy(&state);
break;
- case RESUME_SHOW_PATCH:
- ret = show_patch(&state, resume.sub_mode);
+ case RESUME_SHOW_PATCH_RAW:
+ case RESUME_SHOW_PATCH_DIFF:
+ ret = show_patch(&state, resume_mode);
break;
default:
BUG("invalid resume value");
diff --git a/builtin/apply.c b/builtin/apply.c
index 555219de40..861a01910c 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,6 +1,6 @@
-#include "cache.h"
#include "builtin.h"
-#include "parse-options.h"
+#include "gettext.h"
+#include "repository.h"
#include "apply.h"
static const char * const apply_usage[] = {
diff --git a/builtin/archive.c b/builtin/archive.c
index f094390ee0..15ee1ec7bb 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -2,13 +2,13 @@
* Copyright (c) 2006 Franck Bui-Huu
* Copyright (c) 2006 Rene Scharfe
*/
-#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "gettext.h"
#include "transport.h"
#include "parse-options.h"
#include "pkt-line.h"
-#include "sideband.h"
+#include "repository.h"
static void create_output_file(const char *output_file)
{
@@ -81,7 +81,7 @@ static int run_remote_archiver(int argc, const char **argv,
int cmd_archive(int argc, const char **argv, const char *prefix)
{
const char *exec = "git-upload-archive";
- const char *output = NULL;
+ char *output = NULL;
const char *remote = NULL;
struct option local_opts[] = {
OPT_FILENAME('o', "output", &output,
@@ -106,5 +106,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+ UNLEAK(output);
return write_archive(argc, argv, prefix, the_repository, output, 0);
}
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
index 28ef7ec2a4..f69c3f7e43 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1,37 +1,62 @@
#include "builtin.h"
-#include "cache.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "bisect.h"
#include "refs.h"
-#include "dir.h"
#include "strvec.h"
#include "run-command.h"
+#include "oid-array.h"
+#include "path.h"
#include "prompt.h"
#include "quote.h"
#include "revision.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
-static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
-static const char * const git_bisect_helper_usage[] = {
- N_("git bisect--helper --bisect-reset [<commit>]"),
- "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
- N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
- " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
- "git bisect--helper --bisect-next",
- N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
- N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
- N_("git bisect--helper --bisect-replay <filename>"),
- N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
- "git bisect--helper --bisect-visualize",
- N_("git bisect--helper --bisect-run <cmd>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+ N_("git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]" \
+ " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+ " [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+ N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+ "git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+ N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+ "git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+ N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+ "git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+ N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+ "git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+ N_("git bisect run <cmd> [<arg>...]")
+
+static const char * const git_bisect_usage[] = {
+ BUILTIN_GIT_BISECT_START_USAGE,
+ BUILTIN_GIT_BISECT_STATE_USAGE,
+ BUILTIN_GIT_BISECT_TERMS_USAGE,
+ BUILTIN_GIT_BISECT_SKIP_USAGE,
+ BUILTIN_GIT_BISECT_NEXT_USAGE,
+ BUILTIN_GIT_BISECT_RESET_USAGE,
+ BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+ BUILTIN_GIT_BISECT_REPLAY_USAGE,
+ BUILTIN_GIT_BISECT_LOG_USAGE,
+ BUILTIN_GIT_BISECT_RUN_USAGE,
NULL
};
@@ -206,32 +231,31 @@ static int bisect_reset(const char *commit)
struct strbuf branch = STRBUF_INIT;
if (!commit) {
- if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
+ if (!strbuf_read_file(&branch, git_path_bisect_start(), 0))
printf(_("We are not bisecting.\n"));
- return 0;
- }
- strbuf_rtrim(&branch);
+ else
+ strbuf_rtrim(&branch);
} else {
struct object_id oid;
- if (get_oid_commit(commit, &oid))
+ if (repo_get_oid_commit(the_repository, commit, &oid))
return error(_("'%s' is not a valid commit"), commit);
strbuf_addstr(&branch, commit);
}
- if (!ref_exists("BISECT_HEAD")) {
- struct strvec argv = STRVEC_INIT;
+ if (branch.len && !ref_exists("BISECT_HEAD")) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
- if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
+ cmd.git_cmd = 1;
+ strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
+ branch.buf, "--", NULL);
+ if (run_command(&cmd)) {
error(_("could not check out original"
" HEAD '%s'. Try 'git bisect"
" reset <commit>'."), branch.buf);
strbuf_release(&branch);
- strvec_clear(&argv);
return -1;
}
- strvec_clear(&argv);
}
strbuf_release(&branch);
@@ -245,7 +269,8 @@ static void log_commit(FILE *fp, char *fmt, const char *state,
struct strbuf commit_msg = STRBUF_INIT;
char *label = xstrfmt(fmt, state);
- format_commit_message(commit, "%s", &commit_msg, &pp);
+ repo_format_commit_message(the_repository, commit, "%s", &commit_msg,
+ &pp);
fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
commit_msg.buf);
@@ -272,7 +297,7 @@ static int bisect_write(const char *state, const char *rev,
goto finish;
}
- if (get_oid(rev, &oid)) {
+ if (repo_get_oid(the_repository, rev, &oid)) {
res = error(_("couldn't get the oid of the rev '%s'"), rev);
goto finish;
}
@@ -547,7 +572,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
* sets up a revision walk.
*/
reset_revision_walk();
- init_revisions(revs, NULL);
+ repo_init_revisions(the_repository, revs, NULL);
setup_revisions(0, NULL, revs, NULL);
for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
cb.object_flags = UNINTERESTING;
@@ -583,8 +608,8 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
while ((commit = get_revision(&revs)) != NULL) {
strbuf_reset(&commit_name);
- format_commit_message(commit, "%s",
- &commit_name, &pp);
+ repo_format_commit_message(the_repository, commit, "%s",
+ &commit_name, &pp);
fprintf(fp, "# possible first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&commit->object.oid),
commit_name.buf);
@@ -613,7 +638,8 @@ static int bisect_successful(struct bisect_terms *terms)
read_ref(bad_ref, &oid);
commit = lookup_commit_reference_by_name(bad_ref);
- format_commit_message(commit, "%s", &commit_name, &pp);
+ repo_format_commit_message(the_repository, commit, "%s", &commit_name,
+ &pp);
res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&commit->object.oid),
@@ -657,7 +683,8 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
return bisect_next(terms, prefix);
}
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int no_checkout = 0;
int first_parent_only = 0;
@@ -754,7 +781,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
*/
head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
if (!head)
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("bad HEAD - I need a HEAD"));
/*
@@ -765,10 +792,12 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
strbuf_read_file(&start_head, git_path_bisect_start(), 0);
strbuf_trim(&start_head);
if (!no_checkout) {
- const char *argv[] = { "checkout", start_head.buf,
- "--", NULL };
+ struct child_process cmd = CHILD_PROCESS_INIT;
- if (run_command_v_opt(argv, RUN_GIT_CMD)) {
+ cmd.git_cmd = 1;
+ strvec_pushl(&cmd.args, "checkout", start_head.buf,
+ "--", NULL);
+ if (run_command(&cmd)) {
res = error(_("checking out '%s' failed."
" Try 'git bisect start "
"<valid-branch>'."),
@@ -778,19 +807,12 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
}
} else {
/* Get the rev from where we start. */
- if (!get_oid(head, &head_oid) &&
+ if (!repo_get_oid(the_repository, head, &head_oid) &&
!starts_with(head, "refs/heads/")) {
strbuf_reset(&start_head);
strbuf_addstr(&start_head, oid_to_hex(&head_oid));
- } else if (!get_oid(head, &head_oid) &&
+ } else if (!repo_get_oid(the_repository, head, &head_oid) &&
skip_prefix(head, "refs/heads/", &head)) {
- /*
- * This error message should only be triggered by
- * cogito usage, and cogito users should understand
- * it relates to cg-seek.
- */
- if (!is_empty_or_missing_file(git_path_head_name()))
- return error(_("won't bisect on cg-seek'ed tree"));
strbuf_addstr(&start_head, head);
} else {
return error(_("bad HEAD - strange symbolic ref"));
@@ -812,7 +834,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
write_file(git_path_bisect_first_parent(), "\n");
if (no_checkout) {
- if (get_oid(start_head.buf, &oid) < 0) {
+ if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
res = error(_("invalid ref: '%s'"), start_head.buf);
goto finish;
}
@@ -885,18 +907,17 @@ static int bisect_autostart(struct bisect_terms *terms)
yesno = git_prompt(_("Do you want me to do it for you "
"[Y/n]? "), PROMPT_ECHO);
res = tolower(*yesno) == 'n' ?
- -1 : bisect_start(terms, empty_strvec, 0);
+ -1 : bisect_start(terms, 0, empty_strvec);
return res;
}
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
- int argc)
+static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
+ const char **argv)
{
const char *state;
int i, verify_expected = 1;
struct object_id oid, expected;
- struct strbuf buf = STRBUF_INIT;
struct oid_array revs = OID_ARRAY_INIT;
if (!argc)
@@ -917,11 +938,12 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
if (argc == 0) {
const char *head = "BISECT_HEAD";
- enum get_oid_result res_head = get_oid(head, &oid);
+ enum get_oid_result res_head = repo_get_oid(the_repository,
+ head, &oid);
if (res_head == MISSING_OBJECT) {
head = "HEAD";
- res_head = get_oid(head, &oid);
+ res_head = repo_get_oid(the_repository, head, &oid);
}
if (res_head)
@@ -937,7 +959,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
for (; argc; argc--, argv++) {
struct commit *commit;
- if (get_oid(*argv, &oid)){
+ if (repo_get_oid(the_repository, *argv, &oid)){
error(_("Bad rev input: %s"), *argv);
oid_array_clear(&revs);
return BISECT_FAILED;
@@ -950,10 +972,8 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
oid_array_append(&revs, &commit->object.oid);
}
- if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
- get_oid_hex(buf.buf, &expected) < 0)
+ if (read_ref("BISECT_EXPECTED_REV", &expected))
verify_expected = 0; /* Ignore invalid file contents */
- strbuf_release(&buf);
for (i = 0; i < revs.nr; i++) {
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
@@ -962,7 +982,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
}
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
unlink_or_warn(git_path_bisect_ancestors_ok());
- unlink_or_warn(git_path_bisect_expected_rev());
+ delete_ref(NULL, "BISECT_EXPECTED_REV", NULL, REF_NO_DEREF);
verify_expected = 0;
}
}
@@ -1010,7 +1030,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
struct strvec argv = STRVEC_INIT;
int res;
sq_dequote_to_strvec(rev, &argv);
- res = bisect_start(terms, argv.v, argv.nr);
+ res = bisect_start(terms, argv.nr, argv.v);
strvec_clear(&argv);
return res;
}
@@ -1060,7 +1080,8 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
return bisect_auto_next(terms, NULL);
}
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int i;
enum bisect_error res;
@@ -1075,7 +1096,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
struct rev_info revs;
struct commit *commit;
- init_revisions(&revs, NULL);
+ repo_init_revisions(the_repository, &revs, NULL);
setup_revisions(2, argv + i - 1, &revs, NULL);
if (prepare_revision_walk(&revs))
@@ -1090,48 +1111,47 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
strvec_push(&argv_state, argv[i]);
}
}
- res = bisect_state(terms, argv_state.v, argv_state.nr);
+ res = bisect_state(terms, argv_state.nr, argv_state.v);
strvec_clear(&argv_state);
return res;
}
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+ const char **argv)
{
- struct strvec args = STRVEC_INIT;
- int flags = RUN_COMMAND_NO_STDIN, res = 0;
+ struct child_process cmd = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT;
if (bisect_next_check(terms, NULL) != 0)
return BISECT_FAILED;
+ cmd.no_stdin = 1;
if (!argc) {
if ((getenv("DISPLAY") || getenv("SESSIONNAME") || getenv("MSYSTEM") ||
getenv("SECURITYSESSIONID")) && exists_in_PATH("gitk")) {
- strvec_push(&args, "gitk");
+ strvec_push(&cmd.args, "gitk");
} else {
- strvec_push(&args, "log");
- flags |= RUN_GIT_CMD;
+ strvec_push(&cmd.args, "log");
+ cmd.git_cmd = 1;
}
} else {
if (argv[0][0] == '-') {
- strvec_push(&args, "log");
- flags |= RUN_GIT_CMD;
+ strvec_push(&cmd.args, "log");
+ cmd.git_cmd = 1;
} else if (strcmp(argv[0], "tig") && !starts_with(argv[0], "git"))
- flags |= RUN_GIT_CMD;
+ cmd.git_cmd = 1;
- strvec_pushv(&args, argv);
+ strvec_pushv(&cmd.args, argv);
}
- strvec_pushl(&args, "--bisect", "--", NULL);
+ strvec_pushl(&cmd.args, "--bisect", "--", NULL);
strbuf_read_file(&sb, git_path_bisect_names(), 0);
- sq_dequote_to_strvec(sb.buf, &args);
+ sq_dequote_to_strvec(sb.buf, &cmd.args);
strbuf_release(&sb);
- res = run_command_v_opt(args.v, flags);
- strvec_clear(&args);
- return res;
+ return run_command(&cmd);
}
static int get_first_good(const char *refname UNUSED,
@@ -1142,8 +1162,17 @@ static int get_first_good(const char *refname UNUSED,
return 1;
}
-static int verify_good(const struct bisect_terms *terms,
- const char **quoted_argv)
+static int do_bisect_run(const char *command)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ printf(_("running %s\n"), command);
+ cmd.use_shell = 1;
+ strvec_push(&cmd.args, command);
+ return run_command(&cmd);
+}
+
+static int verify_good(const struct bisect_terms *terms, const char *command)
{
int rc;
enum bisect_error res;
@@ -1163,8 +1192,7 @@ static int verify_good(const struct bisect_terms *terms,
if (res != BISECT_OK)
return -1;
- printf(_("running %s\n"), quoted_argv[0]);
- rc = run_command_v_opt(quoted_argv, RUN_USING_SHELL);
+ rc = do_bisect_run(command);
res = bisect_checkout(&current_rev, no_checkout);
if (res != BISECT_OK)
@@ -1173,11 +1201,10 @@ static int verify_good(const struct bisect_terms *terms,
return rc;
}
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
{
int res = BISECT_OK;
struct strbuf command = STRBUF_INIT;
- struct strvec run_args = STRVEC_INIT;
const char *new_state;
int temporary_stdout_fd, saved_stdout;
int is_first_run = 1;
@@ -1185,18 +1212,15 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (bisect_next_check(terms, NULL))
return BISECT_FAILED;
- if (argc)
- sq_quote_argv(&command, argv);
- else {
+ if (!argc) {
error(_("bisect run failed: no command provided."));
return BISECT_FAILED;
}
- strvec_push(&run_args, command.buf);
-
+ sq_quote_argv(&command, argv);
+ strbuf_ltrim(&command);
while (1) {
- printf(_("running %s\n"), command.buf);
- res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
+ res = do_bisect_run(command.buf);
/*
* Exit code 126 and 127 can either come from the shell
@@ -1206,10 +1230,10 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
* missing or non-executable script.
*/
if (is_first_run && (res == 126 || res == 127)) {
- int rc = verify_good(terms, run_args.v);
+ int rc = verify_good(terms, command.buf);
is_first_run = 0;
- if (rc < 0) {
- error(_("unable to verify '%s' on good"
+ if (rc < 0 || 128 <= rc) {
+ error(_("unable to verify %s on good"
" revision"), command.buf);
res = BISECT_FAILED;
break;
@@ -1224,7 +1248,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res < 0 || 128 <= res) {
error(_("bisect run failed: exit code %d from"
- " '%s' is < 0 or >= 128"), res, command.buf);
+ " %s is < 0 or >= 128"), res, command.buf);
break;
}
@@ -1246,7 +1270,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
saved_stdout = dup(1);
dup2(temporary_stdout_fd, 1);
- res = bisect_state(terms, &new_state, 1);
+ res = bisect_state(terms, 1, &new_state);
fflush(stdout);
dup2(saved_stdout, 1);
@@ -1258,14 +1282,14 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res == BISECT_ONLY_SKIPPED_LEFT)
error(_("bisect run cannot continue any more"));
else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
- printf(_("bisect run success"));
+ puts(_("bisect run success"));
res = BISECT_OK;
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
- printf(_("bisect found first bad commit"));
+ puts(_("bisect found first bad commit"));
res = BISECT_OK;
} else if (res) {
- error(_("bisect run failed: 'git bisect--helper --bisect-state"
- " %s' exited with error code %d"), new_state, res);
+ error(_("bisect run failed: 'git bisect %s'"
+ " exited with error code %d"), new_state, res);
} else {
continue;
}
@@ -1273,126 +1297,147 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
}
strbuf_release(&command);
- strvec_clear(&run_args);
return res;
}
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+ if (argc > 1)
+ return error(_("'%s' requires either no argument or a commit"),
+ "git bisect reset");
+ return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ if (argc > 1)
+ return error(_("'%s' requires 0 or 1 argument"),
+ "git bisect terms");
+ res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
{
- enum {
- BISECT_RESET = 1,
- BISECT_NEXT_CHECK,
- BISECT_TERMS,
- BISECT_START,
- BISECT_AUTOSTART,
- BISECT_NEXT,
- BISECT_STATE,
- BISECT_LOG,
- BISECT_REPLAY,
- BISECT_SKIP,
- BISECT_VISUALIZE,
- BISECT_RUN,
- } cmdmode = 0;
- int res = 0, nolog = 0;
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ set_terms(&terms, "bad", "good");
+ res = bisect_start(&terms, argc, argv);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ if (argc)
+ return error(_("'%s' requires 0 arguments"),
+ "git bisect next");
+ get_terms(&terms);
+ res = bisect_next(&terms, prefix);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
+{
+ return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ if (argc != 1)
+ return error(_("no logfile given"));
+ set_terms(&terms, "bad", "good");
+ res = bisect_replay(&terms, argv[0]);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ set_terms(&terms, "bad", "good");
+ get_terms(&terms);
+ res = bisect_skip(&terms, argc, argv);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ get_terms(&terms);
+ res = bisect_visualize(&terms, argc, argv);
+ free_terms(&terms);
+ return res;
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+ int res;
+ struct bisect_terms terms = { 0 };
+
+ if (!argc)
+ return error(_("'%s' failed: no command provided."), "git bisect run");
+ get_terms(&terms);
+ res = bisect_run(&terms, argc, argv);
+ free_terms(&terms);
+ return res;
+}
+
+int cmd_bisect(int argc, const char **argv, const char *prefix)
+{
+ int res = 0;
+ parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
- OPT_CMDMODE(0, "bisect-reset", &cmdmode,
- N_("reset the bisection state"), BISECT_RESET),
- OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
- N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
- OPT_CMDMODE(0, "bisect-terms", &cmdmode,
- N_("print out the bisect terms"), BISECT_TERMS),
- OPT_CMDMODE(0, "bisect-start", &cmdmode,
- N_("start the bisect session"), BISECT_START),
- OPT_CMDMODE(0, "bisect-next", &cmdmode,
- N_("find the next bisection commit"), BISECT_NEXT),
- OPT_CMDMODE(0, "bisect-state", &cmdmode,
- N_("mark the state of ref (or refs)"), BISECT_STATE),
- OPT_CMDMODE(0, "bisect-log", &cmdmode,
- N_("list the bisection steps so far"), BISECT_LOG),
- OPT_CMDMODE(0, "bisect-replay", &cmdmode,
- N_("replay the bisection process from the given file"), BISECT_REPLAY),
- OPT_CMDMODE(0, "bisect-skip", &cmdmode,
- N_("skip some commits for checkout"), BISECT_SKIP),
- OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
- N_("visualize the bisection"), BISECT_VISUALIZE),
- OPT_CMDMODE(0, "bisect-run", &cmdmode,
- N_("use <cmd>... to automatically bisect"), BISECT_RUN),
- OPT_BOOL(0, "no-log", &nolog,
- N_("no log for BISECT_WRITE")),
+ OPT_SUBCOMMAND("reset", &fn, cmd_bisect__reset),
+ OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
+ OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
+ OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
+ OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
+ OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
+ OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
+ OPT_SUBCOMMAND("visualize", &fn, cmd_bisect__visualize),
+ OPT_SUBCOMMAND("view", &fn, cmd_bisect__visualize),
+ OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
OPT_END()
};
- struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+ argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL);
- argc = parse_options(argc, argv, prefix, options,
- git_bisect_helper_usage,
- PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
+ if (!fn) {
+ struct bisect_terms terms = { 0 };
- if (!cmdmode)
- usage_with_options(git_bisect_helper_usage, options);
+ if (!argc)
+ usage_msg_opt(_("need a command"), git_bisect_usage, options);
- switch (cmdmode) {
- case BISECT_RESET:
- if (argc > 1)
- return error(_("--bisect-reset requires either no argument or a commit"));
- res = bisect_reset(argc ? argv[0] : NULL);
- break;
- case BISECT_TERMS:
- if (argc > 1)
- return error(_("--bisect-terms requires 0 or 1 argument"));
- res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
- break;
- case BISECT_START:
- set_terms(&terms, "bad", "good");
- res = bisect_start(&terms, argv, argc);
- break;
- case BISECT_NEXT:
- if (argc)
- return error(_("--bisect-next requires 0 arguments"));
- get_terms(&terms);
- res = bisect_next(&terms, prefix);
- break;
- case BISECT_STATE:
- set_terms(&terms, "bad", "good");
- get_terms(&terms);
- res = bisect_state(&terms, argv, argc);
- break;
- case BISECT_LOG:
- if (argc)
- return error(_("--bisect-log requires 0 arguments"));
- res = bisect_log();
- break;
- case BISECT_REPLAY:
- if (argc != 1)
- return error(_("no logfile given"));
- set_terms(&terms, "bad", "good");
- res = bisect_replay(&terms, argv[0]);
- break;
- case BISECT_SKIP:
set_terms(&terms, "bad", "good");
get_terms(&terms);
- res = bisect_skip(&terms, argv, argc);
- break;
- case BISECT_VISUALIZE:
- get_terms(&terms);
- res = bisect_visualize(&terms, argv, argc);
- break;
- case BISECT_RUN:
- if (!argc)
- return error(_("bisect run failed: no command provided."));
- get_terms(&terms);
- res = bisect_run(&terms, argv, argc);
- break;
- default:
- BUG("unknown subcommand %d", cmdmode);
+ if (check_and_set_terms(&terms, argv[0]))
+ usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+ options, argv[0]);
+ res = bisect_state(&terms, argc, argv);
+ free_terms(&terms);
+ } else {
+ argc--;
+ argv++;
+ res = fn(argc, argv, prefix);
}
- 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_INTERNAL_SUCCESS_1ST_BAD_FOUND))
- res = BISECT_OK;
- return -res;
+ return is_bisect_success(res) ? 0 : -res;
}
diff --git a/builtin/blame.c b/builtin/blame.c
index a9fe8cf7a6..db1f56de61 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -5,10 +5,13 @@
* See COPYING for licensing conditions
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "color.h"
#include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "commit.h"
#include "diff.h"
@@ -22,14 +25,18 @@
#include "userdiff.h"
#include "line-range.h"
#include "line-log.h"
-#include "dir.h"
#include "progress.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
#include "blame.h"
#include "refs.h"
+#include "setup.h"
#include "tag.h"
+#include "write-or-die.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
+static char annotate_usage[] = N_("git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>");
static const char *blame_opt_usage[] = {
blame_usage,
@@ -38,6 +45,13 @@ static const char *blame_opt_usage[] = {
NULL
};
+static const char *annotate_opt_usage[] = {
+ annotate_usage,
+ "",
+ N_("<rev-opts> are documented in git-rev-list(1)"),
+ NULL
+};
+
static int longest_file;
static int longest_author;
static int max_orig_digits;
@@ -191,13 +205,13 @@ static void get_commit_info(struct commit *commit,
const char *message;
encoding = get_log_output_encoding();
- message = logmsg_reencode(commit, NULL, encoding);
+ message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
get_ac_line(message, "\nauthor ",
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
if (!detailed) {
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(the_repository, commit, message);
return;
}
@@ -211,7 +225,7 @@ static void get_commit_info(struct commit *commit,
else
strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
- unuse_commit_buffer(commit, message);
+ repo_unuse_commit_buffer(the_repository, commit, message);
}
/*
@@ -593,8 +607,9 @@ static int read_ancestry(const char *graft_file)
static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
{
- const char *uniq = find_unique_abbrev(&suspect->commit->object.oid,
- auto_abbrev);
+ const char *uniq = repo_find_unique_abbrev(the_repository,
+ &suspect->commit->object.oid,
+ auto_abbrev);
int len = strlen(uniq);
if (auto_abbrev < len)
return len;
@@ -677,7 +692,8 @@ static const char *add_prefix(const char *prefix, const char *path)
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
}
-static int git_blame_config(const char *var, const char *value, void *cb)
+static int git_blame_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "blame.showroot")) {
show_root = git_config_bool(var, value);
@@ -731,6 +747,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "blame.coloring")) {
+ if (!value)
+ return config_error_nonbool(var);
if (!strcmp(value, "repeatedLines")) {
coloring_mode |= OUTPUT_COLOR_LINE;
} else if (!strcmp(value, "highlightRecent")) {
@@ -750,7 +768,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
if (userdiff_config(var, value) < 0)
return -1;
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static int blame_copy_callback(const struct option *option, const char *arg, int unset)
@@ -794,7 +812,7 @@ static int is_a_rev(const char *name)
{
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return 0;
return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
}
@@ -837,7 +855,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,
peel_to_commit_oid, sb);
}
for_each_string_list_item(i, ignore_rev_list) {
- if (get_oid_committish(i->string, &oid) ||
+ if (repo_get_oid_committish(the_repository, i->string, &oid) ||
peel_to_commit_oid(&oid, sb))
die(_("cannot find revision %s to ignore"), i->string);
oidset_insert(&sb->ignore_list, &oid);
@@ -899,6 +917,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
long anchor;
const int hexsz = the_hash_algo->hexsz;
long num_lines = 0;
+ const char *str_usage = cmd_is_annotate ? annotate_usage : blame_usage;
+ const char **opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
@@ -914,7 +934,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_options_start(&ctx, argc, argv, prefix, options,
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
for (;;) {
- switch (parse_options_step(&ctx, options, blame_opt_usage)) {
+ switch (parse_options_step(&ctx, options, opt_usage)) {
case PARSE_OPT_NON_OPTION:
case PARSE_OPT_UNKNOWN:
break;
@@ -934,7 +954,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
ctx.argv[0] = "--children";
reverse = 1;
}
- parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
+ parse_revision_opt(&revs, &ctx, options, opt_usage);
}
parse_done:
revision_opts_finish(&revs);
@@ -1040,7 +1060,7 @@ parse_done:
switch (argc - dashdash_pos - 1) {
case 2: /* (1b) */
if (argc != 4)
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
/* reorder for the new way: <rev> -- <path> */
argv[1] = argv[3];
argv[3] = argv[2];
@@ -1051,11 +1071,11 @@ parse_done:
argv[argc] = NULL;
break;
default:
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
}
} else {
if (argc < 2)
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */
path = add_prefix(prefix, argv[1]);
argv[1] = argv[2];
@@ -1113,7 +1133,7 @@ parse_done:
nth_line_cb, &sb, lno, anchor,
&bottom, &top, sb.path,
the_repository->index))
- usage(blame_usage);
+ usage(str_usage);
if ((!lno && (top || bottom)) || lno < bottom)
die(Q_("file %s has only %lu line",
"file %s has only %lu lines",
diff --git a/builtin/branch.c b/builtin/branch.c
index e0e0af4320..0a32d1b6c8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -5,21 +5,22 @@
* Based on git-branch.sh by Junio C Hamano.
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "color.h"
+#include "editor.h"
+#include "environment.h"
#include "refs.h"
#include "commit.h"
-#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "remote.h"
#include "parse-options.h"
#include "branch.h"
-#include "diff.h"
-#include "revision.h"
+#include "path.h"
#include "string-list.h"
#include "column.h"
#include "utf8.h"
-#include "wt-status.h"
#include "ref-filter.h"
#include "worktree.h"
#include "help.h"
@@ -77,7 +78,8 @@ static unsigned int colopts;
define_list_config_array(color_branch_slots);
-static int git_branch_config(const char *var, const char *value, void *cb)
+static int git_branch_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
const char *slot_name;
@@ -111,7 +113,10 @@ static int git_branch_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_color_default_config(var, value, cb);
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static const char *branch_get_color(enum color_branch ix)
@@ -150,24 +155,25 @@ static int branch_merged(int kind, const char *name,
if (!reference_rev)
reference_rev = head_rev;
- merged = in_merge_bases(rev, reference_rev);
+ merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
+ reference_rev) : 0;
/*
* After the safety valve is fully redefined to "check with
* upstream, if any, otherwise with HEAD", we should just
- * return the result of the in_merge_bases() above without
+ * return the result of the repo_in_merge_bases() above without
* any of the following code, but during the transition period,
* a gentle reminder is in order.
*/
if ((head_rev != reference_rev) &&
- in_merge_bases(rev, head_rev) != merged) {
+ (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
if (merged)
warning(_("deleting branch '%s' that has been merged to\n"
- " '%s', but not yet merged to HEAD."),
+ " '%s', but not yet merged to HEAD"),
name, reference_name);
else
warning(_("not deleting branch '%s' that is not yet merged to\n"
- " '%s', even though it is merged to HEAD."),
+ " '%s', even though it is merged to HEAD"),
name, reference_name);
}
free(reference_name_to_free);
@@ -180,13 +186,13 @@ static int check_branch_commit(const char *branchname, const char *refname,
{
struct commit *rev = lookup_commit_reference(the_repository, oid);
if (!force && !rev) {
- error(_("Couldn't look up commit object for '%s'"), refname);
+ error(_("couldn't look up commit object for '%s'"), refname);
return -1;
}
if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
- error(_("The branch '%s' is not fully merged.\n"
+ error(_("the branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, "
- "run 'git branch -D %s'."), branchname, branchname);
+ "run 'git branch -D %s'"), branchname, branchname);
return -1;
}
return 0;
@@ -197,7 +203,7 @@ static void delete_branch_config(const char *branchname)
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "branch.%s", branchname);
if (git_config_rename_section(buf.buf, NULL) < 0)
- warning(_("Update of config-file failed"));
+ warning(_("update of config-file failed"));
strbuf_release(&buf);
}
@@ -216,10 +222,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *item;
int branch_name_pos;
+ const char *fmt_remotes = "refs/remotes/%s";
switch (kinds) {
case FILTER_REFS_REMOTES:
- fmt = "refs/remotes/%s";
+ fmt = fmt_remotes;
/* For subsequent UI messages */
remote_branch = 1;
allowed_interpret = INTERPRET_BRANCH_REMOTE;
@@ -235,11 +242,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
branch_name_pos = strcspn(fmt, "%");
- if (!force) {
+ if (!force)
head_rev = lookup_commit_reference(the_repository, &head_oid);
- if (!head_rev)
- die(_("Couldn't look up commit object for HEAD"));
- }
for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
char *target = NULL;
@@ -252,8 +256,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (kinds == FILTER_REFS_BRANCHES) {
const char *path;
if ((path = branch_checked_out(name))) {
- error(_("Cannot delete branch '%s' "
- "checked out at '%s'"),
+ error(_("cannot delete branch '%s' "
+ "used by worktree at '%s'"),
bname.buf, path);
ret = 1;
continue;
@@ -266,9 +270,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
| RESOLVE_REF_ALLOW_BAD_NAME,
&oid, &flags);
if (!target) {
- error(remote_branch
- ? _("remote-tracking branch '%s' not found.")
- : _("branch '%s' not found."), bname.buf);
+ if (remote_branch) {
+ error(_("remote-tracking branch '%s' not found"), bname.buf);
+ } else {
+ char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
+ char *virtual_target = resolve_refdup(virtual_name,
+ RESOLVE_REF_READING
+ | RESOLVE_REF_NO_RECURSE
+ | RESOLVE_REF_ALLOW_BAD_NAME,
+ &oid, &flags);
+ FREE_AND_NULL(virtual_name);
+
+ if (virtual_target)
+ error(_("branch '%s' not found.\n"
+ "Did you forget --remote?"),
+ bname.buf);
+ else
+ error(_("branch '%s' not found"), bname.buf);
+ FREE_AND_NULL(virtual_target);
+ }
ret = 1;
continue;
}
@@ -283,7 +303,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
item = string_list_append(&refs_to_delete, name);
item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
- : find_unique_abbrev(&oid, DEFAULT_ABBREV));
+ : repo_find_unique_abbrev(the_repository, &oid, DEFAULT_ABBREV));
next:
free(target);
@@ -345,17 +365,8 @@ static const char *quote_literal_for_format(const char *s)
static struct strbuf buf = STRBUF_INIT;
strbuf_reset(&buf);
- while (*s) {
- const char *ep = strchrnul(s, '%');
- if (s < ep)
- strbuf_add(&buf, s, ep - s);
- if (*ep == '%') {
- strbuf_addstr(&buf, "%%");
- s = ep + 1;
- } else {
- s = ep;
- }
- }
+ while (strbuf_expand_step(&buf, &s))
+ strbuf_addstr(&buf, "%%");
return buf.buf;
}
@@ -423,8 +434,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
{
int i;
struct ref_array array;
- struct strbuf out = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
int maxwidth = 0;
const char *remote_prefix = "";
char *to_free = NULL;
@@ -451,25 +460,30 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
if (verify_ref_format(format))
die(_("unable to parse format string"));
+ filter_ahead_behind(the_repository, format, &array);
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&err);
- strbuf_reset(&out);
- if (format_ref_array_item(array.items[i], format, &out, &err))
- die("%s", err.buf);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- /* format to a string_list to let print_columns() do its job */
+ if (column_active(colopts)) {
+ struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
+
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+
+ for (i = 0; i < array.nr; i++) {
+ strbuf_reset(&err);
+ strbuf_reset(&out);
+ if (format_ref_array_item(array.items[i], format, &out, &err))
+ die("%s", err.buf);
+
+ /* format to a string_list to let print_columns() do its job */
string_list_append(output, out.buf);
- } else {
- fwrite(out.buf, 1, out.len, stdout);
- putchar('\n');
}
+
+ strbuf_release(&err);
+ strbuf_release(&out);
+ } else {
+ print_formatted_ref_array(&array, format);
}
- strbuf_release(&err);
- strbuf_release(&out);
ref_array_clear(&array);
free(to_free);
}
@@ -489,9 +503,9 @@ static void print_current_branch_name(void)
die(_("HEAD (%s) points outside of refs/heads/"), refname);
}
-static void reject_rebase_or_bisect_branch(const char *target)
+static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
+ const char *target)
{
- struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
@@ -501,31 +515,57 @@ static void reject_rebase_or_bisect_branch(const char *target)
continue;
if (is_worktree_being_rebased(wt, target))
- die(_("Branch %s is being rebased at %s"),
+ die(_("branch %s is being rebased at %s"),
target, wt->path);
if (is_worktree_being_bisected(wt, target))
- die(_("Branch %s is being bisected at %s"),
+ die(_("branch %s is being bisected at %s"),
target, wt->path);
}
+}
- free_worktrees(worktrees);
+/*
+ * Update all per-worktree HEADs pointing at the old ref to point the new ref.
+ * This will be used when renaming a branch. Returns 0 if successful, non-zero
+ * otherwise.
+ */
+static int replace_each_worktree_head_symref(struct worktree **worktrees,
+ const char *oldref, const char *newref,
+ const char *logmsg)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; worktrees[i]; i++) {
+ struct ref_store *refs;
+
+ if (worktrees[i]->is_detached)
+ continue;
+ if (!worktrees[i]->head_ref)
+ continue;
+ if (strcmp(oldref, worktrees[i]->head_ref))
+ continue;
+
+ refs = get_worktree_ref_store(worktrees[i]);
+ if (refs_create_symref(refs, "HEAD", newref, logmsg))
+ ret = error(_("HEAD of working tree %s is not updated"),
+ worktrees[i]->path);
+ }
+
+ return ret;
}
+#define IS_HEAD 1
+#define IS_ORPHAN 2
+
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
{
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
const char *interpreted_oldname = NULL;
const char *interpreted_newname = NULL;
- int recovery = 0;
-
- if (!oldname) {
- if (copy)
- die(_("cannot copy the current branch while not on any."));
- else
- die(_("cannot rename the current branch while not on any."));
- }
+ int recovery = 0, oldref_usage = 0;
+ struct worktree **worktrees = get_worktrees();
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
@@ -535,14 +575,25 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
if (ref_exists(oldref.buf))
recovery = 1;
else
- die(_("Invalid branch name: '%s'"), oldname);
+ die(_("invalid branch name: '%s'"), oldname);
}
- if ((copy || strcmp(head, oldname)) && !ref_exists(oldref.buf)) {
- if (copy && !strcmp(head, oldname))
- die(_("No commit on branch '%s' yet."), oldname);
+ for (int i = 0; worktrees[i]; i++) {
+ struct worktree *wt = worktrees[i];
+
+ if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
+ oldref_usage |= IS_HEAD;
+ if (is_null_oid(&wt->head_oid))
+ oldref_usage |= IS_ORPHAN;
+ break;
+ }
+ }
+
+ if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+ if (oldref_usage & IS_HEAD)
+ die(_("no commit on branch '%s' yet"), oldname);
else
- die(_("No branch named '%s'."), oldname);
+ die(_("no branch named '%s'"), oldname);
}
/*
@@ -554,7 +605,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
else
validate_new_branchname(newname, &newref, force);
- reject_rebase_or_bisect_branch(oldref.buf);
+ reject_rebase_or_bisect_branch(worktrees, oldref.buf);
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
@@ -568,38 +619,39 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
- if (!copy &&
- (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+ if (!copy && !(oldref_usage & IS_ORPHAN) &&
rename_ref(oldref.buf, newref.buf, logmsg.buf))
- die(_("Branch rename failed"));
+ die(_("branch rename failed"));
if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
- die(_("Branch copy failed"));
+ die(_("branch copy failed"));
if (recovery) {
if (copy)
- warning(_("Created a copy of a misnamed branch '%s'"),
+ warning(_("created a copy of a misnamed branch '%s'"),
interpreted_oldname);
else
- warning(_("Renamed a misnamed branch '%s' away"),
+ warning(_("renamed a misnamed branch '%s' away"),
interpreted_oldname);
}
- if (!copy &&
- replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
- die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
+ if (!copy && (oldref_usage & IS_HEAD) &&
+ replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
+ logmsg.buf))
+ die(_("branch renamed to %s, but HEAD is not updated"), newname);
strbuf_release(&logmsg);
strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
- strbuf_release(&oldref);
strbuf_addf(&newsection, "branch.%s", interpreted_newname);
- strbuf_release(&newref);
if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
- die(_("Branch is renamed, but update of config-file failed"));
- if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
- die(_("Branch is copied, but update of config-file failed"));
+ die(_("branch is renamed, but update of config-file failed"));
+ if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
+ die(_("branch is copied, but update of config-file failed"));
+ strbuf_release(&oldref);
+ strbuf_release(&newref);
strbuf_release(&oldsection);
strbuf_release(&newsection);
+ free_worktrees(worktrees);
}
static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
@@ -613,7 +665,7 @@ static int edit_branch_description(const char *branch_name)
exists = !read_branch_desc(&buf, branch_name);
if (!buf.len || buf.buf[buf.len-1] != '\n')
strbuf_addch(&buf, '\n');
- strbuf_commented_addf(&buf,
+ strbuf_commented_addf(&buf, comment_line_char,
_("Please edit the description for the branch\n"
" %s\n"
"Lines starting with '%c' will be stripped.\n"),
@@ -624,7 +676,7 @@ static int edit_branch_description(const char *branch_name)
strbuf_release(&buf);
return -1;
}
- strbuf_stripspace(&buf, 1);
+ strbuf_stripspace(&buf, comment_line_char);
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
@@ -646,7 +698,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int reflog = 0, quiet = 0, icase = 0, force = 0,
recurse_submodules_explicit = 0;
enum branch_track track;
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -665,8 +717,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("unset the upstream info")),
OPT__COLOR(&branch_use_color, N_("use colored output")),
- OPT_SET_INT('r', "remotes", &filter.kind, N_("act on remote-tracking branches"),
- FILTER_REFS_REMOTES),
+ OPT_SET_INT_F('r', "remotes", &filter.kind, N_("act on remote-tracking branches"),
+ FILTER_REFS_REMOTES,
+ PARSE_OPT_NONEG),
OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")),
OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches that don't contain the commit")),
OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")),
@@ -674,12 +727,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__ABBREV(&filter.abbrev),
OPT_GROUP(N_("Specific git-branch actions:")),
- OPT_SET_INT('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
- FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES),
+ OPT_SET_INT_F('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
+ FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES,
+ PARSE_OPT_NONEG),
OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
OPT_BOOL('l', "list", &list, N_("list branch names")),
@@ -702,20 +758,25 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
setup_ref_filter_porcelain_msg();
- memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_branch_usage, options);
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_branch_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
track = git_branch_track;
head = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (!head)
- die(_("Failed to resolve HEAD as a valid ref."));
+ die(_("failed to resolve HEAD as a valid ref"));
if (!strcmp(head, "HEAD"))
filter.detached = 1;
else if (!skip_prefix(head, "refs/heads/", &head))
@@ -769,6 +830,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (list)
setup_auto_pager("branch", 1);
+ UNLEAK(sorting_options);
+
if (delete) {
if (!argc)
die(_("branch name required"));
@@ -796,93 +859,104 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
ref_sorting_release(sorting);
+ ref_filter_clear(&filter);
return 0;
} else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 1; /* assume failure */
if (!argc) {
if (filter.detached)
- die(_("Cannot give description to detached HEAD"));
+ die(_("cannot give description to detached HEAD"));
branch_name = head;
- } else if (argc == 1)
- branch_name = argv[0];
- else
+ } else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch_name = buf.buf;
+ } else {
die(_("cannot edit description of more than one branch"));
+ }
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
- if (!ref_exists(branch_ref.buf)) {
- strbuf_release(&branch_ref);
-
- if (!argc || !strcmp(head, branch_name))
- return error(_("No commit on branch '%s' yet."),
- branch_name);
- else
- return error(_("No branch named '%s'."),
- branch_name);
- }
+ if (!ref_exists(branch_ref.buf))
+ error((!argc || branch_checked_out(branch_ref.buf))
+ ? _("no commit on branch '%s' yet")
+ : _("no branch named '%s'"),
+ branch_name);
+ else if (!edit_branch_description(branch_name))
+ ret = 0; /* happy */
+
strbuf_release(&branch_ref);
+ strbuf_release(&buf);
- if (edit_branch_description(branch_name))
- return 1;
- } else if (copy) {
+ return ret;
+ } else if (copy || rename) {
if (!argc)
die(_("branch name required"));
+ else if ((argc == 1) && filter.detached)
+ die(copy? _("cannot copy the current branch while not on any")
+ : _("cannot rename the current branch while not on any"));
else if (argc == 1)
- copy_or_rename_branch(head, argv[0], 1, copy > 1);
+ copy_or_rename_branch(head, argv[0], copy, copy + rename > 1);
else if (argc == 2)
- copy_or_rename_branch(argv[0], argv[1], 1, copy > 1);
+ copy_or_rename_branch(argv[0], argv[1], copy, copy + rename > 1);
else
- die(_("too many branches for a copy operation"));
- } else if (rename) {
- if (!argc)
- die(_("branch name required"));
- else if (argc == 1)
- copy_or_rename_branch(head, argv[0], 0, rename > 1);
- else if (argc == 2)
- copy_or_rename_branch(argv[0], argv[1], 0, rename > 1);
- else
- die(_("too many arguments for a rename operation"));
+ die(copy? _("too many branches for a copy operation")
+ : _("too many arguments for a rename operation"));
} else if (new_upstream) {
- struct branch *branch = branch_get(argv[0]);
+ struct branch *branch;
+ struct strbuf buf = STRBUF_INIT;
- if (argc > 1)
+ if (!argc)
+ branch = branch_get(NULL);
+ else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch = branch_get(buf.buf);
+ } else
die(_("too many arguments to set new upstream"));
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not set upstream of HEAD to %s when "
- "it does not point to any branch."),
+ "it does not point to any branch"),
new_upstream);
die(_("no such branch '%s'"), argv[0]);
}
if (!ref_exists(branch->refname)) {
- if (!argc || !strcmp(head, branch->name))
- die(_("No commit on branch '%s' yet."), branch->name);
+ if (!argc || branch_checked_out(branch->refname))
+ die(_("no commit on branch '%s' yet"), branch->name);
die(_("branch '%s' does not exist"), branch->name);
}
dwim_and_setup_tracking(the_repository, branch->name,
new_upstream, BRANCH_TRACK_OVERRIDE,
quiet);
+ strbuf_release(&buf);
} else if (unset_upstream) {
- struct branch *branch = branch_get(argv[0]);
+ struct branch *branch;
struct strbuf buf = STRBUF_INIT;
- if (argc > 1)
+ if (!argc)
+ branch = branch_get(NULL);
+ else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch = branch_get(buf.buf);
+ } else
die(_("too many arguments to unset upstream"));
if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not unset upstream of HEAD when "
- "it does not point to any branch."));
+ "it does not point to any branch"));
die(_("no such branch '%s'"), argv[0]);
}
if (!branch_has_merge_config(branch))
- die(_("Branch '%s' has no upstream information"), branch->name);
+ die(_("branch '%s' has no upstream information"), branch->name);
+ strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_reset(&buf);
@@ -894,11 +968,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
const char *start_name = argc == 2 ? argv[1] : head;
if (filter.kind != FILTER_REFS_BRANCHES)
- die(_("The -a, and -r, options to 'git branch' do not take a branch name.\n"
+ die(_("the -a, and -r, options to 'git branch' do not take a branch name.\n"
"Did you mean to use: -a|-r --list <pattern>?"));
if (track == BRANCH_TRACK_OVERRIDE)
- die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
+ die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead"));
if (recurse_submodules) {
create_branches_recursively(the_repository, branch_name,
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 530895be55..3106e56a13 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,4 +1,7 @@
#include "builtin.h"
+#include "abspath.h"
+#include "editor.h"
+#include "gettext.h"
#include "parse-options.h"
#include "strbuf.h"
#include "help.h"
@@ -6,7 +9,8 @@
#include "hook.h"
#include "hook-list.h"
#include "diagnose.h"
-
+#include "object-file.h"
+#include "setup.h"
static void get_system_info(struct strbuf *sys_info)
{
@@ -60,7 +64,8 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
}
static const char * const bugreport_usage[] = {
- N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--diagnose[=<mode>]"),
+ N_("git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ " [--diagnose[=<mode>]]"),
NULL
};
@@ -105,6 +110,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
const char *user_relative_path = NULL;
char *prefixed_filename;
size_t output_path_len;
+ int ret;
const struct option bugreport_options[] = {
OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -120,6 +126,11 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, bugreport_options,
bugreport_usage, 0);
+ if (argc) {
+ error(_("unknown argument `%s'"), argv[0]);
+ usage(bugreport_usage[0]);
+ }
+
/* Prepare the path to put the result */
prefixed_filename = prefix_filename(prefix,
option_output ? option_output : "");
@@ -181,7 +192,9 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
user_relative_path);
free(prefixed_filename);
- UNLEAK(buffer);
- UNLEAK(report_path);
- return !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&buffer);
+
+ ret = !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&report_path);
+ return ret;
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index e80efce3a4..3ad11dc5d0 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,7 +1,11 @@
#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "setup.h"
#include "strvec.h"
#include "parse-options.h"
-#include "cache.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "bundle.h"
/*
@@ -11,32 +15,42 @@
* 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
+#define BUILTIN_BUNDLE_CREATE_USAGE \
+ N_("git bundle create [-q | --quiet | --progress]\n" \
+ " [--version=<version>] <file> <git-rev-list-args>")
+#define BUILTIN_BUNDLE_VERIFY_USAGE \
+ N_("git bundle verify [-q | --quiet] <file>")
+#define BUILTIN_BUNDLE_LIST_HEADS_USAGE \
+ N_("git bundle list-heads <file> [<refname>...]")
+#define BUILTIN_BUNDLE_UNBUNDLE_USAGE \
+ N_("git bundle unbundle [--progress] <file> [<refname>...]")
+
+static char const * const builtin_bundle_usage[] = {
+ BUILTIN_BUNDLE_CREATE_USAGE,
+ BUILTIN_BUNDLE_VERIFY_USAGE,
+ BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+ BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+ NULL,
};
static const char * const builtin_bundle_create_usage[] = {
- N_("git bundle create [<options>] <file> <git-rev-list args>"),
- NULL
+ BUILTIN_BUNDLE_CREATE_USAGE,
+ NULL
};
static const char * const builtin_bundle_verify_usage[] = {
- N_("git bundle verify [<options>] <file>"),
- NULL
+ BUILTIN_BUNDLE_VERIFY_USAGE,
+ NULL
};
static const char * const builtin_bundle_list_heads_usage[] = {
- N_("git bundle list-heads <file> [<refname>...]"),
- NULL
+ BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+ NULL
};
static const char * const builtin_bundle_unbundle_usage[] = {
- N_("git bundle unbundle <file> [<refname>...]"),
- NULL
+ BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+ NULL
};
static int parse_options_cmd_bundle(int argc,
@@ -45,51 +59,45 @@ static int parse_options_cmd_bundle(int argc,
const char * const usagestr[],
const struct option options[],
char **bundle_file) {
- int newargc;
- newargc = parse_options(argc, argv, NULL, options, usagestr,
+ argc = 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;
+ if (!argc)
+ usage_msg_opt(_("need a <file> argument"), usagestr, options);
+ *bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
+ return argc;
}
static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
- int all_progress_implied = 0;
- int progress = isatty(STDERR_FILENO);
- struct strvec pack_opts;
+ struct strvec pack_opts = STRVEC_INIT;
int version = -1;
int ret;
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_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
+ N_("do not show progress meter"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
+ N_("show progress meter"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
+ N_("historical; same as --progress"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+ OPT_PASSTHRU_ARGV(0, "all-progress-implied", &pack_opts, NULL,
+ N_("historical; does nothing"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
OPT_INTEGER(0, "version", &version,
N_("specify bundle format version")),
OPT_END()
};
char *bundle_file;
+ if (isatty(STDERR_FILENO))
+ strvec_push(&pack_opts, "--progress");
+ strvec_push(&pack_opts, "--all-progress-implied");
+
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_create_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- strvec_init(&pack_opts);
- if (progress == 0)
- strvec_push(&pack_opts, "--quiet");
- else if (progress == 1)
- strvec_push(&pack_opts, "--progress");
- else if (progress == 2)
- strvec_push(&pack_opts, "--all-progress");
- if (progress && all_progress_implied)
- strvec_push(&pack_opts, "--all-progress-implied");
-
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
@@ -98,6 +106,23 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
return ret;
}
+/*
+ * Similar to read_bundle_header(), but handle "-" as stdin.
+ */
+static int open_bundle(const char *path, struct bundle_header *header,
+ const char **name)
+{
+ if (!strcmp(path, "-")) {
+ if (name)
+ *name = "<stdin>";
+ return read_bundle_header_fd(0, header, "<stdin>");
+ }
+
+ if (name)
+ *name = path;
+ return read_bundle_header(path, header);
+}
+
static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
@@ -109,22 +134,24 @@ static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
OPT_END()
};
char *bundle_file;
+ const char *name;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
ret = 1;
goto cleanup;
}
close(bundle_fd);
- if (verify_bundle(the_repository, &header, !quiet)) {
+ if (verify_bundle(the_repository, &header,
+ quiet ? VERIFY_BUNDLE_QUIET : VERIFY_BUNDLE_VERBOSE)) {
ret = 1;
goto cleanup;
}
- fprintf(stderr, _("%s is okay\n"), bundle_file);
+ fprintf(stderr, _("%s is okay\n"), name);
ret = 0;
cleanup:
free(bundle_file);
@@ -145,7 +172,7 @@ static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
@@ -175,7 +202,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
@@ -185,7 +212,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
ret = !!unbundle(the_repository, &header, bundle_fd,
- &extra_index_pack_args) ||
+ &extra_index_pack_args, 0) ||
list_bundle_refs(&header, argc, argv);
bundle_header_release(&header);
cleanup:
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 989eee0bb4..7d4899348a 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -3,20 +3,27 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
-#include "config.h"
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "config.h"
+#include "convert.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "ident.h"
#include "parse-options.h"
#include "userdiff.h"
#include "streaming.h"
-#include "tree-walk.h"
#include "oid-array.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "promisor-remote.h"
#include "mailmap.h"
+#include "write-or-die.h"
enum batch_mode {
BATCH_MODE_CONTENTS,
@@ -32,7 +39,8 @@ struct batch_options {
int all_objects;
int unordered;
int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
- int nul_terminated;
+ char input_delim;
+ char output_delim;
const char *format;
};
@@ -60,7 +68,7 @@ static int filter_object(const char *path, unsigned mode,
{
enum object_type type;
- *buf = read_object_file(oid, &type, size);
+ *buf = repo_read_object_file(the_repository, oid, &type, size);
if (!*buf)
return error(_("cannot read object %s '%s'"),
oid_to_hex(oid), path);
@@ -132,14 +140,27 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 's':
oi.sizep = &size;
+
+ if (use_mailmap) {
+ oi.typep = &type;
+ oi.contentp = (void**)&buf;
+ }
+
if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
+
+ if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
+ size_t s = size;
+ buf = replace_idents_using_mailmap(buf, &s);
+ size = cast_size_t_to_ulong(s);
+ }
+
printf("%"PRIuMAX"\n", (uintmax_t)size);
ret = 0;
goto cleanup;
case 'e':
- return !has_object_file(&oid);
+ return !repo_has_object_file(the_repository, &oid);
case 'w':
@@ -174,7 +195,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
ret = stream_blob(&oid);
goto cleanup;
}
- buf = read_object_file(&oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &oid, &type,
+ &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -194,8 +216,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (exp_type_id == OBJ_BLOB) {
struct object_id blob_oid;
if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
- char *buffer = read_object_file(&oid, &type,
- &size);
+ char *buffer = repo_read_object_file(the_repository,
+ &oid,
+ &type,
+ &size);
const char *target;
if (!skip_prefix(buffer, "object ", &target) ||
get_oid_hex(target, &blob_oid))
@@ -283,10 +307,8 @@ static int is_atom(const char *atom, const char *s, int slen)
}
static void expand_atom(struct strbuf *sb, const char *atom, int len,
- void *vdata)
+ struct expand_data *data)
{
- struct expand_data *data = vdata;
-
if (is_atom("objectname", atom, len)) {
if (!data->mark_query)
strbuf_addstr(sb, oid_to_hex(&data->oid));
@@ -320,19 +342,21 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
die("unknown format element: %.*s", len, atom);
}
-static size_t expand_format(struct strbuf *sb, const char *start, void *data)
+static void expand_format(struct strbuf *sb, const char *start,
+ struct expand_data *data)
{
- const char *end;
-
- if (*start != '(')
- return 0;
- end = strchr(start + 1, ')');
- if (!end)
- die("format element '%s' does not end in ')'", start);
-
- expand_atom(sb, start + 1, end - start - 1, data);
-
- return end - start + 1;
+ while (strbuf_expand_step(sb, &start)) {
+ const char *end;
+
+ if (skip_prefix(start, "%", &start) || *start != '(')
+ strbuf_addch(sb, '%');
+ else if (!(end = strchr(start + 1, ')')))
+ die("format element '%s' does not end in ')'", start);
+ else {
+ expand_atom(sb, start + 1, end - start - 1, data);
+ start = end + 1;
+ }
+ }
}
static void batch_write(struct batch_options *opt, const void *data, int len)
@@ -370,9 +394,10 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (!textconv_object(the_repository,
data->rest, 0100644, oid,
1, &contents, &size))
- contents = read_object_file(oid,
- &type,
- &size);
+ contents = repo_read_object_file(the_repository,
+ oid,
+ &type,
+ &size);
if (!contents)
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
@@ -389,7 +414,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
unsigned long size;
void *contents;
- contents = read_object_file(oid, &type, &size);
+ contents = repo_read_object_file(the_repository, oid, &type,
+ &size);
if (use_mailmap) {
size_t s = size;
@@ -409,11 +435,12 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
}
}
-static void print_default_format(struct strbuf *scratch, struct expand_data *data)
+static void print_default_format(struct strbuf *scratch, struct expand_data *data,
+ struct batch_options *opt)
{
- strbuf_addf(scratch, "%s %s %"PRIuMAX"\n", oid_to_hex(&data->oid),
+ strbuf_addf(scratch, "%s %s %"PRIuMAX"%c", oid_to_hex(&data->oid),
type_name(data->type),
- (uintmax_t)data->size);
+ (uintmax_t)data->size, opt->output_delim);
}
/*
@@ -431,6 +458,9 @@ static void batch_object_write(const char *obj_name,
if (!data->skip_object_info) {
int ret;
+ if (use_mailmap)
+ data->info.typep = &data->type;
+
if (pack)
ret = packed_object_info(the_repository, pack, offset,
&data->info);
@@ -439,27 +469,39 @@ static void batch_object_write(const char *obj_name,
&data->oid, &data->info,
OBJECT_INFO_LOOKUP_REPLACE);
if (ret < 0) {
- printf("%s missing\n",
- obj_name ? obj_name : oid_to_hex(&data->oid));
+ printf("%s missing%c",
+ obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim);
fflush(stdout);
return;
}
+
+ if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
+ size_t s = data->size;
+ char *buf = NULL;
+
+ buf = repo_read_object_file(the_repository, &data->oid, &data->type,
+ &data->size);
+ buf = replace_idents_using_mailmap(buf, &s);
+ data->size = cast_size_t_to_ulong(s);
+
+ free(buf);
+ }
}
strbuf_reset(scratch);
if (!opt->format) {
- print_default_format(scratch, data);
+ print_default_format(scratch, data, opt);
} else {
- strbuf_expand(scratch, opt->format, expand_format, data);
- strbuf_addch(scratch, '\n');
+ expand_format(scratch, opt->format, data);
+ strbuf_addch(scratch, opt->output_delim);
}
batch_write(opt, scratch->buf, scratch->len);
if (opt->batch_mode == BATCH_MODE_CONTENTS) {
print_object_or_die(opt, data);
- batch_write(opt, "\n", 1);
+ batch_write(opt, &opt->output_delim, 1);
}
}
@@ -477,22 +519,25 @@ static void batch_one_object(const char *obj_name,
if (result != FOUND) {
switch (result) {
case MISSING_OBJECT:
- printf("%s missing\n", obj_name);
+ printf("%s missing%c", obj_name, opt->output_delim);
break;
case SHORT_NAME_AMBIGUOUS:
- printf("%s ambiguous\n", obj_name);
+ printf("%s ambiguous%c", obj_name, opt->output_delim);
break;
case DANGLING_SYMLINK:
- printf("dangling %"PRIuMAX"\n%s\n",
- (uintmax_t)strlen(obj_name), obj_name);
+ printf("dangling %"PRIuMAX"%c%s%c",
+ (uintmax_t)strlen(obj_name),
+ opt->output_delim, obj_name, opt->output_delim);
break;
case SYMLINK_LOOP:
- printf("loop %"PRIuMAX"\n%s\n",
- (uintmax_t)strlen(obj_name), obj_name);
+ printf("loop %"PRIuMAX"%c%s%c",
+ (uintmax_t)strlen(obj_name),
+ opt->output_delim, obj_name, opt->output_delim);
break;
case NOT_DIR:
- printf("notdir %"PRIuMAX"\n%s\n",
- (uintmax_t)strlen(obj_name), obj_name);
+ printf("notdir %"PRIuMAX"%c%s%c",
+ (uintmax_t)strlen(obj_name),
+ opt->output_delim, obj_name, opt->output_delim);
break;
default:
BUG("unknown get_sha1_with_context result %d\n",
@@ -504,9 +549,9 @@ static void batch_one_object(const char *obj_name,
}
if (ctx.mode == 0) {
- printf("symlink %"PRIuMAX"\n%s\n",
+ printf("symlink %"PRIuMAX"%c%s%c",
(uintmax_t)ctx.symlink_path.len,
- ctx.symlink_path.buf);
+ opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
fflush(stdout);
return;
}
@@ -531,7 +576,7 @@ static int batch_object_cb(const struct object_id *oid, void *vdata)
}
static int collect_loose_object(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
oid_array_append(data, oid);
@@ -539,8 +584,8 @@ static int collect_loose_object(const struct object_id *oid,
}
static int collect_packed_object(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
void *data)
{
oid_array_append(data, oid);
@@ -563,7 +608,7 @@ static int batch_unordered_object(const struct object_id *oid,
}
static int batch_unordered_loose(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
return batch_unordered_object(oid, NULL, 0, data);
@@ -651,20 +696,12 @@ static void batch_objects_command(struct batch_options *opt,
struct queued_cmd *queued_cmd = NULL;
size_t alloc = 0, nr = 0;
- while (1) {
- int i, ret;
+ while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
+ int i;
const struct parse_cmd *cmd = NULL;
const char *p = NULL, *cmd_end;
struct queued_cmd call = {0};
- if (opt->nul_terminated)
- ret = strbuf_getline_nul(&input, stdin);
- else
- ret = strbuf_getline(&input, stdin);
-
- if (ret)
- break;
-
if (!input.len)
die(_("empty command in input"));
if (isspace(*input.buf))
@@ -734,9 +771,8 @@ static int batch_objects(struct batch_options *opt)
*/
memset(&data, 0, sizeof(data));
data.mark_query = 1;
- strbuf_expand(&output,
+ expand_format(&output,
opt->format ? opt->format : DEFAULT_FORMAT,
- expand_format,
&data);
data.mark_query = 0;
strbuf_release(&output);
@@ -759,10 +795,10 @@ static int batch_objects(struct batch_options *opt)
if (!memcmp(&data.info, &empty, sizeof(empty)))
data.skip_object_info = 1;
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
warning("This repository uses promisor remotes. Some objects may not be loaded.");
- read_replace_refs = 0;
+ disable_replace_refs();
cb.opt = opt;
cb.expand = &data;
@@ -808,16 +844,7 @@ static int batch_objects(struct batch_options *opt)
goto cleanup;
}
- while (1) {
- int ret;
- if (opt->nul_terminated)
- ret = strbuf_getline_nul(&input, stdin);
- else
- ret = strbuf_getline(&input, stdin);
-
- if (ret == EOF)
- break;
-
+ while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
if (data.split_on_whitespace) {
/*
* Split at first whitespace, tying off the beginning
@@ -842,12 +869,13 @@ static int batch_objects(struct batch_options *opt)
return retval;
}
-static int git_cat_file_config(const char *var, const char *value, void *cb)
+static int git_cat_file_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (userdiff_config(var, value) < 0)
return -1;
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static int batch_option_callback(const struct option *opt,
@@ -886,16 +914,18 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
const char *exp_type = NULL, *obj_name = NULL;
struct batch_options batch = {0};
int unknown_type = 0;
+ int input_nul_terminated = 0;
+ int nul_terminated = 0;
const char * const usage[] = {
N_("git cat-file <type> <object>"),
N_("git cat-file (-e | -p) <object>"),
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
- N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
- " [--buffer] [--follow-symlinks] [--unordered]\n"
- " [--textconv | --filters]"),
N_("git cat-file (--textconv | --filters)\n"
" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
+ N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
+ " [--buffer] [--follow-symlinks] [--unordered]\n"
+ " [--textconv | --filters] [-Z]"),
NULL
};
const struct option options[] = {
@@ -922,7 +952,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("like --batch, but don't emit <contents>"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
batch_option_callback),
- OPT_BOOL('z', NULL, &batch.nul_terminated, N_("stdin is NUL-terminated")),
+ OPT_BOOL_F('z', NULL, &input_nul_terminated, N_("stdin is NUL-terminated"),
+ PARSE_OPT_HIDDEN),
+ OPT_BOOL('Z', NULL, &nul_terminated, N_("stdin and stdout is NUL-terminated")),
OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
N_("read commands from stdin"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
@@ -981,9 +1013,18 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
else if (batch.all_objects)
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
"--batch-all-objects");
- else if (batch.nul_terminated)
+ else if (input_nul_terminated)
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
"-z");
+ else if (nul_terminated)
+ usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+ "-Z");
+
+ batch.input_delim = batch.output_delim = '\n';
+ if (input_nul_terminated)
+ batch.input_delim = '\0';
+ if (nul_terminated)
+ batch.input_delim = batch.output_delim = '\0';
/* Batch defaults */
if (batch.buffer_output < 0)
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index dd83397786..c1da1d184e 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -1,17 +1,23 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "attr.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
#include "quote.h"
+#include "repository.h"
+#include "setup.h"
#include "parse-options.h"
+#include "write-or-die.h"
static int all_attrs;
static int cached_attrs;
static int stdin_paths;
+static char *source;
static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
-N_("git check-attr --stdin [-z] [-a | --all | <attr>...]"),
+N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
NULL
};
@@ -23,6 +29,7 @@ static const struct option check_attr_options[] = {
OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
OPT_BOOL('z', NULL, &nul_term_line,
N_("terminate input and output records by a NUL character")),
+ OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
OPT_END()
};
@@ -55,10 +62,10 @@ static void output_attr(struct attr_check *check, const char *file)
}
}
-static void check_attr(const char *prefix,
- struct attr_check *check,
+static void check_attr(const char *prefix, struct attr_check *check,
int collect_all,
const char *file)
+
{
char *full_path =
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
@@ -73,8 +80,7 @@ static void check_attr(const char *prefix,
free(full_path);
}
-static void check_attr_stdin_paths(const char *prefix,
- struct attr_check *check,
+static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
int collect_all)
{
struct strbuf buf = STRBUF_INIT;
@@ -105,6 +111,7 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
struct attr_check *check;
+ struct object_id initialized_oid;
int cnt, i, doubledash, filei;
if (!is_bare_repository())
@@ -115,7 +122,10 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
- if (read_cache() < 0) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
+ if (repo_read_index(the_repository) < 0) {
die("invalid cache");
}
@@ -176,6 +186,12 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
}
}
+ if (source) {
+ if (repo_get_oid_tree(the_repository, source, &initialized_oid))
+ die("%s: not a valid tree-ish source", source);
+ set_git_attr_source(source);
+ }
+
if (stdin_paths)
check_attr_stdin_paths(prefix, check, all_attrs);
else {
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 2191256965..906cd96753 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -1,12 +1,14 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "quote.h"
#include "pathspec.h"
#include "parse-options.h"
+#include "repository.h"
#include "submodule.h"
+#include "write-or-die.h"
static int quiet, verbose, stdin_paths, show_non_matching, no_index;
static const char * const check_ignore_usage[] = {
@@ -179,7 +181,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
die(_("--non-matching is only valid with --verbose"));
/* read_cache() is only necessary so we can watch out for submodules. */
- if (!no_index && read_cache() < 0)
+ if (!no_index && repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
setup_standard_excludes(&dir);
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index 7dc47e4793..b8a05b8e07 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,8 +1,12 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "ident.h"
#include "mailmap.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "string-list.h"
+#include "write-or-die.h"
static int use_stdin;
static const char * const check_mailmap_usage[] = {
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index fd0e5f8683..5eb6bdc3f6 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -2,9 +2,9 @@
* GIT - The information manager from hell
*/
-#include "cache.h"
-#include "refs.h"
#include "builtin.h"
+#include "refs.h"
+#include "setup.h"
#include "strbuf.h"
static const char builtin_check_ref_format_usage[] =
@@ -60,6 +60,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
char *to_free = NULL;
int ret = 1;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_check_ref_format_usage);
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index ede7dc32a4..6b62b5375b 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -1,9 +1,11 @@
#include "builtin.h"
#include "config.h"
#include "entry.h"
+#include "gettext.h"
#include "parallel-checkout.h"
#include "parse-options.h"
#include "pkt-line.h"
+#include "read-cache-ll.h"
static void packet_to_pc_item(const char *buffer, int len,
struct parallel_checkout_item *pc_item)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 97e06e8c52..2e086a204d 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -4,22 +4,26 @@
* Copyright (C) 2005 Linus Torvalds
*
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
-#include "dir.h"
+#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
+#include "repository.h"
#include "cache-tree.h"
#include "parse-options.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "read-cache-ll.h"
+#include "setup.h"
+#include "sparse-index.h"
#define CHECKOUT_ALL 4
static int nul_term_line;
static int checkout_stage; /* default to checkout stage0 */
static int ignore_skip_worktree; /* default to 0 */
-static int to_tempfile;
+static int to_tempfile = -1;
static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state = CHECKOUT_INIT;
@@ -65,7 +69,7 @@ static void write_tempfile_record(const char *name, const char *prefix)
static int checkout_file(const char *name, const char *prefix)
{
int namelen = strlen(name);
- int pos = cache_name_pos(name, namelen);
+ int pos = index_name_pos(&the_index, name, namelen);
int has_same_name = 0;
int is_file = 0;
int is_skipped = 1;
@@ -75,8 +79,8 @@ static int checkout_file(const char *name, const char *prefix)
if (pos < 0)
pos = -pos - 1;
- while (pos < active_nr) {
- struct cache_entry *ce = active_cache[pos];
+ while (pos < the_index.cache_nr) {
+ struct cache_entry *ce = the_index.cache[pos];
if (ce_namelen(ce) != namelen ||
memcmp(ce->name, name, namelen))
break;
@@ -136,8 +140,8 @@ static int checkout_all(const char *prefix, int prefix_length)
int i, errs = 0;
struct cache_entry *last_ce = NULL;
- for (i = 0; i < active_nr ; i++) {
- struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr ; i++) {
+ struct cache_entry *ce = the_index.cache[i];
if (S_ISSPARSEDIR(ce->ce_mode)) {
if (!ce_skip_worktree(ce))
@@ -151,7 +155,7 @@ static int checkout_all(const char *prefix, int prefix_length)
*/
if (ignore_skip_worktree) {
ensure_full_index(&the_index);
- ce = active_cache[i];
+ ce = the_index.cache[i];
}
}
@@ -188,15 +192,16 @@ static const char * const builtin_checkout_index_usage[] = {
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
+ int *stage = opt->value;
+
BUG_ON_OPT_NEG(unset);
if (!strcmp(arg, "all")) {
- to_tempfile = 1;
- checkout_stage = CHECKOUT_ALL;
+ *stage = CHECKOUT_ALL;
} else {
int ch = arg[0];
if ('1' <= ch && ch <= '3')
- checkout_stage = arg[0] - '0';
+ *stage = arg[0] - '0';
else
die(_("stage should be between 1 and 3 or all"));
}
@@ -234,7 +239,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
N_("write the content to temporary files")),
OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
N_("when creating files, prepend <string>")),
- OPT_CALLBACK_F(0, "stage", NULL, "(1|2|3|all)",
+ OPT_CALLBACK_F(0, "stage", &checkout_stage, "(1|2|3|all)",
N_("copy out the files from named stage"),
PARSE_OPT_NONEG, option_parse_stage),
OPT_END()
@@ -249,7 +254,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- if (read_cache() < 0) {
+ if (repo_read_index(the_repository) < 0) {
die("invalid cache");
}
@@ -264,13 +269,20 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
state.base_dir = "";
state.base_dir_len = strlen(state.base_dir);
+ if (to_tempfile < 0)
+ to_tempfile = (checkout_stage == CHECKOUT_ALL);
+ if (!to_tempfile && checkout_stage == CHECKOUT_ALL)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--stage=all", "--no-temp");
+
/*
* when --prefix is specified we do not want to update cache.
*/
if (index_opt && !state.base_dir_len && !to_tempfile) {
state.refresh_cache = 1;
state.istate = &the_index;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file,
+ LOCK_DIE_ON_ERROR);
}
get_parallel_checkout_configs(&pc_workers, &pc_threshold);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a132392fb..a6e30931b5 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,7 +1,6 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
-#include "blob.h"
#include "branch.h"
#include "cache-tree.h"
#include "checkout.h"
@@ -9,19 +8,28 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "hook.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
#include "lockfile.h"
+#include "mem-pool.h"
#include "merge-recursive.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "refs.h"
#include "remote.h"
#include "resolve-undo.h"
#include "revision.h"
-#include "run-command.h"
+#include "setup.h"
#include "submodule.h"
-#include "submodule-config.h"
+#include "symlinks.h"
+#include "trace2.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -29,6 +37,7 @@
#include "xdiff-interface.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "add-interactive.h"
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -74,7 +83,7 @@ struct checkout_opts {
const char *ignore_unmerged_opt;
int ignore_unmerged;
int pathspec_file_nul;
- const char *pathspec_from_file;
+ char *pathspec_from_file;
const char *new_branch;
const char *new_branch_force;
@@ -148,9 +157,9 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
* entry in place. Whether it is UPTODATE or not, checkout_entry will
* do the right thing.
*/
- pos = cache_name_pos(ce->name, ce->ce_namelen);
+ pos = index_name_pos(&the_index, ce->name, ce->ce_namelen);
if (pos >= 0) {
- struct cache_entry *old = active_cache[pos];
+ struct cache_entry *old = the_index.cache[pos];
if (ce->ce_mode == old->ce_mode &&
!ce_intent_to_add(old) &&
oideq(&ce->oid, &old->oid)) {
@@ -160,7 +169,8 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
}
}
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+ add_index_entry(&the_index, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
}
@@ -178,8 +188,8 @@ static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
static int skip_same_name(const struct cache_entry *ce, int pos)
{
- while (++pos < active_nr &&
- !strcmp(active_cache[pos]->name, ce->name))
+ while (++pos < the_index.cache_nr &&
+ !strcmp(the_index.cache[pos]->name, ce->name))
; /* skip */
return pos;
}
@@ -187,9 +197,9 @@ static int skip_same_name(const struct cache_entry *ce, int pos)
static int check_stage(int stage, const struct cache_entry *ce, int pos,
int overlay_mode)
{
- while (pos < active_nr &&
- !strcmp(active_cache[pos]->name, ce->name)) {
- if (ce_stage(active_cache[pos]) == stage)
+ while (pos < the_index.cache_nr &&
+ !strcmp(the_index.cache[pos]->name, ce->name)) {
+ if (ce_stage(the_index.cache[pos]) == stage)
return 0;
pos++;
}
@@ -206,8 +216,8 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
unsigned seen = 0;
const char *name = ce->name;
- while (pos < active_nr) {
- ce = active_cache[pos];
+ while (pos < the_index.cache_nr) {
+ ce = the_index.cache[pos];
if (strcmp(name, ce->name))
break;
seen |= (1 << ce_stage(ce));
@@ -223,15 +233,15 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
const struct checkout *state, int *nr_checkouts,
int overlay_mode)
{
- while (pos < active_nr &&
- !strcmp(active_cache[pos]->name, ce->name)) {
- if (ce_stage(active_cache[pos]) == stage)
- return checkout_entry(active_cache[pos], state,
+ while (pos < the_index.cache_nr &&
+ !strcmp(the_index.cache[pos]->name, ce->name)) {
+ if (ce_stage(the_index.cache[pos]) == stage)
+ return checkout_entry(the_index.cache[pos], state,
NULL, nr_checkouts);
pos++;
}
if (!overlay_mode) {
- unlink_entry(ce);
+ unlink_entry(ce, NULL);
return 0;
}
if (stage == 2)
@@ -243,7 +253,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
static int checkout_merged(int pos, const struct checkout *state,
int *nr_checkouts, struct mem_pool *ce_mem_pool)
{
- struct cache_entry *ce = active_cache[pos];
+ struct cache_entry *ce = the_index.cache[pos];
const char *path = ce->name;
mmfile_t ancestor, ours, theirs;
enum ll_merge_result merge_status;
@@ -256,7 +266,7 @@ static int checkout_merged(int pos, const struct checkout *state,
int renormalize = 0;
memset(threeway, 0, sizeof(threeway));
- while (pos < active_nr) {
+ while (pos < the_index.cache_nr) {
int stage;
stage = ce_stage(ce);
if (!stage || strcmp(path, ce->name))
@@ -265,7 +275,7 @@ static int checkout_merged(int pos, const struct checkout *state,
if (stage == 2)
mode = create_ce_mode(ce->ce_mode);
pos++;
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
}
if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2]))
return error(_("path '%s' does not have necessary versions"), path);
@@ -391,8 +401,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
if (pc_workers > 1)
init_parallel_checkout();
- for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
+ for (pos = 0; pos < the_index.cache_nr; pos++) {
+ struct cache_entry *ce = the_index.cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state,
@@ -430,8 +440,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
"Updated %d paths from %s",
nr_checkouts),
nr_checkouts,
- find_unique_abbrev(&opts->source_tree->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &opts->source_tree->object.oid,
+ DEFAULT_ABBREV));
else if (!nr_unmerged || nr_checkouts)
fprintf_ln(stderr, Q_("Updated %d path from the index",
"Updated %d paths from the index",
@@ -487,18 +497,40 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("'%s' must be used when '%s' is not specified"),
"--worktree", "--source");
- if (opts->checkout_index && !opts->checkout_worktree &&
- opts->writeout_stage)
- die(_("'%s' or '%s' cannot be used with %s"),
- "--ours", "--theirs", "--staged");
+ /*
+ * Reject --staged option to the restore command when combined with
+ * merge-related options. Use the accept_ref flag to distinguish it
+ * from the checkout command, which does not accept --staged anyway.
+ *
+ * `restore --ours|--theirs --worktree --staged` could mean resolving
+ * conflicted paths to one side in both the worktree and the index,
+ * but does not currently.
+ *
+ * `restore --merge|--conflict=<style>` already recreates conflicts
+ * in both the worktree and the index, so adding --staged would be
+ * meaningless.
+ */
+ if (!opts->accept_ref && opts->checkout_index) {
+ if (opts->writeout_stage)
+ die(_("'%s' or '%s' cannot be used with %s"),
+ "--ours", "--theirs", "--staged");
+
+ if (opts->merge)
+ die(_("'%s' or '%s' cannot be used with %s"),
+ "--merge", "--conflict", "--staged");
+ }
- if (opts->checkout_index && !opts->checkout_worktree &&
- opts->merge)
- die(_("'%s' or '%s' cannot be used with %s"),
- "--merge", "--conflict", "--staged");
+ /*
+ * recreating unmerged index entries and writing out data from
+ * unmerged index entries would make no sense when checking out
+ * of a tree-ish.
+ */
+ if ((opts->merge || opts->writeout_stage) && opts->source_tree)
+ die(_("'%s', '%s', or '%s' cannot be used when checking out of a tree"),
+ "--merge", "--ours", "--theirs");
if (opts->patch_mode) {
- const char *patch_mode;
+ enum add_p_mode patch_mode;
const char *rev = new_branch_info->name;
char rev_oid[GIT_MAX_HEXSZ + 1];
@@ -516,23 +548,26 @@ static int checkout_paths(const struct checkout_opts *opts,
rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
if (opts->checkout_index && opts->checkout_worktree)
- patch_mode = "--patch=checkout";
+ patch_mode = ADD_P_CHECKOUT;
else if (opts->checkout_index && !opts->checkout_worktree)
- patch_mode = "--patch=reset";
+ patch_mode = ADD_P_RESET;
else if (!opts->checkout_index && opts->checkout_worktree)
- patch_mode = "--patch=worktree";
+ patch_mode = ADD_P_WORKTREE;
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return run_add_interactive(rev, patch_mode, &opts->pathspec);
+ return !!run_add_p(the_repository, patch_mode, rev,
+ &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
- if (read_cache_preload(&opts->pathspec) < 0)
+ if (repo_read_index_preload(the_repository, &opts->pathspec, 0) < 0)
return error(_("index file corrupt"));
if (opts->source_tree)
read_tree_some(opts->source_tree, &opts->pathspec);
+ if (opts->merge)
+ unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
ps_matched = xcalloc(opts->pathspec.nr, 1);
@@ -540,13 +575,13 @@ static int checkout_paths(const struct checkout_opts *opts,
* Make sure all pathspecs participated in locating the paths
* to be checked out.
*/
- for (pos = 0; pos < active_nr; pos++)
+ for (pos = 0; pos < the_index.cache_nr; pos++)
if (opts->overlay_mode)
- mark_ce_for_checkout_overlay(active_cache[pos],
+ mark_ce_for_checkout_overlay(the_index.cache[pos],
ps_matched,
opts);
else
- mark_ce_for_checkout_no_overlay(active_cache[pos],
+ mark_ce_for_checkout_no_overlay(the_index.cache[pos],
ps_matched,
opts);
@@ -556,13 +591,9 @@ static int checkout_paths(const struct checkout_opts *opts,
}
free(ps_matched);
- /* "checkout -m path" to recreate conflicted state */
- if (opts->merge)
- unmerge_marked_index(&the_index);
-
/* Any unmerged paths? */
- for (pos = 0; pos < active_nr; pos++) {
- const struct cache_entry *ce = active_cache[pos];
+ for (pos = 0; pos < the_index.cache_nr; pos++) {
+ const struct cache_entry *ce = the_index.cache[pos];
if (ce->ce_flags & CE_MATCHED) {
if (!ce_stage(ce))
continue;
@@ -637,14 +668,16 @@ static void describe_detached_head(const char *msg, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
- if (!parse_commit(commit))
+ if (!repo_parse_commit(the_repository, commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
if (print_sha1_ellipsis()) {
fprintf(stderr, "%s %s... %s\n", msg,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+ sb.buf);
} else {
fprintf(stderr, "%s %s %s\n", msg,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV), sb.buf);
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+ sb.buf);
}
strbuf_release(&sb);
}
@@ -698,7 +731,8 @@ static void setup_branch_path(struct branch_info *branch)
* If this is a ref, resolve it; otherwise, look up the OID for our
* expression. Failure here is okay.
*/
- if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname, 0))
+ if (!repo_dwim_ref(the_repository, branch->name, strlen(branch->name),
+ &branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
@@ -722,7 +756,7 @@ static void init_topts(struct unpack_trees_options *topts, int merge,
setup_unpack_trees_porcelain(topts, "checkout");
- topts->initial_checkout = is_cache_unborn();
+ topts->initial_checkout = is_index_unborn(&the_index);
topts->update = 1;
topts->merge = 1;
topts->quiet = merge && old_commit;
@@ -740,17 +774,18 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct lock_file lock_file = LOCK_INIT;
struct tree *new_tree;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
- if (read_cache_preload(NULL) < 0)
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+ if (repo_read_index_preload(the_repository, NULL, 0) < 0)
return error(_("index file corrupt"));
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
if (new_branch_info->commit)
BUG("'switch --orphan' should never accept a commit as starting point");
new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
} else
- new_tree = get_commit_tree(new_branch_info->commit);
+ new_tree = repo_get_commit_tree(the_repository,
+ new_branch_info->commit);
if (opts->discard_changes) {
ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
@@ -761,9 +796,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct unpack_trees_options topts;
const struct object_id *old_commit_oid;
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
- if (unmerged_cache()) {
+ if (unmerged_index(&the_index)) {
error(_("you need to resolve your current index first"));
return 1;
}
@@ -812,7 +847,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
*/
if (!old_branch_info->commit)
return 1;
- old_tree = get_commit_tree(old_branch_info->commit);
+ old_tree = repo_get_commit_tree(the_repository,
+ old_branch_info->commit);
if (repo_index_has_changes(the_repository, old_tree, &sb))
die(_("cannot continue with staged changes in "
@@ -832,7 +868,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
* entries in the index.
*/
- add_files_to_cache(NULL, NULL, 0);
+ add_files_to_cache(the_repository, NULL, NULL, 0, 0);
init_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);
@@ -867,7 +903,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
}
- if (!cache_tree_fully_valid(active_cache_tree))
+ if (!cache_tree_fully_valid(the_index.cache_tree))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
@@ -884,7 +920,7 @@ static void report_tracking(struct branch_info *new_branch_info)
struct strbuf sb = STRBUF_INIT;
struct branch *branch = branch_get(new_branch_info->name);
- if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL))
+ if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL, 1))
return;
fputs(sb.buf, stdout);
strbuf_release(&sb);
@@ -1001,7 +1037,7 @@ static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
strbuf_addstr(sb, " ");
strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV);
strbuf_addch(sb, ' ');
- if (!parse_commit(commit))
+ if (!repo_parse_commit(the_repository, commit))
pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
strbuf_addch(sb, '\n');
}
@@ -1057,7 +1093,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
" git branch <new-branch-name> %s\n\n",
/* Give ngettext() the count */
lost),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
}
/*
@@ -1157,11 +1193,14 @@ static int switch_branches(const struct checkout_opts *opts,
return ret || writeout_error;
}
-static int git_checkout_config(const char *var, const char *value, void *cb)
+static int git_checkout_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
struct checkout_opts *opts = cb;
if (!strcmp(var, "diff.ignoresubmodules")) {
+ if (!value)
+ return config_error_nonbool(var);
handle_ignore_submodules_arg(&opts->diff_options, value);
return 0;
}
@@ -1173,7 +1212,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
if (starts_with(var, "submodule."))
return git_default_submodule_config(var, value, NULL);
- return git_xmerge_config(var, value, NULL);
+ return git_xmerge_config(var, value, ctx, NULL);
}
static void setup_new_branch_info_and_source_tree(
@@ -1201,7 +1240,8 @@ static void setup_new_branch_info_and_source_tree(
*source_tree = parse_tree_indirect(rev);
} else {
parse_commit_or_die(new_branch_info->commit);
- *source_tree = get_commit_tree(new_branch_info->commit);
+ *source_tree = repo_get_commit_tree(the_repository,
+ new_branch_info->commit);
}
}
@@ -1269,7 +1309,7 @@ static int parse_branchname_arg(int argc, const char **argv,
* between A and B, A...B names that merge base.
*
* (b) If <something> is _not_ a commit, either "--" is present
- * or <something> is not a path, no -t or -b was given, and
+ * or <something> is not a path, no -t or -b was given,
* and there is a tracking branch whose name is <something>
* in one and only one remote (or if the branch exists on the
* remote named in checkout.defaultRemote), then this is a
@@ -1319,7 +1359,7 @@ static int parse_branchname_arg(int argc, const char **argv,
if (!strcmp(arg, "-"))
arg = "@{-1}";
- if (get_oid_mb(arg, rev)) {
+ if (repo_get_oid_mb(the_repository, arg, rev)) {
/*
* Either case (3) or (4), with <something> not being
* a commit, or an attempt to use case (1) with an
@@ -1416,7 +1456,8 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
char *to_free;
int code;
- if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
+ if (repo_dwim_ref(the_repository, branch_info->name,
+ strlen(branch_info->name), &oid, &to_free, 0) == 1) {
const char *ref = to_free;
if (skip_prefix(ref, "refs/tags/", &ref))
@@ -1470,6 +1511,28 @@ static void die_if_some_operation_in_progress(void)
"or \"git worktree add\"."));
if (state.bisect_in_progress)
warning(_("you are switching branch while bisecting"));
+
+ wt_status_state_free_buffers(&state);
+}
+
+/*
+ * die if attempting to checkout an existing branch that is in use
+ * in another worktree, unless ignore-other-wortrees option is given.
+ * The check is bypassed when the branch is already the current one,
+ * as it will not make things any worse.
+ */
+static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
+ const char *full_ref)
+{
+ int flags;
+ char *head_ref;
+
+ if (opts->ignore_other_worktrees)
+ return;
+ head_ref = resolve_refdup("HEAD", 0, NULL, &flags);
+ if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
+ die_if_checked_out(full_ref, 1);
+ free(head_ref);
}
static int checkout_branch(struct checkout_opts *opts,
@@ -1532,14 +1595,15 @@ static int checkout_branch(struct checkout_opts *opts,
if (!opts->can_switch_when_in_progress)
die_if_some_operation_in_progress();
- if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
- !opts->ignore_other_worktrees) {
- int flag;
- char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
- if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new_branch_info->path)))
- die_if_checked_out(new_branch_info->path, 1);
- free(head_ref);
+ /* "git checkout <branch>" */
+ if (new_branch_info->path && !opts->force_detach && !opts->new_branch)
+ die_if_switching_to_a_branch_in_use(opts, new_branch_info->path);
+
+ /* "git checkout -B <branch>" */
+ if (opts->new_branch_force) {
+ char *full_ref = xstrfmt("refs/heads/%s", opts->new_branch);
+ die_if_switching_to_a_branch_in_use(opts, full_ref);
+ free(full_ref);
}
if (!new_branch_info->commit && opts->new_branch) {
@@ -1583,7 +1647,7 @@ static struct option *add_common_switch_branch_options(
parse_opt_tracking_mode),
OPT__FORCE(&opts->force, N_("force checkout (throw away local modifications)"),
PARSE_OPT_NOCOMPLETE),
- OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
+ OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unborn branch")),
OPT_BOOL_F(0, "overwrite-ignore", &opts->overwrite_ignore,
N_("update ignored files (default)"),
PARSE_OPT_NOCOMPLETE),
@@ -1656,8 +1720,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if (opts->conflict_style) {
+ struct key_value_info kvi = KVI_INIT;
+ struct config_context ctx = {
+ .kvi = &kvi,
+ };
opts->merge = 1; /* implied */
- git_xmerge_config("merge.conflictstyle", opts->conflict_style, NULL);
+ git_xmerge_config("merge.conflictstyle", opts->conflict_style,
+ &ctx, NULL);
}
if (opts->force) {
opts->discard_changes = 1;
@@ -1743,7 +1812,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
} else if (!opts->accept_ref && opts->from_treeish) {
struct object_id rev;
- if (get_oid_mb(opts->from_treeish, &rev))
+ if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
die(_("could not resolve %s"), opts->from_treeish);
setup_new_branch_info_and_source_tree(new_branch_info,
@@ -1871,6 +1940,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
options, checkout_usage, &new_branch_info);
branch_info_release(&new_branch_info);
clear_pathspec(&opts.pathspec);
+ free(opts.pathspec_from_file);
FREE_AND_NULL(options);
return ret;
}
diff --git a/builtin/clean.c b/builtin/clean.c
index 5466636e66..d90766cad3 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -6,12 +6,17 @@
* Based on git-clean.sh by Pavel Roskin
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "string-list.h"
#include "quote.h"
#include "column.h"
@@ -26,7 +31,7 @@ static struct string_list del_list = STRING_LIST_INIT_DUP;
static unsigned int colopts;
static const char *const builtin_clean_usage[] = {
- N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
+ N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...]"),
NULL
};
@@ -99,7 +104,8 @@ struct menu_stuff {
define_list_config_array(color_interactive_slots);
-static int git_clean_config(const char *var, const char *value, void *cb)
+static int git_clean_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
const char *slot_name;
@@ -126,8 +132,10 @@ static int git_clean_config(const char *var, const char *value, void *cb)
return 0;
}
- /* inspect the color.ui config variable and others */
- return git_color_default_config(var, value, cb);
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static const char *clean_get_color(enum color_clean ix)
@@ -560,7 +568,7 @@ static int parse_choice(struct menu_stuff *menu_stuff,
/*
* Implement a git-add-interactive compatible UI, which is borrowed
- * from git-add--interactive.perl.
+ * from add-interactive.c.
*
* Return value:
*
@@ -963,7 +971,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (ignored && ignored_only)
- die(_("-x and -X cannot be used together"));
+ die(_("options '%s' and '%s' cannot be used together"), "-x", "-X");
if (!ignored)
setup_standard_excludes(&dir);
if (ignored_only)
@@ -1012,7 +1020,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
@@ -1031,7 +1039,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
struct stat st;
const char *rel;
- if (!cache_name_is_other(ent->name, ent->len))
+ if (!index_name_is_other(&the_index, ent->name, ent->len))
continue;
if (lstat(ent->name, &st))
@@ -1092,5 +1100,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
string_list_clear(&del_list, 0);
string_list_clear(&exclude_list, 0);
+ clear_pathspec(&pathspec);
return (errors != 0);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index d4a64e1582..bad1b70ce8 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -8,15 +8,21 @@
* Clone a repository into a different directory that does not yet exist.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "parse-options.h"
-#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -29,8 +35,11 @@
#include "branch.h"
#include "remote.h"
#include "run-command.h"
+#include "setup.h"
#include "connected.h"
#include "packfile.h"
+#include "path.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "hook.h"
#include "bundle.h"
@@ -62,6 +71,7 @@ static char *remote_name = NULL;
static char *option_branch = NULL;
static struct string_list option_not = STRING_LIST_INIT_NODUP;
static const char *real_git_dir;
+static const char *ref_format;
static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
@@ -147,14 +157,13 @@ static struct option builtin_clone_options[] = {
N_("any cloned submodules will be shallow")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
N_("set config inside the new repository")),
OPT_STRING_LIST(0, "server-option", &server_options,
N_("server-specific"), N_("option to transmit")),
- OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
- TRANSPORT_FAMILY_IPV4),
- OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
- TRANSPORT_FAMILY_IPV6),
+ OPT_IPVERSION(&family),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
N_("apply partial clone filters to submodules")),
@@ -326,8 +335,18 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
- if (!iter)
+ if (!iter) {
+ if (errno == ENOTDIR) {
+ int saved_errno = errno;
+ struct stat st;
+
+ if (!lstat(src->buf, &st) && S_ISLNK(st.st_mode))
+ die(_("'%s' is a symlink, refusing to clone with --local"),
+ src->buf);
+ errno = saved_errno;
+ }
die_errno(_("failed to start iterator over '%s'"), src->buf);
+ }
strbuf_addch(src, '/');
src_len = src->len;
@@ -547,9 +566,9 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue;
if (ends_with(ref->name, "^{}"))
continue;
- if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK |
- OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
continue;
update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
@@ -653,9 +672,9 @@ static void update_head(const struct ref *our, const struct ref *remote,
static int git_sparse_checkout_init(const char *repo)
{
- struct strvec argv = STRVEC_INIT;
+ struct child_process cmd = CHILD_PROCESS_INIT;
int result = 0;
- strvec_pushl(&argv, "-C", repo, "sparse-checkout", "set", NULL);
+ strvec_pushl(&cmd.args, "-C", repo, "sparse-checkout", "set", NULL);
/*
* We must apply the setting in the current process
@@ -663,12 +682,12 @@ static int git_sparse_checkout_init(const char *repo)
*/
core_apply_sparse_checkout = 1;
- if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
+ cmd.git_cmd = 1;
+ if (run_command(&cmd)) {
error(_("failed to initialize sparse-checkout"));
result = 1;
}
- strvec_clear(&argv);
return result;
}
@@ -703,7 +722,7 @@ static int checkout(int submodule_progress, int filter_submodules)
/* We need to be in the new work tree for the checkout */
setup_work_tree();
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof opts);
opts.update = 1;
@@ -733,45 +752,49 @@ static int checkout(int submodule_progress, int filter_submodules)
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
- struct strvec args = STRVEC_INIT;
- strvec_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ strvec_pushl(&cmd.args, "submodule", "update", "--require-init",
+ "--recursive", NULL);
if (option_shallow_submodules == 1)
- strvec_push(&args, "--depth=1");
+ strvec_push(&cmd.args, "--depth=1");
if (max_jobs != -1)
- strvec_pushf(&args, "--jobs=%d", max_jobs);
+ strvec_pushf(&cmd.args, "--jobs=%d", max_jobs);
if (submodule_progress)
- strvec_push(&args, "--progress");
+ strvec_push(&cmd.args, "--progress");
if (option_verbosity < 0)
- strvec_push(&args, "--quiet");
+ strvec_push(&cmd.args, "--quiet");
if (option_remote_submodules) {
- strvec_push(&args, "--remote");
- strvec_push(&args, "--no-fetch");
+ strvec_push(&cmd.args, "--remote");
+ strvec_push(&cmd.args, "--no-fetch");
}
if (filter_submodules && filter_options.choice)
- strvec_pushf(&args, "--filter=%s",
+ strvec_pushf(&cmd.args, "--filter=%s",
expand_list_objects_filter_spec(&filter_options));
if (option_single_branch >= 0)
- strvec_push(&args, option_single_branch ?
+ strvec_push(&cmd.args, option_single_branch ?
"--single-branch" :
"--no-single-branch");
- err = run_command_v_opt(args.v, RUN_GIT_CMD);
- strvec_clear(&args);
+ cmd.git_cmd = 1;
+ err = run_command(&cmd);
}
return err;
}
-static int git_clone_config(const char *k, const char *v, void *cb)
+static int git_clone_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "clone.defaultremotename")) {
+ if (!v)
+ return config_error_nonbool(k);
free(remote_name);
remote_name = xstrdup(v);
}
@@ -780,17 +803,19 @@ static int git_clone_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "clone.filtersubmodules"))
config_filter_submodules = git_config_bool(k, v);
- return git_default_config(k, v, cb);
+ return git_default_config(k, v, ctx, cb);
}
-static int write_one_config(const char *key, const char *value, void *data)
+static int write_one_config(const char *key, const char *value,
+ const struct config_context *ctx,
+ void *data)
{
/*
* give git_clone_config a chance to write config values back to the
* environment, since git_config_set_multivar_gently only deals with
* config-file writes
*/
- int apply_failed = git_clone_config(key, value, data);
+ int apply_failed = git_clone_config(key, value, ctx, data);
if (apply_failed)
return apply_failed;
@@ -864,11 +889,15 @@ static void write_refspec_config(const char *src_ref_prefix,
static void dissociate_from_references(void)
{
- static const char* argv[] = { "repack", "-a", "-d", NULL };
char *alternates = git_pathdup("objects/info/alternates");
if (!access(alternates, F_OK)) {
- if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ cmd.git_cmd = 1;
+ cmd.no_stdin = 1;
+ strvec_pushl(&cmd.args, "repack", "-a", "-d", NULL);
+ if (run_command(&cmd))
die(_("cannot repack to clean up"));
if (unlink(alternates) && errno != ENOENT)
die_errno(_("cannot unlink temporary alternates file"));
@@ -887,6 +916,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int is_bundle = 0, is_local;
int reject_shallow = 0;
const char *repo_name, *repo, *work_tree, *git_dir;
+ char *repo_to_free = NULL;
char *path = NULL, *dir, *display_repo = NULL;
int dest_exists, real_dest_exists = 0;
const struct ref *refs, *remote_head;
@@ -903,6 +933,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
int filter_submodules = 0;
+ int hash_algo;
+ unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+ const int do_not_override_repo_unix_permissions = -1;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -927,6 +960,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_single_branch == -1)
option_single_branch = deepen ? 1 : 0;
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (option_mirror)
option_bare = 1;
@@ -937,14 +976,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (bundle_uri && deepen)
- die(_("--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-exclude"));
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--bundle-uri",
+ "--depth/--shallow-since/--shallow-exclude");
repo_name = argv[0];
path = get_repo_path(repo_name, &is_bundle);
if (path) {
FREE_AND_NULL(path);
- repo = absolute_pathdup(repo_name);
+ repo = repo_to_free = absolute_pathdup(repo_name);
} else if (strchr(repo_name, ':')) {
repo = repo_name;
display_repo = transport_anonymize_url(repo);
@@ -1069,8 +1110,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
- INIT_DB_QUIET);
+ /*
+ * Initialize the repository, but skip initializing the reference
+ * database. We do not yet know about the object format of the
+ * repository, and reference backends may persist that information into
+ * their on-disk data structures.
+ */
+ init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
+ ref_storage_format, NULL,
+ do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
if (real_git_dir) {
free((char *)git_dir);
@@ -1157,10 +1205,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- if (option_sparse_checkout && git_sparse_checkout_init(dir))
- return 1;
-
- remote = remote_get(remote_name);
+ remote = remote_get_early(remote_name);
refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
branch_top.buf);
@@ -1238,19 +1283,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
- /*
- * Before fetching from the remote, download and install bundle
- * data from the --bundle-uri option.
- */
- if (bundle_uri) {
- /* At this point, we need the_repository to match the cloned repo. */
- if (repo_init(the_repository, git_dir, work_tree))
- warning(_("failed to initialize the repo, skipping bundle URI"));
- else if (fetch_bundle_uri(the_repository, bundle_uri))
- warning(_("failed to fetch objects from bundle URI '%s'"),
- bundle_uri);
- }
-
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
refspec_ref_prefixes(&remote->fetch,
&transport_ls_refs_options.ref_prefixes);
@@ -1263,18 +1295,55 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
+ /*
+ * Now that we know what algorithm the remote side is using, let's set
+ * ours to the same thing.
+ */
+ hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+ initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
+ repo_set_hash_algo(the_repository, hash_algo);
+ create_reference_database(the_repository->ref_storage_format, NULL, 1);
+
+ /*
+ * Before fetching from the remote, download and install bundle
+ * data from the --bundle-uri option.
+ */
+ if (bundle_uri) {
+ int has_heuristic = 0;
+
+ /* At this point, we need the_repository to match the cloned repo. */
+ if (repo_init(the_repository, git_dir, work_tree))
+ warning(_("failed to initialize the repo, skipping bundle URI"));
+ else if (fetch_bundle_uri(the_repository, bundle_uri, &has_heuristic))
+ warning(_("failed to fetch objects from bundle URI '%s'"),
+ bundle_uri);
+ else if (has_heuristic)
+ git_config_set_gently("fetch.bundleuri", bundle_uri);
+ } else {
+ /*
+ * Populate transport->got_remote_bundle_uri and
+ * transport->bundle_uri. We might get nothing.
+ */
+ transport_get_remote_bundle_uri(transport);
+
+ if (transport->bundles &&
+ hashmap_get_size(&transport->bundles->bundles)) {
+ /* At this point, we need the_repository to match the cloned repo. */
+ if (repo_init(the_repository, git_dir, work_tree))
+ warning(_("failed to initialize the repo, skipping bundle URI"));
+ else if (fetch_bundle_list(the_repository,
+ transport->bundles))
+ warning(_("failed to fetch advertised bundles"));
+ } else {
+ clear_bundle_list(transport->bundles);
+ FREE_AND_NULL(transport->bundles);
+ }
+ }
+
if (refs)
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
if (mapped_refs) {
- int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
-
- /*
- * Now that we know what algorithm the remote side is using,
- * let's set ours to the same thing.
- */
- initialize_repository_version(hash_algo, 1);
- repo_set_hash_algo(the_repository, hash_algo);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
@@ -1375,6 +1444,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
dissociate_from_references();
}
+ if (option_sparse_checkout && git_sparse_checkout_init(dir))
+ return 1;
+
junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress, filter_submodules);
@@ -1387,7 +1459,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(unborn_head);
free(dir);
free(path);
- UNLEAK(repo);
+ free(repo_to_free);
junk_mode = JUNK_LEAVE_ALL;
transport_ls_refs_options_release(&transport_ls_refs_options);
diff --git a/builtin/column.c b/builtin/column.c
index 158fdf53d9..e80218f81f 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -1,6 +1,6 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
#include "strbuf.h"
#include "parse-options.h"
#include "string-list.h"
@@ -12,7 +12,8 @@ static const char * const builtin_column_usage[] = {
};
static unsigned int colopts;
-static int column_config(const char *var, const char *value, void *cb)
+static int column_config(const char *var, const char *value,
+ const struct config_context *ctx UNUSED, void *cb)
{
return git_column_config(var, value, cb, &colopts);
}
@@ -55,5 +56,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
string_list_append(&list, sb.buf);
print_columns(&list, colopts, &copts);
+ strbuf_release(&sb);
+ string_list_clear(&list, 0);
return 0;
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 51557fe786..666ad574a4 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -1,22 +1,27 @@
#include "builtin.h"
+#include "commit.h"
#include "config.h"
-#include "dir.h"
-#include "lockfile.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
#include "repository.h"
#include "commit-graph.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "progress.h"
+#include "replace-object.h"
+#include "strbuf.h"
#include "tag.h"
+#include "trace2.h"
#define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
- N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]")
+ N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]")
#define BUILTIN_COMMIT_GRAPH_WRITE_USAGE \
- N_("git commit-graph write [--object-dir <objdir>] [--append] " \
- "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] " \
- "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] " \
- "<split options>")
+ N_("git commit-graph write [--object-dir <dir>] [--append]\n" \
+ " [--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]\n" \
+ " [--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]\n" \
+ " <split options>")
static const char * builtin_commit_graph_verify_usage[] = {
BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
@@ -63,10 +68,13 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
struct commit_graph *graph = NULL;
struct object_directory *odb = NULL;
char *graph_name;
- int open_ok;
+ char *chain_name;
+ enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
int fd;
struct stat st;
int flags = 0;
+ int incomplete_chain = 0;
+ int ret;
static struct option builtin_commit_graph_verify_options[] = {
OPT_BOOL(0, "shallow", &opts.shallow,
@@ -95,24 +103,40 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
odb = find_odb(the_repository, opts.obj_dir);
graph_name = get_commit_graph_filename(odb);
- open_ok = open_commit_graph(graph_name, &fd, &st);
- if (!open_ok && errno != ENOENT)
+ chain_name = get_commit_graph_chain_filename(odb);
+ if (open_commit_graph(graph_name, &fd, &st))
+ opened = OPENED_GRAPH;
+ else if (errno != ENOENT)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
+ else if (open_commit_graph_chain(chain_name, &fd, &st))
+ opened = OPENED_CHAIN;
+ else if (errno != ENOENT)
+ die_errno(_("could not open commit-graph chain '%s'"), chain_name);
FREE_AND_NULL(graph_name);
+ FREE_AND_NULL(chain_name);
FREE_AND_NULL(options);
- if (open_ok)
+ if (opened == OPENED_NONE)
+ return 0;
+ else if (opened == OPENED_GRAPH)
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
else
- graph = read_commit_graph_one(the_repository, odb);
+ graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+ &incomplete_chain);
- /* Return failure if open_ok predicted success */
if (!graph)
- return !!open_ok;
+ return 1;
+
+ ret = verify_commit_graph(the_repository, graph, flags);
+ free_commit_graph(graph);
- UNLEAK(graph);
- return verify_commit_graph(the_repository, graph, flags);
+ if (incomplete_chain) {
+ error("one or more commit-graph chain files could not be loaded");
+ ret |= 1;
+ }
+
+ return ret;
}
extern int read_replace_refs;
@@ -179,10 +203,11 @@ static int write_option_max_new_filters(const struct option *opt,
}
static int git_commit_graph_write_config(const char *var, const char *value,
+ const struct config_context *ctx,
void *cb UNUSED)
{
if (!strcmp(var, "commitgraph.maxnewfilters"))
- write_opts.max_new_filters = git_config_int(var, value);
+ write_opts.max_new_filters = git_config_int(var, value, ctx->kvi);
/*
* No need to fall-back to 'git_default_config', since this was already
* called in 'cmd_commit_graph()'.
@@ -267,8 +292,8 @@ static int graph_write(int argc, const char **argv, const char *prefix)
if (opts.reachable) {
if (write_commit_graph_reachable(odb, flags, &write_opts))
- return 1;
- return 0;
+ result = 1;
+ goto cleanup;
}
if (opts.stdin_packs) {
@@ -302,6 +327,7 @@ cleanup:
FREE_AND_NULL(options);
string_list_clear(&pack_indexes, 0);
strbuf_release(&buf);
+ oidset_clear(&commits);
return result;
}
@@ -317,7 +343,7 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
- read_replace_refs = 0;
+ disable_replace_refs();
save_commit_buffer = 0;
argc = parse_options(argc, argv, prefix, options,
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 63ea322933..1bb7819839 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -3,20 +3,20 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "repository.h"
#include "commit.h"
-#include "tree.h"
-#include "builtin.h"
-#include "utf8.h"
-#include "gpg-interface.h"
#include "parse-options.h"
static const char * const commit_tree_usage[] = {
- N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] "
- "[(-F <file>)...] <tree>"),
+ N_("git commit-tree <tree> [(-p <parent>)...]"),
+ N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
+ " [(-F <file>)...] <tree>"),
NULL
};
@@ -36,14 +36,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
commit_list_insert(parent, parents_p);
}
-static int commit_tree_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, NULL);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
static int parse_parent_arg_callback(const struct option *opt,
const char *arg, int unset)
{
@@ -52,7 +44,7 @@ static int parse_parent_arg_callback(const struct option *opt,
BUG_ON_OPT_NEG_NOARG(unset, arg);
- if (get_oid_commit(arg, &oid))
+ if (repo_get_oid_commit(the_repository, arg, &oid))
die(_("not a valid object name %s"), arg);
assert_oid_type(&oid, OBJ_COMMIT);
@@ -120,7 +112,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(commit_tree_config, NULL);
+ git_config(git_default_config, NULL);
if (argc < 2 || !strcmp(argv[1], "-h"))
usage_with_options(commit_tree_usage, options);
@@ -130,7 +122,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (argc != 1)
die(_("must give exactly one tree"));
- if (get_oid_tree(argv[0], &tree_oid))
+ if (repo_get_oid_tree(the_repository, argv[0], &tree_oid))
die(_("not a valid object name %s"), argv[0]);
if (!buffer.len) {
diff --git a/builtin/commit.c b/builtin/commit.c
index d9de4ef008..65196a2827 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -5,34 +5,34 @@
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
+#include "advice.h"
#include "config.h"
#include "lockfile.h"
#include "cache-tree.h"
#include "color.h"
#include "dir.h"
-#include "builtin.h"
+#include "editor.h"
+#include "environment.h"
#include "diff.h"
-#include "diffcore.h"
#include "commit.h"
+#include "gettext.h"
#include "revision.h"
#include "wt-status.h"
#include "run-command.h"
-#include "hook.h"
-#include "refs.h"
-#include "log-tree.h"
#include "strbuf.h"
-#include "utf8.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "string-list.h"
#include "rerere.h"
#include "unpack-trees.h"
-#include "quote.h"
-#include "submodule.h"
-#include "gpg-interface.h"
#include "column.h"
#include "sequencer.h"
+#include "sparse-index.h"
#include "mailmap.h"
#include "help.h"
#include "commit-reach.h"
@@ -40,12 +40,19 @@
#include "pretty.h"
static const char * const builtin_commit_usage[] = {
- N_("git commit [<options>] [--] <pathspec>..."),
+ N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+ " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n"
+ " [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
+ " [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
+ " [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+ " [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+ " [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
+ " [--] [<pathspec>...]"),
NULL
};
static const char * const builtin_status_usage[] = {
- N_("git status [<options>] [--] <pathspec>..."),
+ N_("git status [<options>] [--] [<pathspec>...]"),
NULL
};
@@ -265,8 +272,8 @@ static int list_paths(struct string_list *list, const char *with_tree,
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ const struct cache_entry *ce = the_index.cache[i];
struct string_list_item *item;
if (ce->ce_flags & CE_UPDATE)
@@ -295,10 +302,10 @@ static void add_remove_files(struct string_list *list)
continue;
if (!lstat(p->string, &st)) {
- if (add_to_cache(p->string, &st, 0))
+ if (add_to_index(&the_index, p->string, &st, 0))
die(_("updating files failed"));
} else
- remove_file_from_cache(p->string);
+ remove_file_from_index(&the_index, p->string);
}
}
@@ -309,7 +316,7 @@ static void create_base_index(const struct commit *current_head)
struct tree_desc t;
if (!current_head) {
- discard_cache();
+ discard_index(&the_index);
return;
}
@@ -336,7 +343,7 @@ static void refresh_cache_or_die(int refresh_flags)
* refresh_flags contains REFRESH_QUIET, so the only errors
* are for unmerged entries.
*/
- if (refresh_cache(refresh_flags | REFRESH_IN_PORCELAIN))
+ if (refresh_index(&the_index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
die_resolve_conflict("commit");
}
@@ -375,12 +382,13 @@ static const char *prepare_index(const char **argv, const char *prefix,
(!amend || (fixup_message && strcmp(fixup_prefix, "amend"))))))
die(_("No paths with --include/--only does not make sense."));
- if (read_cache_preload(&pathspec) < 0)
+ if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
die(_("index file corrupt"));
if (interactive) {
char *old_index_env = NULL, *old_repo_index_file;
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &index_lock,
+ LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
@@ -403,9 +411,10 @@ static const char *prepare_index(const char **argv, const char *prefix,
unsetenv(INDEX_ENVIRONMENT);
FREE_AND_NULL(old_index_env);
- discard_cache();
- read_cache_from(get_lock_file_path(&index_lock));
- if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+ discard_index(&the_index);
+ read_index_from(&the_index, get_lock_file_path(&index_lock),
+ get_git_dir());
+ if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
if (write_locked_index(&the_index, &index_lock, 0))
@@ -431,12 +440,14 @@ static const char *prepare_index(const char **argv, const char *prefix,
* (B) on failure, rollback the real index.
*/
if (all || (also && pathspec.nr)) {
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
- add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
+ repo_hold_locked_index(the_repository, &index_lock,
+ LOCK_DIE_ON_ERROR);
+ add_files_to_cache(the_repository, also ? prefix : NULL,
+ &pathspec, 0, 0);
refresh_cache_or_die(refresh_flags);
- update_main_cache_tree(WRITE_TREE_SILENT);
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
- die(_("unable to write new_index file"));
+ die(_("unable to write new index file"));
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
goto out;
@@ -452,14 +463,15 @@ static const char *prepare_index(const char **argv, const char *prefix,
* We still need to refresh the index here.
*/
if (!only && !pathspec.nr) {
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &index_lock,
+ LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
- if (active_cache_changed
- || !cache_tree_fully_valid(active_cache_tree))
- update_main_cache_tree(WRITE_TREE_SILENT);
+ if (the_index.cache_changed
+ || !cache_tree_fully_valid(the_index.cache_tree))
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die(_("unable to write new_index file"));
+ die(_("unable to write new index file"));
commit_style = COMMIT_AS_IS;
ret = get_index_file();
goto out;
@@ -498,16 +510,16 @@ static const char *prepare_index(const char **argv, const char *prefix,
if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
exit(1);
- discard_cache();
- if (read_cache() < 0)
+ discard_index(&the_index);
+ if (repo_read_index(the_repository) < 0)
die(_("cannot read the index"));
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
add_remove_files(&partial);
- refresh_cache(REFRESH_QUIET);
- update_main_cache_tree(WRITE_TREE_SILENT);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
- die(_("unable to write new_index file"));
+ die(_("unable to write new index file"));
hold_lock_file_for_update(&false_lock,
git_path("next-index-%"PRIuMAX,
@@ -516,14 +528,14 @@ static const char *prepare_index(const char **argv, const char *prefix,
create_base_index(current_head);
add_remove_files(&partial);
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
if (write_locked_index(&the_index, &false_lock, 0))
die(_("unable to write temporary index file"));
- discard_cache();
+ discard_index(&the_index);
ret = get_lock_file_path(&false_lock);
- read_cache_from(ret);
+ read_index_from(&the_index, ret, get_git_dir());
out:
string_list_clear(&partial, 0);
clear_pathspec(&pathspec);
@@ -546,7 +558,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
s->index_file = index_file;
s->fp = fp;
s->nowarn = nowarn;
- s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
+ s->is_initial = repo_get_oid(the_repository, s->reference, &oid) ? 1 : 0;
if (!s->is_initial)
oidcpy(&s->oid_commit, &oid);
s->status_format = status_format;
@@ -701,15 +713,15 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
{
const char *buffer, *subject, *fmt;
- buffer = get_commit_buffer(commit, NULL);
+ buffer = repo_get_commit_buffer(the_repository, commit, NULL);
find_commit_subject(buffer, &subject);
/*
* If we amend the 'amend!' commit then we don't want to
* duplicate the subject line.
*/
fmt = starts_with(subject, "amend!") ? "%b" : "%B";
- format_commit_message(commit, fmt, sb, ctx);
- unuse_commit_buffer(commit, buffer);
+ repo_format_commit_message(the_repository, commit, fmt, sb, ctx);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
}
static int prepare_to_commit(const char *index_file, const char *prefix,
@@ -747,10 +759,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct commit *c;
c = lookup_commit_reference_by_name(squash_message);
if (!c)
- die(_("could not lookup commit %s"), squash_message);
+ die(_("could not lookup commit '%s'"), squash_message);
ctx.output_encoding = get_commit_output_encoding();
- format_commit_message(c, "squash! %s\n\n", &sb,
- &ctx);
+ repo_format_commit_message(the_repository, c,
+ "squash! %s\n\n", &sb,
+ &ctx);
}
}
@@ -781,10 +794,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
char *fmt;
commit = lookup_commit_reference_by_name(fixup_commit);
if (!commit)
- die(_("could not lookup commit %s"), fixup_commit);
+ die(_("could not lookup commit '%s'"), fixup_commit);
ctx.output_encoding = get_commit_output_encoding();
fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
- format_commit_message(commit, fmt, &sb, &ctx);
+ repo_format_commit_message(the_repository, commit, fmt, &sb,
+ &ctx);
free(fmt);
hook_arg1 = "message";
@@ -875,10 +889,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->hints = 0;
if (clean_message_contents)
- strbuf_stripspace(&sb, 0);
+ strbuf_stripspace(&sb, '\0');
if (signoff)
- append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
+ append_signoff(&sb, ignored_log_message_bytes(sb.buf, sb.len), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
@@ -980,21 +994,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct object_id oid;
const char *parent = "HEAD";
- if (!active_nr && read_cache() < 0)
+ if (!the_index.initialized && repo_read_index(the_repository) < 0)
die(_("Cannot read index"));
if (amend)
parent = "HEAD^1";
- if (get_oid(parent, &oid)) {
+ if (repo_get_oid(the_repository, parent, &oid)) {
int i, ita_nr = 0;
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++)
- if (ce_intent_to_add(active_cache[i]))
+ for (i = 0; i < the_index.cache_nr; i++)
+ if (ce_intent_to_add(the_index.cache[i]))
ita_nr++;
- committable = active_nr - ita_nr > 0;
+ committable = the_index.cache_nr - ita_nr > 0;
} else {
/*
* Unless the user did explicitly request a submodule
@@ -1022,7 +1036,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct child_process run_trailer = CHILD_PROCESS_INIT;
strvec_pushl(&run_trailer.args, "interpret-trailers",
- "--in-place", git_path_commit_editmsg(), NULL);
+ "--in-place", "--no-divider",
+ git_path_commit_editmsg(), NULL);
strvec_pushv(&run_trailer.args, trailer_args.v);
run_trailer.git_cmd = 1;
if (run_command(&run_trailer))
@@ -1061,11 +1076,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
* and could have updated it. We must do this before we invoke
* the editor and after we invoke run_status above.
*/
- discard_cache();
+ discard_index(&the_index);
}
- read_cache_from(index_file);
+ read_index_from(&the_index, index_file, get_git_dir());
- if (update_main_cache_tree(0)) {
+ if (cache_tree_update(&the_index, 0)) {
error(_("Error building trees"));
return 0;
}
@@ -1121,7 +1136,8 @@ static const char *find_author_by_nickname(const char *name)
struct pretty_print_context ctx = {0};
ctx.date_mode.type = DATE_NORMAL;
strbuf_release(&buf);
- format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+ repo_format_commit_message(the_repository, commit,
+ "%aN <%aE>", &buf, &ctx);
release_revisions(&revs);
return strbuf_detach(&buf, NULL);
}
@@ -1167,9 +1183,9 @@ static const char *read_commit_message(const char *name)
commit = lookup_commit_reference_by_name(name);
if (!commit)
- die(_("could not lookup commit %s"), name);
+ die(_("could not lookup commit '%s'"), name);
out_enc = get_commit_output_encoding();
- return logmsg_reencode(commit, NULL, out_enc);
+ return repo_logmsg_reencode(the_repository, commit, NULL, out_enc);
}
/*
@@ -1383,7 +1399,8 @@ static int parse_status_slot(const char *slot)
return LOOKUP_CONFIG(color_status_slots, slot);
}
-static int git_status_config(const char *k, const char *v, void *cb)
+static int git_status_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
struct wt_status *s = cb;
const char *slot_name;
@@ -1392,7 +1409,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
return git_column_config(k, v, "status", &s->colopts);
if (!strcmp(k, "status.submodulesummary")) {
int is_bool;
- s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+ s->submodule_summary = git_config_bool_or_int(k, v, ctx->kvi,
+ &is_bool);
if (is_bool && s->submodule_summary)
s->submodule_summary = -1;
return 0;
@@ -1452,11 +1470,11 @@ static int git_status_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "diff.renamelimit")) {
if (s->rename_limit == -1)
- s->rename_limit = git_config_int(k, v);
+ s->rename_limit = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "status.renamelimit")) {
- s->rename_limit = git_config_int(k, v);
+ s->rename_limit = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "diff.renames")) {
@@ -1468,7 +1486,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
s->detect_rename = git_config_rename(k, v);
return 0;
}
- return git_diff_ui_config(k, v, NULL);
+ return git_diff_ui_config(k, v, ctx, NULL);
}
int cmd_status(int argc, const char **argv, const char *prefix)
@@ -1549,11 +1567,11 @@ int cmd_status(int argc, const char **argv, const char *prefix)
&s.pathspec, NULL, NULL);
if (use_optional_locks())
- fd = hold_locked_index(&index_lock, 0);
+ fd = repo_hold_locked_index(the_repository, &index_lock, 0);
else
fd = -1;
- s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
+ s.is_initial = repo_get_oid(the_repository, s.reference, &oid) ? 1 : 0;
if (!s.is_initial)
oidcpy(&s.oid_commit, &oid);
@@ -1583,10 +1601,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_commit_config(const char *k, const char *v, void *cb)
+static int git_commit_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
struct wt_status *s = cb;
- int status;
if (!strcmp(k, "commit.template"))
return git_config_pathname(&template_file, k, v);
@@ -1602,14 +1620,12 @@ static int git_commit_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "commit.verbose")) {
int is_bool;
- config_commit_verbose = git_config_bool_or_int(k, v, &is_bool);
+ config_commit_verbose = git_config_bool_or_int(k, v, ctx->kvi,
+ &is_bool);
return 0;
}
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
- return git_status_config(k, v, s);
+ return git_status_config(k, v, ctx, s);
}
int cmd_commit(int argc, const char **argv, const char *prefix)
@@ -1700,11 +1716,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
s.colopts = 0;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
current_head = NULL;
else {
current_head = lookup_commit_or_die(&oid, "HEAD");
- if (parse_commit(current_head))
+ if (repo_parse_commit(the_repository, current_head))
die(_("could not parse HEAD commit"));
}
verbose = -1; /* unspecified */
@@ -1816,7 +1832,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
append_merge_tag_headers(parents, &tail);
}
- if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
+ if (commit_tree_extended(sb.buf, sb.len, &the_index.cache_tree->oid,
parents, &oid, author_ident.buf, NULL,
sign_commit, extra)) {
rollback_index_files();
@@ -1838,7 +1854,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (commit_index_files())
die(_("repository has been updated, but unable to write\n"
- "new_index file. Check that disk is not full and quota is\n"
+ "new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."));
git_test_write_commit_graph_or_die();
@@ -1864,8 +1880,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
apply_autostash(git_path_merge_autostash(the_repository));
cleanup:
- UNLEAK(author_ident);
- UNLEAK(err);
- UNLEAK(sb);
+ strbuf_release(&author_ident);
+ strbuf_release(&err);
+ strbuf_release(&sb);
return ret;
}
diff --git a/builtin/config.c b/builtin/config.c
index 753e5fac29..11a4d4ef14 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -1,10 +1,18 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
#include "color.h"
+#include "editor.h"
+#include "environment.h"
+#include "repository.h"
+#include "gettext.h"
+#include "ident.h"
#include "parse-options.h"
#include "urlmatch.h"
+#include "path.h"
#include "quote.h"
+#include "setup.h"
+#include "strbuf.h"
#include "worktree.h"
static const char *const builtin_config_usage[] = {
@@ -185,37 +193,42 @@ static void check_argc(int argc, int min, int max)
usage_builtin_config();
}
-static void show_config_origin(struct strbuf *buf)
+static void show_config_origin(const struct key_value_info *kvi,
+ struct strbuf *buf)
{
const char term = end_nul ? '\0' : '\t';
- strbuf_addstr(buf, current_config_origin_type());
+ strbuf_addstr(buf, config_origin_type_name(kvi->origin_type));
strbuf_addch(buf, ':');
if (end_nul)
- strbuf_addstr(buf, current_config_name());
+ strbuf_addstr(buf, kvi->filename ? kvi->filename : "");
else
- quote_c_style(current_config_name(), buf, NULL, 0);
+ quote_c_style(kvi->filename ? kvi->filename : "", buf, NULL, 0);
strbuf_addch(buf, term);
}
-static void show_config_scope(struct strbuf *buf)
+static void show_config_scope(const struct key_value_info *kvi,
+ struct strbuf *buf)
{
const char term = end_nul ? '\0' : '\t';
- const char *scope = config_scope_name(current_config_scope());
+ const char *scope = config_scope_name(kvi->scope);
strbuf_addstr(buf, N_(scope));
strbuf_addch(buf, term);
}
static int show_all_config(const char *key_, const char *value_,
+ const struct config_context *ctx,
void *cb UNUSED)
{
+ const struct key_value_info *kvi = ctx->kvi;
+
if (show_origin || show_scope) {
struct strbuf buf = STRBUF_INIT;
if (show_scope)
- show_config_scope(&buf);
+ show_config_scope(kvi, &buf);
if (show_origin)
- show_config_origin(&buf);
+ show_config_origin(kvi, &buf);
/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
@@ -233,12 +246,13 @@ struct strbuf_list {
int alloc;
};
-static int format_config(struct strbuf *buf, const char *key_, const char *value_)
+static int format_config(struct strbuf *buf, const char *key_,
+ const char *value_, const struct key_value_info *kvi)
{
if (show_scope)
- show_config_scope(buf);
+ show_config_scope(kvi, buf);
if (show_origin)
- show_config_origin(buf);
+ show_config_origin(kvi, buf);
if (show_keys)
strbuf_addstr(buf, key_);
if (!omit_values) {
@@ -247,13 +261,14 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
if (type == TYPE_INT)
strbuf_addf(buf, "%"PRId64,
- git_config_int64(key_, value_ ? value_ : ""));
+ git_config_int64(key_, value_ ? value_ : "", kvi));
else if (type == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
else if (type == TYPE_BOOL_OR_INT) {
int is_bool, v;
- v = git_config_bool_or_int(key_, value_, &is_bool);
+ v = git_config_bool_or_int(key_, value_, kvi,
+ &is_bool);
if (is_bool)
strbuf_addstr(buf, v ? "true" : "false");
else
@@ -292,9 +307,11 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
return 0;
}
-static int collect_config(const char *key_, const char *value_, void *cb)
+static int collect_config(const char *key_, const char *value_,
+ const struct config_context *ctx, void *cb)
{
struct strbuf_list *values = cb;
+ const struct key_value_info *kvi = ctx->kvi;
if (!use_key_regexp && strcmp(key_, key))
return 0;
@@ -309,7 +326,7 @@ static int collect_config(const char *key_, const char *value_, void *cb)
ALLOC_GROW(values->items, values->nr + 1, values->alloc);
strbuf_init(&values->items[values->nr], 0);
- return format_config(&values->items[values->nr++], key_, value_);
+ return format_config(&values->items[values->nr++], key_, value_, kvi);
}
static int get_value(const char *key_, const char *regex_, unsigned flags)
@@ -367,14 +384,18 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
}
config_with_options(collect_config, &values,
- &given_config_source, &config_options);
+ &given_config_source, the_repository,
+ &config_options);
if (!values.nr && default_value) {
+ struct key_value_info kvi = KVI_INIT;
struct strbuf *item;
+
+ kvi_from_param(&kvi);
ALLOC_GROW(values.items, values.nr + 1, values.alloc);
item = &values.items[values.nr++];
strbuf_init(item, 0);
- if (format_config(item, key_, default_value) < 0)
+ if (format_config(item, key_, default_value, &kvi) < 0)
die(_("failed to format default config value: %s"),
default_value);
}
@@ -403,7 +424,8 @@ free_strings:
return ret;
}
-static char *normalize_value(const char *key, const char *value)
+static char *normalize_value(const char *key, const char *value,
+ struct key_value_info *kvi)
{
if (!value)
return NULL;
@@ -418,12 +440,12 @@ static char *normalize_value(const char *key, const char *value)
*/
return xstrdup(value);
if (type == TYPE_INT)
- return xstrfmt("%"PRId64, git_config_int64(key, value));
+ return xstrfmt("%"PRId64, git_config_int64(key, value, kvi));
if (type == TYPE_BOOL)
return xstrdup(git_config_bool(key, value) ? "true" : "false");
if (type == TYPE_BOOL_OR_INT) {
int is_bool, v;
- v = git_config_bool_or_int(key, value, &is_bool);
+ v = git_config_bool_or_int(key, value, kvi, &is_bool);
if (!is_bool)
return xstrfmt("%d", v);
else
@@ -460,6 +482,7 @@ static const char *get_colorbool_slot;
static char parsed_color[COLOR_MAXLEN];
static int git_get_color_config(const char *var, const char *value,
+ const struct config_context *ctx UNUSED,
void *cb UNUSED)
{
if (!strcmp(var, get_color_slot)) {
@@ -478,7 +501,8 @@ static void get_color(const char *var, const char *def_color)
get_color_found = 0;
parsed_color[0] = '\0';
config_with_options(git_get_color_config, NULL,
- &given_config_source, &config_options);
+ &given_config_source, the_repository,
+ &config_options);
if (!get_color_found && def_color) {
if (color_parse(def_color, parsed_color) < 0)
@@ -492,6 +516,7 @@ static int get_colorbool_found;
static int get_diff_color_found;
static int get_color_ui_found;
static int git_get_colorbool_config(const char *var, const char *value,
+ const struct config_context *ctx UNUSED,
void *data UNUSED)
{
if (!strcmp(var, get_colorbool_slot))
@@ -510,7 +535,8 @@ static int get_colorbool(const char *var, int print)
get_diff_color_found = -1;
get_color_ui_found = -1;
config_with_options(git_get_colorbool_config, NULL,
- &given_config_source, &config_options);
+ &given_config_source, the_repository,
+ &config_options);
if (get_colorbool_found < 0) {
if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -547,13 +573,17 @@ static void check_write(void)
struct urlmatch_current_candidate_value {
char value_is_null;
struct strbuf value;
+ struct key_value_info kvi;
};
-static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
+static int urlmatch_collect_fn(const char *var, const char *value,
+ const struct config_context *ctx,
+ void *cb)
{
struct string_list *values = cb;
struct string_list_item *item = string_list_insert(values, var);
struct urlmatch_current_candidate_value *matched = item->util;
+ const struct key_value_info *kvi = ctx->kvi;
if (!matched) {
matched = xmalloc(sizeof(*matched));
@@ -562,6 +592,7 @@ static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
} else {
strbuf_reset(&matched->value);
}
+ matched->kvi = *kvi;
if (value) {
strbuf_addstr(&matched->value, value);
@@ -599,7 +630,8 @@ static int get_urlmatch(const char *var, const char *url)
}
config_with_options(urlmatch_config_entry, &config,
- &given_config_source, &config_options);
+ &given_config_source, the_repository,
+ &config_options);
ret = !values.nr;
@@ -608,7 +640,8 @@ static int get_urlmatch(const char *var, const char *url)
struct strbuf buf = STRBUF_INIT;
format_config(&buf, item->string,
- matched->value_is_null ? NULL : matched->value.buf);
+ matched->value_is_null ? NULL : matched->value.buf,
+ &matched->kvi);
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
@@ -639,8 +672,10 @@ static char *default_user_config(void)
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
- char *value;
+ char *value = NULL;
int flags = 0;
+ int ret = 0;
+ struct key_value_info default_kvi = KVI_INIT;
given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
@@ -704,7 +739,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
given_config_source.scope = CONFIG_SCOPE_LOCAL;
} else if (use_worktree_config) {
struct worktree **worktrees = get_worktrees();
- if (repository_format_worktree_config)
+ if (the_repository->repository_format_worktree_config)
given_config_source.file = git_pathdup("config.worktree");
else if (worktrees[0] && worktrees[1])
die(_("--worktree cannot be used with multiple "
@@ -818,7 +853,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
if (config_with_options(show_all_config, NULL,
- &given_config_source,
+ &given_config_source, the_repository,
&config_options) < 0) {
if (given_config_source.file)
die_errno(_("unable to read config file '%s'"),
@@ -856,44 +891,38 @@ int cmd_config(int argc, const char **argv, const char *prefix)
free(config_file);
}
else if (actions == ACTION_SET) {
- int ret;
check_write();
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
+ value = normalize_value(argv[0], argv[1], &default_kvi);
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
- return ret;
}
else if (actions == ACTION_SET_ALL) {
check_write();
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags);
+ value = normalize_value(argv[0], argv[1], &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags);
}
else if (actions == ACTION_ADD) {
check_write();
check_argc(argc, 2, 2);
- value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value,
- CONFIG_REGEX_NONE,
- flags);
+ value = normalize_value(argv[0], argv[1], &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value,
+ CONFIG_REGEX_NONE,
+ flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
check_argc(argc, 2, 3);
- value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ value = normalize_value(argv[0], argv[1], &default_kvi);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -934,26 +963,28 @@ int cmd_config(int argc, const char **argv, const char *prefix)
flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
- int ret;
check_write();
check_argc(argc, 2, 2);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], argv[1]);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_REMOVE_SECTION) {
- int ret;
check_write();
check_argc(argc, 1, 1);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], NULL);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
@@ -966,5 +997,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return get_colorbool(argv[0], argc == 2);
}
- return 0;
+ free(value);
+ return ret;
}
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 07b9419596..2d4bb5e8d0 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -4,15 +4,17 @@
* Copyright (c) 2006 Junio C Hamano
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
#include "repository.h"
-#include "builtin.h"
#include "parse-options.h"
#include "quote.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static unsigned long garbage;
static off_t size_garbage;
@@ -57,7 +59,8 @@ static void loose_garbage(const char *path)
report_garbage(PACKDIR_FILE_GARBAGE, path);
}
-static int count_loose(const struct object_id *oid, const char *path, void *data)
+static int count_loose(const struct object_id *oid, const char *path,
+ void *data UNUSED)
{
struct stat st;
@@ -72,13 +75,14 @@ static int count_loose(const struct object_id *oid, const char *path, void *data
return 0;
}
-static int count_cruft(const char *basename, const char *path, void *data)
+static int count_cruft(const char *basename UNUSED, const char *path,
+ void *data UNUSED)
{
loose_garbage(path);
return 0;
}
-static int print_alternate(struct object_directory *odb, void *data)
+static int print_alternate(struct object_directory *odb, void *data UNUSED)
{
printf("alternate: ");
quote_c_style(odb->path, NULL, stdout, 0);
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 4c6c89ab0d..3a6a750a8e 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,4 +1,7 @@
#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
#ifndef NO_UNIX_SOCKETS
@@ -34,19 +37,22 @@ static struct credential_cache_entry *lookup_credential(const struct credential
int i;
for (i = 0; i < entries_nr; i++) {
struct credential *e = &entries[i].item;
- if (credential_match(c, e))
+ if (credential_match(c, e, 0))
return &entries[i];
}
return NULL;
}
-static void remove_credential(const struct credential *c)
+static void remove_credential(const struct credential *c, int match_password)
{
struct credential_cache_entry *e;
- e = lookup_credential(c);
- if (e)
- e->expiration = 0;
+ int i;
+ for (i = 0; i < entries_nr; i++) {
+ e = &entries[i];
+ if (credential_match(c, &e->item, match_password))
+ e->expiration = 0;
+ }
}
static timestamp_t check_expirations(void)
@@ -127,6 +133,12 @@ static void serve_one_client(FILE *in, FILE *out)
if (e) {
fprintf(out, "username=%s\n", e->item.username);
fprintf(out, "password=%s\n", e->item.password);
+ if (e->item.password_expiry_utc != TIME_MAX)
+ fprintf(out, "password_expiry_utc=%"PRItime"\n",
+ e->item.password_expiry_utc);
+ if (e->item.oauth_refresh_token)
+ fprintf(out, "oauth_refresh_token=%s\n",
+ e->item.oauth_refresh_token);
}
}
else if (!strcmp(action.buf, "exit")) {
@@ -141,14 +153,14 @@ static void serve_one_client(FILE *in, FILE *out)
exit(0);
}
else if (!strcmp(action.buf, "erase"))
- remove_credential(&c);
+ remove_credential(&c, 1);
else if (!strcmp(action.buf, "store")) {
if (timeout < 0)
warning("cache client didn't specify a timeout");
else if (!c.username || !c.password)
warning("cache client gave us a partial credential");
else {
- remove_credential(&c);
+ remove_credential(&c, 0);
cache_credential(&c, timeout);
}
}
@@ -267,7 +279,7 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
const char *socket_path;
int ignore_sighup = 0;
static const char *usage[] = {
- "git-credential-cache--daemon [opts] <socket_path>",
+ "git credential-cache--daemon [--debug] <socket-path>",
NULL
};
int debug = 0;
@@ -305,7 +317,7 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
{
const char * const usage[] = {
- "git credential-cache--daemon [options] <action>",
+ "git credential-cache--daemon [--debug] <socket-path>",
"",
"credential-cache--daemon is disabled in this build of Git",
NULL
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 78c02ad531..bba96d4ffd 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,10 +1,12 @@
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "strbuf.h"
+#include "write-or-die.h"
#ifndef NO_UNIX_SOCKETS
-#include "credential.h"
-#include "string-list.h"
#include "unix-socket.h"
#include "run-command.h"
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 62a4f3c265..4a492411bb 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,16 +1,20 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "lockfile.h"
#include "credential.h"
+#include "path.h"
#include "string-list.h"
#include "parse-options.h"
+#include "write-or-die.h"
static struct lock_file credential_lock;
static int parse_credential_file(const char *fn,
struct credential *c,
void (*match_cb)(struct credential *),
- void (*other_cb)(struct strbuf *))
+ void (*other_cb)(struct strbuf *),
+ int match_password)
{
FILE *fh;
struct strbuf line = STRBUF_INIT;
@@ -27,7 +31,7 @@ static int parse_credential_file(const char *fn,
while (strbuf_getline_lf(&line, fh) != EOF) {
if (!credential_from_url_gently(&entry, line.buf, 1) &&
entry.username && entry.password &&
- credential_match(c, &entry)) {
+ credential_match(c, &entry, match_password)) {
found_credential = 1;
if (match_cb) {
match_cb(&entry);
@@ -57,7 +61,7 @@ static void print_line(struct strbuf *buf)
}
static void rewrite_credential_file(const char *fn, struct credential *c,
- struct strbuf *extra)
+ struct strbuf *extra, int match_password)
{
int timeout_ms = 1000;
@@ -66,11 +70,30 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
if (extra)
print_line(extra);
- parse_credential_file(fn, c, NULL, print_line);
+ parse_credential_file(fn, c, NULL, print_line, match_password);
if (commit_lock_file(&credential_lock) < 0)
die_errno("unable to write credential store");
}
+static int is_rfc3986_unreserved(char ch)
+{
+ return isalnum(ch) ||
+ ch == '-' || ch == '_' || ch == '.' || ch == '~';
+}
+
+static int is_rfc3986_reserved_or_unreserved(char ch)
+{
+ if (is_rfc3986_unreserved(ch))
+ return 1;
+ switch (ch) {
+ case '!': case '*': case '\'': case '(': case ')': case ';':
+ case ':': case '@': case '&': case '=': case '+': case '$':
+ case ',': case '/': case '?': case '#': case '[': case ']':
+ return 1;
+ }
+ return 0;
+}
+
static void store_credential_file(const char *fn, struct credential *c)
{
struct strbuf buf = STRBUF_INIT;
@@ -88,7 +111,7 @@ static void store_credential_file(const char *fn, struct credential *c)
is_rfc3986_reserved_or_unreserved);
}
- rewrite_credential_file(fn, c, &buf);
+ rewrite_credential_file(fn, c, &buf, 0);
strbuf_release(&buf);
}
@@ -135,7 +158,7 @@ static void remove_credential(const struct string_list *fns, struct credential *
return;
for_each_string_list_item(fn, fns)
if (!access(fn->string, F_OK))
- rewrite_credential_file(fn->string, c, NULL);
+ rewrite_credential_file(fn->string, c, NULL, 1);
}
static void lookup_credential(const struct string_list *fns, struct credential *c)
@@ -143,7 +166,7 @@ static void lookup_credential(const struct string_list *fns, struct credential *
struct string_list_item *fn;
for_each_string_list_item(fn, fns)
- if (parse_credential_file(fn->string, c, print_entry, NULL))
+ if (parse_credential_file(fn->string, c, print_entry, NULL, 0))
return; /* Found credential */
}
diff --git a/builtin/credential.c b/builtin/credential.c
index d7b304fa08..7010752987 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -6,7 +6,7 @@
static const char usage_msg[] =
"git credential (fill|approve|reject)";
-int cmd_credential(int argc, const char **argv, const char *prefix)
+int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
{
const char *op;
struct credential c = CREDENTIAL_INIT;
diff --git a/builtin/describe.c b/builtin/describe.c
index e17c4b4c69..d6c77a714f 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,30 +1,36 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "commit.h"
#include "tag.h"
-#include "blob.h"
#include "refs.h"
-#include "builtin.h"
-#include "exec-cmd.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
#include "revision.h"
#include "diff.h"
#include "hashmap.h"
+#include "setup.h"
#include "strvec.h"
#include "run-command.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "list-objects.h"
#include "commit-slab.h"
+#include "wildmatch.h"
#define MAX_TAGS (FLAG_BITS - 1)
+#define DEFAULT_CANDIDATES 10
define_commit_slab(commit_names, struct commit_name *);
static const char * const describe_usage[] = {
- N_("git describe [<options>] [<commit-ish>...]"),
- N_("git describe [<options>] --dirty"),
+ N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"),
+ N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"),
+ N_("git describe <blob>"),
NULL
};
@@ -34,7 +40,7 @@ static int tags; /* Allow lightweight tags */
static int longformat;
static int first_parent;
static int abbrev = -1; /* unspecified */
-static int max_candidates = 10;
+static int max_candidates = DEFAULT_CANDIDATES;
static struct hashmap names;
static int have_util;
static struct string_list patterns = STRING_LIST_INIT_NODUP;
@@ -260,7 +266,7 @@ static unsigned long finish_depth_computation(
best->depth++;
while (parents) {
struct commit *p = parents->item;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
commit_list_insert_by_date(p, list);
p->object.flags |= c->object.flags;
@@ -297,7 +303,8 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
{
- strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev));
+ strbuf_addf(dst, "-%d-g%s", depth,
+ repo_find_unique_abbrev(the_repository, oid, abbrev));
}
static void describe_commit(struct object_id *oid, struct strbuf *dst)
@@ -402,7 +409,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
while (parents) {
struct commit *p = parents->item;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
commit_list_insert_by_date(p, &list);
p->object.flags |= c->object.flags;
@@ -530,7 +537,7 @@ static void describe(const char *arg, int last_one)
if (debug)
fprintf(stderr, _("describe %s\n"), arg);
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die(_("Not a valid object name %s"), arg);
cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
@@ -549,6 +556,17 @@ static void describe(const char *arg, int last_one)
strbuf_release(&sb);
}
+static int option_parse_exact_match(const struct option *opt, const char *arg,
+ int unset)
+{
+ int *val = opt->value;
+
+ BUG_ON_OPT_ARG(arg);
+
+ *val = unset ? DEFAULT_CANDIDATES : 0;
+ return 0;
+}
+
int cmd_describe(int argc, const char **argv, const char *prefix)
{
int contains = 0;
@@ -560,8 +578,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "long", &longformat, N_("always use long format")),
OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
OPT__ABBREV(&abbrev),
- OPT_SET_INT(0, "exact-match", &max_candidates,
- N_("only output exact matches"), 0),
+ OPT_CALLBACK_F(0, "exact-match", &max_candidates, NULL,
+ N_("only output exact matches"),
+ PARSE_OPT_NOARG, option_parse_exact_match),
OPT_INTEGER(0, "candidates", &max_candidates,
N_("consider <n> most recent tags (default: 10)")),
OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
@@ -649,13 +668,16 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
struct lock_file index_lock = LOCK_INIT;
struct rev_info revs;
struct strvec args = STRVEC_INIT;
- int fd, result;
+ int fd;
setup_work_tree();
- read_cache();
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ repo_read_index(the_repository);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
NULL, NULL, NULL);
- fd = hold_locked_index(&index_lock, 0);
+ fd = repo_hold_locked_index(the_repository,
+ &index_lock, 0);
if (0 <= fd)
repo_update_index_if_able(the_repository, &index_lock);
@@ -663,9 +685,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
strvec_pushv(&args, diff_index_args);
if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
BUG("malformed internal diff-index command line");
- result = run_diff_index(&revs, 0);
+ run_diff_index(&revs, 0);
- if (!diff_result_code(&revs.diffopt, result))
+ if (!diff_result_code(&revs.diffopt))
suffix = NULL;
else
suffix = dirty;
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 576e0e8e38..4f22eb2b55 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -1,9 +1,13 @@
#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
#include "diagnose.h"
static const char * const diagnose_usage[] = {
- N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--mode=<mode>]"),
+ N_("git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ " [--mode=<mode>]"),
NULL
};
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 92cf6e1e92..018011f29e 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -3,18 +3,18 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "diff-merges.h"
#include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
#include "revision.h"
-#include "builtin.h"
-#include "submodule.h"
static const char diff_files_usage[] =
"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_files(int argc, const char **argv, const char *prefix)
@@ -27,6 +27,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
usage(diff_files_usage);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
@@ -75,14 +79,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
diff_merges_set_dense_combined_if_unset(&rev);
- if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
- perror("read_cache_preload");
- result = -1;
- goto cleanup;
- }
- result = run_diff_files(&rev, options);
- result = diff_result_code(&rev.diffopt, result);
-cleanup:
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
+ die_errno("repo_read_index_preload");
+ run_diff_files(&rev, options);
+ result = diff_result_code(&rev.diffopt);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 7d158af6b6..3e05260ac0 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -1,16 +1,17 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "diff-merges.h"
#include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
#include "revision.h"
-#include "builtin.h"
-#include "submodule.h"
+#include "setup.h"
static const char diff_cache_usage[] =
-"git diff-index [-m] [--cached] "
+"git diff-index [-m] [--cached] [--merge-base] "
"[<common-diff-options>] <tree-ish> [<path>...]"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_index(int argc, const char **argv, const char *prefix)
@@ -61,16 +62,16 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
usage(diff_cache_usage);
if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
- if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
- perror("read_cache_preload");
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
+ perror("repo_read_index_preload");
return -1;
}
- } else if (read_cache() < 0) {
- perror("read_cache");
+ } else if (repo_read_index(the_repository) < 0) {
+ perror("repo_read_index");
return -1;
}
- result = run_diff_index(&rev, option);
- result = diff_result_code(&rev.diffopt, result);
+ run_diff_index(&rev, option);
+ result = diff_result_code(&rev.diffopt);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 116097a404..a8e68ce8ef 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -1,12 +1,15 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
#include "config.h"
#include "diff.h"
#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
#include "log-tree.h"
-#include "builtin.h"
-#include "submodule.h"
+#include "read-cache-ll.h"
#include "repository.h"
+#include "revision.h"
+#include "tree.h"
static struct rev_info log_tree_opt;
@@ -83,8 +86,10 @@ static int diff_tree_stdin(char *line)
}
static const char diff_tree_usage[] =
-"git diff-tree [--stdin] [-m] [-c | --cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"git diff-tree [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]\n"
+" [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]\n"
+" [<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"\n"
" -r diff recursively\n"
" -c show combined diff for merge commits\n"
" --cc show combined diff for merge commits removing uninteresting hunks\n"
@@ -93,7 +98,7 @@ static const char diff_tree_usage[] =
" --root include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;
-static void diff_tree_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
+static void diff_tree_tweak_rev(struct rev_info *rev)
{
if (!rev->diffopt.output_format) {
if (rev->dense_combined_merges)
@@ -117,8 +122,12 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
usage(diff_tree_usage);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
repo_init_revisions(the_repository, opt, prefix);
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
opt->abbrev = 0;
opt->diff = 1;
@@ -222,5 +231,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff_free(&opt->diffopt);
}
- return diff_result_code(&opt->diffopt, 0);
+ return diff_result_code(&opt->diffopt);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 54bb3de964..6e196e0c7d 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -3,23 +3,25 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
#include "config.h"
#include "ewah/ewok.h"
#include "lockfile.h"
#include "color.h"
#include "commit.h"
-#include "blob.h"
+#include "gettext.h"
#include "tag.h"
#include "diff.h"
#include "diff-merges.h"
#include "diffcore.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
#include "revision.h"
#include "log-tree.h"
-#include "builtin.h"
-#include "submodule.h"
+#include "setup.h"
#include "oid-array.h"
+#include "tree.h"
#define DIFF_NO_INDEX_EXPLICIT 1
#define DIFF_NO_INDEX_IMPLICIT 2
@@ -30,7 +32,8 @@ static const char builtin_diff_usage[] =
" or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
" or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n"
" or: git diff [<options>] <blob> <blob>\n"
-" or: git diff [<options>] --no-index [--] <path> <path>\n"
+" or: git diff [<options>] --no-index [--] <path> <path>"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
static const char *blob_path(struct object_array_entry *entry)
@@ -72,9 +75,9 @@ static void stuff_change(struct diff_options *opt,
diff_queue(&diff_queued_diff, one, two);
}
-static int builtin_diff_b_f(struct rev_info *revs,
- int argc, const char **argv,
- struct object_array_entry **blob)
+static void builtin_diff_b_f(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry **blob)
{
/* Blob vs file in the working tree*/
struct stat st;
@@ -104,12 +107,11 @@ static int builtin_diff_b_f(struct rev_info *revs,
path);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
- return 0;
}
-static int builtin_diff_blobs(struct rev_info *revs,
- int argc, const char **argv,
- struct object_array_entry **blob)
+static void builtin_diff_blobs(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry **blob)
{
const unsigned mode = canon_mode(S_IFREG | 0644);
@@ -129,11 +131,10 @@ static int builtin_diff_blobs(struct rev_info *revs,
blob_path(blob[0]), blob_path(blob[1]));
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
- return 0;
}
-static int builtin_diff_index(struct rev_info *revs,
- int argc, const char **argv)
+static void builtin_diff_index(struct rev_info *revs,
+ int argc, const char **argv)
{
unsigned int option = 0;
while (1 < argc) {
@@ -156,21 +157,20 @@ static int builtin_diff_index(struct rev_info *revs,
usage(builtin_diff_usage);
if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
- if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
- perror("read_cache_preload");
- return -1;
+ if (repo_read_index_preload(the_repository,
+ &revs->diffopt.pathspec, 0) < 0) {
+ die_errno("repo_read_index_preload");
}
- } else if (read_cache() < 0) {
- perror("read_cache");
- return -1;
+ } else if (repo_read_index(the_repository) < 0) {
+ die_errno("repo_read_cache");
}
- return run_diff_index(revs, option);
+ run_diff_index(revs, option);
}
-static int builtin_diff_tree(struct rev_info *revs,
- int argc, const char **argv,
- struct object_array_entry *ent0,
- struct object_array_entry *ent1)
+static void builtin_diff_tree(struct rev_info *revs,
+ int argc, const char **argv,
+ struct object_array_entry *ent0,
+ struct object_array_entry *ent1)
{
const struct object_id *(oid[2]);
struct object_id mb_oid;
@@ -203,13 +203,12 @@ static int builtin_diff_tree(struct rev_info *revs,
}
diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
- return 0;
}
-static int builtin_diff_combined(struct rev_info *revs,
- int argc, const char **argv,
- struct object_array_entry *ent,
- int ents)
+static void builtin_diff_combined(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry *ent,
+ int ents, int first_non_parent)
{
struct oid_array parents = OID_ARRAY_INIT;
int i;
@@ -217,13 +216,19 @@ static int builtin_diff_combined(struct rev_info *revs,
if (argc > 1)
usage(builtin_diff_usage);
+ if (first_non_parent < 0)
+ die(_("no merge given, only parents."));
+ if (first_non_parent >= ents)
+ BUG("first_non_parent out of range: %d", first_non_parent);
+
diff_merges_set_dense_combined_if_unset(revs);
- for (i = 1; i < ents; i++)
- oid_array_append(&parents, &ent[i].item->oid);
- diff_tree_combined(&ent[0].item->oid, &parents, revs);
+ for (i = 0; i < ents; i++) {
+ if (i != first_non_parent)
+ oid_array_append(&parents, &ent[i].item->oid);
+ }
+ diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
oid_array_clear(&parents);
- return 0;
}
static void refresh_index_quietly(void)
@@ -231,16 +236,17 @@ static void refresh_index_quietly(void)
struct lock_file lock_file = LOCK_INIT;
int fd;
- fd = hold_locked_index(&lock_file, 0);
+ fd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (fd < 0)
return;
- discard_cache();
- read_cache();
- refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
+ discard_index(&the_index);
+ repo_read_index(the_repository);
+ refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
+ NULL);
repo_update_index_if_able(the_repository, &lock_file);
}
-static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+static void builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
{
unsigned int options = 0;
@@ -255,8 +261,10 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
options |= DIFF_SILENT_ON_REMOVED;
else if (!strcmp(argv[1], "-h"))
usage(builtin_diff_usage);
- else
- return error(_("invalid option: %s"), argv[1]);
+ else {
+ error(_("invalid option: %s"), argv[1]);
+ usage(builtin_diff_usage);
+ }
argv++; argc--;
}
@@ -271,11 +279,11 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
diff_merges_set_dense_combined_if_unset(revs);
setup_work_tree();
- if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
- perror("read_cache_preload");
- return -1;
+ if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
+ 0) < 0) {
+ die_errno("repo_read_index_preload");
}
- return run_diff_files(revs, options);
+ run_diff_files(revs, options);
}
struct symdiff {
@@ -385,10 +393,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
int i;
struct rev_info rev;
struct object_array ent = OBJECT_ARRAY_INIT;
+ int first_non_parent = -1;
int blobs = 0, paths = 0;
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
- int result = 0;
+ int result;
struct symdiff sdiff;
/*
@@ -463,8 +472,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &rev, prefix);
/* Set up defaults that will apply to both no-index and regular diffs. */
- rev.diffopt.stat_width = -1;
- rev.diffopt.stat_graph_width = -1;
+ init_diffstat_widths(&rev.diffopt);
rev.diffopt.flags.allow_external = 1;
rev.diffopt.flags.allow_textconv = 1;
@@ -536,13 +544,18 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
- obj = &get_commit_tree(((struct commit *)obj))->object;
+ obj = &repo_get_commit_tree(the_repository,
+ ((struct commit *)obj))->object;
if (obj->type == OBJ_TREE) {
if (sdiff.skip && bitmap_get(sdiff.skip, i))
continue;
obj->flags |= flags;
add_object_array(obj, name, &ent);
+ if (first_non_parent < 0 &&
+ (i >= rev.cmdline.nr || /* HEAD by hand. */
+ rev.cmdline.rev[i].whence != REV_CMD_PARENTS_ONLY))
+ first_non_parent = ent.nr - 1;
} else if (obj->type == OBJ_BLOB) {
if (2 <= blobs)
die(_("more than two blobs given: '%s'"), name);
@@ -562,17 +575,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!ent.nr) {
switch (blobs) {
case 0:
- result = builtin_diff_files(&rev, argc, argv);
+ builtin_diff_files(&rev, argc, argv);
break;
case 1:
if (paths != 1)
usage(builtin_diff_usage);
- result = builtin_diff_b_f(&rev, argc, argv, blob);
+ builtin_diff_b_f(&rev, argc, argv, blob);
break;
case 2:
if (paths)
usage(builtin_diff_usage);
- result = builtin_diff_blobs(&rev, argc, argv, blob);
+ builtin_diff_blobs(&rev, argc, argv, blob);
break;
default:
usage(builtin_diff_usage);
@@ -581,21 +594,22 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
else if (blobs)
usage(builtin_diff_usage);
else if (ent.nr == 1)
- result = builtin_diff_index(&rev, argc, argv);
+ builtin_diff_index(&rev, argc, argv);
else if (ent.nr == 2) {
if (sdiff.warn)
warning(_("%s...%s: multiple merge bases, using %s"),
sdiff.left, sdiff.right, sdiff.base);
- result = builtin_diff_tree(&rev, argc, argv,
- &ent.objects[0], &ent.objects[1]);
+ builtin_diff_tree(&rev, argc, argv,
+ &ent.objects[0], &ent.objects[1]);
} else
- result = builtin_diff_combined(&rev, argc, argv,
- ent.objects, ent.nr);
- result = diff_result_code(&rev.diffopt, result);
+ builtin_diff_combined(&rev, argc, argv,
+ ent.objects, ent.nr,
+ first_non_parent);
+ result = diff_result_code(&rev.diffopt);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
release_revisions(&rev);
- UNLEAK(ent);
+ object_array_clear(&ent);
UNLEAK(blob);
return result;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 4b10ad1a36..a3c72b8258 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -11,19 +11,26 @@
*
* Copyright (C) 2016 Johannes Schindelin
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
-#include "config.h"
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "copy.h"
#include "run-command.h"
-#include "exec-cmd.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "sparse-index.h"
#include "strvec.h"
#include "strbuf.h"
#include "lockfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "dir.h"
#include "entry.h"
+#include "setup.h"
static int trust_exit_code;
@@ -32,20 +39,24 @@ static const char *const builtin_difftool_usage[] = {
NULL
};
-static int difftool_config(const char *var, const char *value, void *cb)
+static int difftool_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "difftool.trustexitcode")) {
trust_exit_code = git_config_bool(var, value);
return 0;
}
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static int print_tool_help(void)
{
- const char *argv[] = { "mergetool", "--tool-help=diff", NULL };
- return run_command_v_opt(argv, RUN_GIT_CMD);
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ cmd.git_cmd = 1;
+ strvec_pushl(&cmd.args, "mergetool", "--tool-help=diff", NULL);
+ return run_command(&cmd);
}
static int parse_index_info(char *p, int *mode1, int *mode2,
@@ -292,7 +303,8 @@ static char *get_symlink(const struct object_id *oid, const char *path)
} else {
enum object_type type;
unsigned long size;
- data = read_object_file(oid, &type, &size);
+ data = repo_read_object_file(the_repository, oid, &type,
+ &size);
if (!data)
die(_("could not read object %s for symlink %s"),
oid_to_hex(oid), path);
@@ -358,10 +370,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL);
struct hashmap_iter iter;
struct pair_entry *entry;
- struct index_state wtindex;
+ struct index_state wtindex = INDEX_STATE_INIT(the_repository);
struct checkout lstate, rstate;
- int flags = RUN_GIT_CMD, err = 0;
- const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
+ int err = 0;
+ struct child_process cmd = CHILD_PROCESS_INIT;
struct hashmap wt_modified, tmp_modified;
int indices_loaded = 0;
@@ -384,8 +396,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
mkdir(ldir.buf, 0700);
mkdir(rdir.buf, 0700);
- memset(&wtindex, 0, sizeof(wtindex));
-
memset(&lstate, 0, sizeof(lstate));
lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
lstate.base_dir_len = ldir.len;
@@ -563,16 +573,17 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
}
strbuf_setlen(&ldir, ldir_len);
- helper_argv[1] = ldir.buf;
strbuf_setlen(&rdir, rdir_len);
- helper_argv[2] = rdir.buf;
if (extcmd) {
- helper_argv[0] = extcmd;
- flags = 0;
- } else
+ strvec_push(&cmd.args, extcmd);
+ } else {
+ strvec_push(&cmd.args, "difftool--helper");
+ cmd.git_cmd = 1;
setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
- ret = run_command_v_opt(helper_argv, flags);
+ }
+ strvec_pushl(&cmd.args, ldir.buf, rdir.buf, NULL);
+ ret = run_command(&cmd);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&wtindex);
@@ -682,7 +693,7 @@ static int run_file_diff(int prompt, const char *prefix,
int cmd_difftool(int argc, const char **argv, const char *prefix)
{
- int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
+ int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
tool_help = 0, no_index = 0;
static char *difftool_cmd = NULL, *extcmd = NULL;
struct option builtin_difftool_options[] = {
@@ -732,13 +743,21 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
} else if (dir_diff)
die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
- die_for_incompatible_opt3(use_gui_tool, "--gui",
+ die_for_incompatible_opt3(use_gui_tool == 1, "--gui",
!!difftool_cmd, "--tool",
!!extcmd, "--extcmd");
- if (use_gui_tool)
+ /*
+ * Explicitly specified GUI option is forwarded to git-mergetool--lib.sh;
+ * empty or unset means "use the difftool.guiDefault config or default to
+ * false".
+ */
+ if (use_gui_tool == 1)
setenv("GIT_MERGETOOL_GUI", "true", 1);
- else if (difftool_cmd) {
+ else if (use_gui_tool == 0)
+ setenv("GIT_MERGETOOL_GUI", "false", 1);
+
+ if (difftool_cmd) {
if (*difftool_cmd)
setenv("GIT_DIFF_TOOL", difftool_cmd, 1);
else
diff --git a/builtin/env--helper.c b/builtin/env--helper.c
deleted file mode 100644
index ea04c16636..0000000000
--- a/builtin/env--helper.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "builtin.h"
-#include "config.h"
-#include "parse-options.h"
-
-static char const * const env__helper_usage[] = {
- N_("git env--helper --type=[bool|ulong] <options> <env-var>"),
- NULL
-};
-
-enum cmdmode {
- ENV_HELPER_TYPE_BOOL = 1,
- ENV_HELPER_TYPE_ULONG
-};
-
-static int option_parse_type(const struct option *opt, const char *arg,
- int unset)
-{
- enum cmdmode *cmdmode = opt->value;
-
- BUG_ON_OPT_NEG(unset);
-
- if (!strcmp(arg, "bool"))
- *cmdmode = ENV_HELPER_TYPE_BOOL;
- else if (!strcmp(arg, "ulong"))
- *cmdmode = ENV_HELPER_TYPE_ULONG;
- else
- die(_("unrecognized --type argument, %s"), arg);
-
- return 0;
-}
-
-int cmd_env__helper(int argc, const char **argv, const char *prefix)
-{
- int exit_code = 0;
- const char *env_variable = NULL;
- const char *env_default = NULL;
- int ret;
- int ret_int, default_int;
- unsigned long ret_ulong, default_ulong;
- enum cmdmode cmdmode = 0;
- struct option opts[] = {
- OPT_CALLBACK_F(0, "type", &cmdmode, N_("type"),
- N_("value is given this type"), PARSE_OPT_NONEG,
- option_parse_type),
- OPT_STRING(0, "default", &env_default, N_("value"),
- N_("default for git_env_*(...) to fall back on")),
- OPT_BOOL(0, "exit-code", &exit_code,
- N_("be quiet only use git_env_*() value as exit code")),
- OPT_END(),
- };
-
- argc = parse_options(argc, argv, prefix, opts, env__helper_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
- if (env_default && !*env_default)
- usage_with_options(env__helper_usage, opts);
- if (!cmdmode)
- usage_with_options(env__helper_usage, opts);
- if (argc != 1)
- usage_with_options(env__helper_usage, opts);
- env_variable = argv[0];
-
- switch (cmdmode) {
- case ENV_HELPER_TYPE_BOOL:
- if (env_default) {
- default_int = git_parse_maybe_bool(env_default);
- if (default_int == -1) {
- error(_("option `--default' expects a boolean value with `--type=bool`, not `%s`"),
- env_default);
- usage_with_options(env__helper_usage, opts);
- }
- } else {
- default_int = 0;
- }
- ret_int = git_env_bool(env_variable, default_int);
- if (!exit_code)
- puts(ret_int ? "true" : "false");
- ret = ret_int;
- break;
- case ENV_HELPER_TYPE_ULONG:
- if (env_default) {
- if (!git_parse_ulong(env_default, &default_ulong)) {
- error(_("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`"),
- env_default);
- usage_with_options(env__helper_usage, opts);
- }
- } else {
- default_ulong = 0;
- }
- ret_ulong = git_env_ulong(env_variable, default_ulong);
- if (!exit_code)
- printf("%lu\n", ret_ulong);
- ret = ret_ulong;
- break;
- default:
- BUG("unknown <type> value");
- break;
- }
-
- return !ret;
-}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 3b3314e7b2..f18f0809f9 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -4,11 +4,13 @@
* Copyright (C) 2007 Johannes E. Schindelin
*/
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -23,7 +25,6 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
-#include "commit-slab.h"
static const char *fast_export_usage[] = {
N_("git fast-export [<rev-list-opts>]"),
@@ -31,9 +32,9 @@ static const char *fast_export_usage[] = {
};
static int progress;
-static enum { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
-static enum { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
-static enum { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
+static enum signed_tag_mode { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum tag_of_filtered_mode { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
+static enum reencode_mode { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
static int fake_missing_tagger;
static int use_done_feature;
static int no_data;
@@ -51,16 +52,18 @@ static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum signed_tag_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- signed_tag_mode = SIGNED_TAG_ABORT;
+ *val = SIGNED_TAG_ABORT;
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
- signed_tag_mode = VERBATIM;
+ *val = VERBATIM;
else if (!strcmp(arg, "warn"))
- signed_tag_mode = WARN;
+ *val = WARN;
else if (!strcmp(arg, "warn-strip"))
- signed_tag_mode = WARN_STRIP;
+ *val = WARN_STRIP;
else if (!strcmp(arg, "strip"))
- signed_tag_mode = STRIP;
+ *val = STRIP;
else
return error("Unknown signed-tags mode: %s", arg);
return 0;
@@ -69,12 +72,14 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum tag_of_filtered_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- tag_of_filtered_mode = TAG_FILTERING_ABORT;
+ *val = TAG_FILTERING_ABORT;
else if (!strcmp(arg, "drop"))
- tag_of_filtered_mode = DROP;
+ *val = DROP;
else if (!strcmp(arg, "rewrite"))
- tag_of_filtered_mode = REWRITE;
+ *val = REWRITE;
else
return error("Unknown tag-of-filtered mode: %s", arg);
return 0;
@@ -83,21 +88,23 @@ static int parse_opt_tag_of_filtered_mode(const struct option *opt,
static int parse_opt_reencode_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum reencode_mode *val = opt->value;
+
if (unset) {
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
return 0;
}
switch (git_parse_maybe_bool(arg)) {
case 0:
- reencode_mode = REENCODE_NO;
+ *val = REENCODE_NO;
break;
case 1:
- reencode_mode = REENCODE_YES;
+ *val = REENCODE_YES;
break;
default:
if (!strcasecmp(arg, "abort"))
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
else
return error("Unknown reencoding mode: %s", arg);
}
@@ -109,7 +116,7 @@ static struct decoration idnums;
static uint32_t last_idnum;
struct anonymized_entry {
struct hashmap_entry hash;
- const char *anon;
+ char *anon;
const char orig[FLEX_ARRAY];
};
@@ -138,43 +145,56 @@ static int anonymized_entry_cmp(const void *cmp_data UNUSED,
return strcmp(a->orig, b->orig);
}
+static struct anonymized_entry *add_anonymized_entry(struct hashmap *map,
+ unsigned hash,
+ const char *orig, size_t len,
+ char *anon)
+{
+ struct anonymized_entry *ret, *old;
+
+ if (!map->cmpfn)
+ hashmap_init(map, anonymized_entry_cmp, NULL, 0);
+
+ FLEX_ALLOC_MEM(ret, orig, orig, len);
+ hashmap_entry_init(&ret->hash, hash);
+ ret->anon = anon;
+ old = hashmap_put_entry(map, ret, hash);
+
+ if (old) {
+ free(old->anon);
+ free(old);
+ }
+
+ return ret;
+}
+
/*
* Basically keep a cache of X->Y so that we can repeatedly replace
* the same anonymized string with another. The actual generation
* is farmed out to the generate function.
*/
static const char *anonymize_str(struct hashmap *map,
- char *(*generate)(void *),
- const char *orig, size_t len,
- void *data)
+ char *(*generate)(void),
+ const char *orig, size_t len)
{
struct anonymized_entry_key key;
struct anonymized_entry *ret;
- if (!map->cmpfn)
- hashmap_init(map, anonymized_entry_cmp, NULL, 0);
-
hashmap_entry_init(&key.hash, memhash(orig, len));
key.orig = orig;
key.orig_len = len;
/* First check if it's a token the user configured manually... */
- if (anonymized_seeds.cmpfn)
- ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
- else
- ret = NULL;
+ ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
/* ...otherwise check if we've already seen it in this context... */
if (!ret)
ret = hashmap_get_entry(map, &key, hash, &key);
/* ...and finally generate a new mapping if necessary */
- if (!ret) {
- FLEX_ALLOC_MEM(ret, orig, orig, len);
- hashmap_entry_init(&ret->hash, key.hash.hash);
- ret->anon = generate(data);
- hashmap_put(map, &ret->hash);
- }
+ if (!ret)
+ ret = add_anonymized_entry(map, key.hash.hash,
+ orig, len, generate());
return ret->anon;
}
@@ -187,12 +207,12 @@ static const char *anonymize_str(struct hashmap *map,
*/
static void anonymize_path(struct strbuf *out, const char *path,
struct hashmap *map,
- char *(*generate)(void *))
+ char *(*generate)(void))
{
while (*path) {
const char *end_of_component = strchrnul(path, '/');
size_t len = end_of_component - path;
- const char *c = anonymize_str(map, generate, path, len, NULL);
+ const char *c = anonymize_str(map, generate, path, len);
strbuf_addstr(out, c);
path = end_of_component;
if (*path)
@@ -296,7 +316,7 @@ static void export_blob(const struct object_id *oid)
object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0;
} else {
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
@@ -367,7 +387,7 @@ static void print_path_1(const char *path)
printf("%s", path);
}
-static char *anonymize_path_component(void *data)
+static char *anonymize_path_component(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -389,7 +409,7 @@ static void print_path(const char *path)
}
}
-static char *generate_fake_oid(void *data)
+static char *generate_fake_oid(void)
{
static uint32_t counter = 1; /* avoid null oid */
const unsigned hashsz = the_hash_algo->rawsz;
@@ -405,11 +425,11 @@ static const char *anonymize_oid(const char *oid_hex)
{
static struct hashmap objs;
size_t len = strlen(oid_hex);
- return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
+ return anonymize_str(&objs, generate_fake_oid, oid_hex, len);
}
static void show_filemodify(struct diff_queue_struct *q,
- struct diff_options *options, void *data)
+ struct diff_options *options UNUSED, void *data)
{
int i;
struct string_list *changed = data;
@@ -502,7 +522,7 @@ static const char *find_encoding(const char *begin, const char *end)
return bol;
}
-static char *anonymize_ref_component(void *data)
+static char *anonymize_ref_component(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -542,13 +562,13 @@ static const char *anonymize_refname(const char *refname)
* We do not even bother to cache commit messages, as they are unlikely
* to be repeated verbatim, and it is not that interesting when they are.
*/
-static char *anonymize_commit_message(const char *old)
+static char *anonymize_commit_message(void)
{
static int counter;
return xstrfmt("subject %d\n\nbody\n", counter++);
}
-static char *anonymize_ident(void *data)
+static char *anonymize_ident(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -591,7 +611,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
len = split.mail_end - split.name_begin;
ident = anonymize_str(&idents, anonymize_ident,
- split.name_begin, len, NULL);
+ split.name_begin, len);
strbuf_addstr(out, ident);
strbuf_addch(out, ' ');
strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
@@ -618,7 +638,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
parse_commit_or_die(commit);
- commit_buffer = get_commit_buffer(commit, NULL);
+ commit_buffer = repo_get_commit_buffer(the_repository, commit, NULL);
author = strstr(commit_buffer, "\nauthor ");
if (!author)
die("could not find author in commit %s",
@@ -669,7 +689,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
mark_next_object(&commit->object);
if (anonymize) {
- reencoded = anonymize_commit_message(message);
+ reencoded = anonymize_commit_message();
} else if (encoding) {
switch(reencode_mode) {
case REENCODE_YES:
@@ -699,7 +719,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
? strlen(message) : 0),
reencoded ? reencoded : message ? message : "");
free(reencoded);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
for (i = 0, p = commit->parents; p; p = p->next) {
struct object *obj = &p->item->object;
@@ -732,7 +752,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
show_progress();
}
-static char *anonymize_tag(void *data)
+static char *anonymize_tag(void)
{
static int counter;
struct strbuf out = STRBUF_INIT;
@@ -766,7 +786,8 @@ static void handle_tag(const char *name, struct tag *tag)
return;
}
- buf = read_object_file(&tag->object.oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &tag->object.oid, &type,
+ &size);
if (!buf)
die("could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2);
@@ -794,7 +815,7 @@ static void handle_tag(const char *name, struct tag *tag)
if (message) {
static struct hashmap tags;
message = anonymize_str(&tags, anonymize_tag,
- message, message_size, NULL);
+ message, message_size);
message_size = strlen(message);
}
}
@@ -917,7 +938,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), &oid, &full_name, 0) != 1)
+ if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+ &oid, &full_name, 0) != 1)
continue;
if (refspecs.nr) {
@@ -1125,11 +1147,6 @@ static void handle_deletes(void)
}
}
-static char *anonymize_seed(void *data)
-{
- return xstrdup(data);
-}
-
static int parse_opt_anonymize_map(const struct option *opt,
const char *arg, int unset)
{
@@ -1151,7 +1168,8 @@ static int parse_opt_anonymize_map(const struct option *opt,
if (!keylen || !*value)
return error(_("--anonymize-map token cannot be empty"));
- anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+ add_anonymized_entry(map, memhash(arg, keylen), arg, keylen,
+ xstrdup(value));
return 0;
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 7134683ab9..92eda20683 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1,5 +1,8 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "lockfile.h"
@@ -9,13 +12,16 @@
#include "commit.h"
#include "delta.h"
#include "pack.h"
+#include "path.h"
#include "refs.h"
#include "csum-file.h"
#include "quote.h"
#include "dir.h"
#include "run-command.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "mem-pool.h"
#include "commit-reach.h"
#include "khash.h"
@@ -175,6 +181,7 @@ static FILE *pack_edges;
static unsigned int show_stats = 1;
static int global_argc;
static const char **global_argv;
+static const char *global_prefix;
/* Memory pools */
static struct mem_pool fi_mem_pool = {
@@ -436,7 +443,7 @@ static void set_checkpoint_signal(void)
#else
-static void checkpoint_signal(int signo)
+static void checkpoint_signal(int signo UNUSED)
{
checkpoint_requested = 1;
}
@@ -1095,6 +1102,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
cycle_packfile();
+ the_hash_algo->init_fn(&checkpoint.ctx);
hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
@@ -1265,7 +1273,7 @@ static void load_tree(struct tree_entry *root)
die("Can't load tree %s", oid_to_hex(oid));
} else {
enum object_type type;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf || type != OBJ_TREE)
die("Can't load tree %s", oid_to_hex(oid));
}
@@ -1625,7 +1633,7 @@ static int update_branch(struct branch *b)
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
- if (!in_merge_bases(old_cmit, new_cmit)) {
+ if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, oid_to_hex(&b->oid),
@@ -2486,7 +2494,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
if (commit_oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", commit_mark);
oidcpy(&commit_oid, &commit_oe->idx.oid);
- } else if (!get_oid(p, &commit_oid)) {
+ } else if (!repo_get_oid(the_repository, p, &commit_oid)) {
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&commit_oid,
@@ -2599,7 +2607,7 @@ static int parse_objectish(struct branch *b, const char *objectish)
} else
parse_from_existing(b);
}
- } else if (!get_oid(objectish, &b->oid)) {
+ } else if (!repo_get_oid(the_repository, objectish, &b->oid)) {
parse_from_existing(b);
if (is_null_oid(&b->oid))
b->delete = 1;
@@ -2654,7 +2662,7 @@ static struct hash_list *parse_merge(unsigned int *count)
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
oidcpy(&n->oid, &oe->idx.oid);
- } else if (!get_oid(from, &n->oid)) {
+ } else if (!repo_get_oid(the_repository, from, &n->oid)) {
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&n->oid,
@@ -2801,8 +2809,7 @@ static void parse_new_tag(const char *arg)
enum object_type type;
const char *v;
- t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
- memset(t, 0, sizeof(struct tag));
+ t = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct tag));
t->name = mem_pool_strdup(&fi_mem_pool, arg);
if (last_tag)
last_tag->next_tag = t;
@@ -2827,7 +2834,7 @@ static void parse_new_tag(const char *arg)
oe = find_mark(marks, from_mark);
type = oe->type;
oidcpy(&oid, &oe->idx.oid);
- } else if (!get_oid(from, &oid)) {
+ } else if (!repo_get_oid(the_repository, from, &oid)) {
struct object_entry *oe = find_object(&oid);
if (!oe) {
type = oid_object_info(the_repository, &oid, NULL);
@@ -2936,7 +2943,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
char *buf;
if (!oe || oe->pack_id == MAX_PACK_ID) {
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
} else {
type = oe->type;
buf = gfi_unpack_entry(oe, &size);
@@ -3044,7 +3051,8 @@ static struct object_entry *dereference(struct object_entry *oe,
buf = gfi_unpack_entry(oe, &size);
} else {
enum object_type unused;
- buf = read_object_file(oid, &unused, &size);
+ buf = repo_read_object_file(the_repository, oid, &unused,
+ &size);
}
if (!buf)
die("Can't load object %s", oid_to_hex(oid));
@@ -3245,7 +3253,7 @@ static void parse_alias(void)
static char* make_fast_import_path(const char *path)
{
if (!relative_marks_paths || is_absolute_path(path))
- return xstrdup(path);
+ return prefix_filename(global_prefix, path);
return git_pathdup("info/fast-import/%s", path);
}
@@ -3316,9 +3324,11 @@ static void option_cat_blob_fd(const char *fd)
static void option_export_pack_edges(const char *edges)
{
+ char *fn = prefix_filename(global_prefix, edges);
if (pack_edges)
fclose(pack_edges);
- pack_edges = xfopen(edges, "a");
+ pack_edges = xfopen(fn, "a");
+ free(fn);
}
static void option_rewrite_submodules(const char *arg, struct string_list *list)
@@ -3333,11 +3343,13 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
f++;
CALLOC_ARRAY(ms, 1);
+ f = prefix_filename(global_prefix, f);
fp = fopen(f, "r");
if (!fp)
die_errno("cannot read '%s'", f);
read_mark_file(&ms, fp, insert_oid_entry);
fclose(fp);
+ free(f);
string_list_insert(list, s)->util = ms;
}
@@ -3551,6 +3563,7 @@ int cmd_fast_import(int argc, const char **argv, const char *prefix)
global_argc = argc;
global_argv = argv;
+ global_prefix = prefix;
rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
for (i = 0; i < (cmd_save - 1); i++)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index afe679368d..44c05ee86c 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,4 +1,7 @@
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
#include "pkt-line.h"
#include "fetch-pack.h"
#include "remote.h"
@@ -40,7 +43,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
(*sought)[*nr - 1] = ref;
}
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
{
int i, ret;
struct ref *ref = NULL;
@@ -211,8 +214,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
int flags = args.verbose ? CONNECT_VERBOSE : 0;
if (args.diag_url)
flags |= CONNECT_DIAG_URL;
- conn = git_connect(fd, dest, args.uploadpack,
- flags);
+ conn = git_connect(fd, dest, "git-upload-pack",
+ args.uploadpack, flags);
if (!conn)
return args.diag_url ? 0 : 1;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index a0fca93bb6..119f1a72ac 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1,15 +1,20 @@
/*
* "git fetch"
*/
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "gettext.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "oidset.h"
+#include "oid-array.h"
#include "commit.h"
-#include "builtin.h"
#include "string-list.h"
#include "remote.h"
#include "transport.h"
@@ -21,14 +26,18 @@
#include "connected.h"
#include "strvec.h"
#include "utf8.h"
-#include "packfile.h"
+#include "pager.h"
+#include "path.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
#include "shallow.h"
-#include "worktree.h"
+#include "trace.h"
+#include "trace2.h"
+#include "bundle-uri.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -46,25 +55,35 @@ enum {
TAGS_SET = 2
};
-static int fetch_prune_config = -1; /* unspecified */
-static int fetch_show_forced_updates = 1;
+enum display_format {
+ DISPLAY_FORMAT_FULL,
+ DISPLAY_FORMAT_COMPACT,
+ DISPLAY_FORMAT_PORCELAIN,
+};
+
+struct display_state {
+ struct strbuf buf;
+
+ int refcol_width;
+ enum display_format format;
+
+ char *url;
+ int url_len, shown_url;
+};
+
static uint64_t forced_updates_ms = 0;
static int prefetch = 0;
static int prune = -1; /* unspecified */
#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
-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 append, dry_run, force, keep, update_head_ok;
static int write_fetch_head = 1;
static int verbosity, deepen_relative, set_upstream, refetch;
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 tags = TAGS_DEFAULT, update_shallow, deepen;
static int atomic_fetch;
static enum transport_family family;
static const char *depth;
@@ -74,58 +93,77 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *gtransport;
static struct transport *gsecondary;
-static const char *submodule_prefix = "";
-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
-static int shown_url = 0;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
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 stdin_refspecs = 0;
-static int negotiate_only;
-static int git_fetch_config(const char *k, const char *v, void *cb)
+struct fetch_config {
+ enum display_format display_format;
+ int prune;
+ int prune_tags;
+ int show_forced_updates;
+ int recurse_submodules;
+ int parallel;
+ int submodule_fetch_jobs;
+};
+
+static int git_fetch_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
+ struct fetch_config *fetch_config = cb;
+
if (!strcmp(k, "fetch.prune")) {
- fetch_prune_config = git_config_bool(k, v);
+ fetch_config->prune = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "fetch.prunetags")) {
- fetch_prune_tags_config = git_config_bool(k, v);
+ fetch_config->prune_tags = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "fetch.showforcedupdates")) {
- fetch_show_forced_updates = git_config_bool(k, v);
+ fetch_config->show_forced_updates = git_config_bool(k, v);
return 0;
}
if (!strcmp(k, "submodule.recurse")) {
int r = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
- recurse_submodules = r;
+ fetch_config->recurse_submodules = r;
}
if (!strcmp(k, "submodule.fetchjobs")) {
- submodule_fetch_jobs_config = parse_submodule_fetchjobs(k, v);
+ fetch_config->submodule_fetch_jobs = parse_submodule_fetchjobs(k, v, ctx->kvi);
return 0;
} else if (!strcmp(k, "fetch.recursesubmodules")) {
- recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+ fetch_config->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)
+ fetch_config->parallel = git_config_int(k, v, ctx->kvi);
+ if (fetch_config->parallel < 0)
die(_("fetch.parallel cannot be negative"));
+ if (!fetch_config->parallel)
+ fetch_config->parallel = online_cpus();
return 0;
}
- return git_default_config(k, v, cb);
+ if (!strcmp(k, "fetch.output")) {
+ if (!v)
+ return config_error_nonbool(k);
+ else if (!strcasecmp(v, "full"))
+ fetch_config->display_format = DISPLAY_FORMAT_FULL;
+ else if (!strcasecmp(v, "compact"))
+ fetch_config->display_format = DISPLAY_FORMAT_COMPACT;
+ else
+ die(_("invalid value for '%s': '%s'"),
+ "fetch.output", v);
+ }
+
+ return git_default_config(k, v, ctx, cb);
}
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
@@ -136,97 +174,11 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
* "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere
*/
- refspec_append(&refmap, arg);
+ refspec_append(opt->value, arg);
return 0;
}
-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_BOOL(0, "atomic", &atomic_fetch,
- N_("use atomic transaction to update references")),
- OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
- N_("path to upload pack on remote end")),
- OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
- OPT_BOOL('m', "multiple", &multiple,
- N_("fetch from multiple remotes")),
- OPT_SET_INT('t', "tags", &tags,
- 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,
- N_("number of submodules fetched in parallel")),
- OPT_BOOL(0, "prefetch", &prefetch,
- N_("modify the refspec to place all refs within refs/prefetch/")),
- OPT_BOOL('p', "prune", &prune,
- N_("prune remote-tracking branches no longer on remote")),
- OPT_BOOL('P', "prune-tags", &prune_tags,
- N_("prune local tags no longer on remote and clobber changed tags")),
- OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
- N_("control recursive fetching of submodules"),
- PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "dry-run", &dry_run,
- N_("dry run")),
- OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
- N_("write fetched references to the FETCH_HEAD file")),
- OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
- OPT_BOOL('u', "update-head-ok", &update_head_ok,
- N_("allow updating of HEAD ref")),
- OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
- OPT_STRING(0, "depth", &depth, N_("depth"),
- N_("deepen history of shallow clone")),
- OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
- N_("deepen history of shallow repository based on time")),
- OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
- OPT_INTEGER(0, "deepen", &deepen_relative,
- N_("deepen history of shallow clone")),
- OPT_SET_INT_F(0, "unshallow", &unshallow,
- N_("convert to a complete repository"),
- 1, PARSE_OPT_NONEG),
- OPT_SET_INT_F(0, "refetch", &refetch,
- N_("re-fetch without negotiating common commits"),
- 1, PARSE_OPT_NONEG),
- { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
- N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
- OPT_CALLBACK_F(0, "recurse-submodules-default",
- &recurse_submodules_default, N_("on-demand"),
- N_("default for recursive fetching of submodules "
- "(lower priority than config files)"),
- PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "update-shallow", &update_shallow,
- N_("accept refs that update .git/shallow")),
- OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
- N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
- OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
- OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
- TRANSPORT_FAMILY_IPV4),
- OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
- TRANSPORT_FAMILY_IPV6),
- OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
- N_("report that we have only objects reachable from this object")),
- OPT_BOOL(0, "negotiate-only", &negotiate_only,
- N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
- OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
- OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
- N_("run 'maintenance --auto' after fetching")),
- OPT_BOOL(0, "auto-gc", &enable_auto_gc,
- N_("run 'maintenance --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_BOOL(0, "stdin", &stdin_refspecs,
- N_("accept refspecs from stdin")),
- OPT_END()
-};
-
static void unlock_pack(unsigned int flags)
{
if (gtransport)
@@ -354,7 +306,7 @@ static void clear_item(struct refname_hash_entry *item)
static void add_already_queued_tags(const char *refname,
- const struct object_id *old_oid,
+ const struct object_id *old_oid UNUSED,
const struct object_id *new_oid,
void *cb_data)
{
@@ -404,9 +356,9 @@ 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) &&
+ !repo_has_object_file_with_flags(the_repository, &ref->old_oid, quick_flags) &&
!oidset_contains(&fetch_oids, &ref->old_oid) &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
item = NULL;
@@ -420,7 +372,7 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -441,7 +393,7 @@ static void find_non_local_tags(const struct ref *refs,
* checked to see if it needs fetching.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -738,76 +690,97 @@ out:
return ret;
}
-static int refcol_width = 10;
-static int compact_format;
-
-static void adjust_refcol_width(const struct ref *ref)
+static int refcol_width(const struct ref *ref_map, int compact_format)
{
- int max, rlen, llen, len;
+ const struct ref *ref;
+ int max, width = 10;
- /* uptodate lines are only shown on high verbosity level */
- if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
- return;
+ max = term_columns();
+ if (compact_format)
+ max = max * 2 / 3;
- max = term_columns();
- rlen = utf8_strwidth(prettify_refname(ref->name));
+ for (ref = ref_map; ref; ref = ref->next) {
+ int rlen, llen = 0, len;
- llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+ if (ref->status == REF_STATUS_REJECT_SHALLOW ||
+ !ref->peer_ref ||
+ !strcmp(ref->name, "HEAD"))
+ continue;
- /*
- * rough estimation to see if the output line is too long and
- * should not be counted (we can't do precise calculation
- * anyway because we don't know if the error explanation part
- * will be printed in update_local_ref)
- */
- if (compact_format) {
- llen = 0;
- max = max * 2 / 3;
+ /* uptodate lines are only shown on high verbosity level */
+ if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+ continue;
+
+ rlen = utf8_strwidth(prettify_refname(ref->name));
+ if (!compact_format)
+ llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+ /*
+ * rough estimation to see if the output line is too long and
+ * should not be counted (we can't do precise calculation
+ * anyway because we don't know if the error explanation part
+ * will be printed in update_local_ref)
+ */
+ len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+ if (len >= max)
+ continue;
+
+ if (width < rlen)
+ width = rlen;
}
- len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
- if (len >= max)
- return;
- /*
- * Not precise calculation for compact mode because '*' can
- * appear on the left hand side of '->' and shrink the column
- * back.
- */
- if (refcol_width < rlen)
- refcol_width = rlen;
+ return width;
}
-static void prepare_format_display(struct ref *ref_map)
+static void display_state_init(struct display_state *display_state, struct ref *ref_map,
+ const char *raw_url, enum display_format format)
{
- struct ref *rm;
- const char *format = "full";
+ int i;
- if (verbosity < 0)
- return;
+ memset(display_state, 0, sizeof(*display_state));
+ strbuf_init(&display_state->buf, 0);
+ display_state->format = format;
- git_config_get_string_tmp("fetch.output", &format);
- if (!strcasecmp(format, "full"))
- compact_format = 0;
- else if (!strcasecmp(format, "compact"))
- compact_format = 1;
+ if (raw_url)
+ display_state->url = transport_anonymize_url(raw_url);
else
- die(_("invalid value for '%s': '%s'"),
- "fetch.output", format);
+ display_state->url = xstrdup("foreign");
- for (rm = ref_map; rm; rm = rm->next) {
- if (rm->status == REF_STATUS_REJECT_SHALLOW ||
- !rm->peer_ref ||
- !strcmp(rm->name, "HEAD"))
- continue;
+ display_state->url_len = strlen(display_state->url);
+ for (i = display_state->url_len - 1; display_state->url[i] == '/' && 0 <= i; i--)
+ ;
+ display_state->url_len = i + 1;
+ if (4 < i && !strncmp(".git", display_state->url + i - 3, 4))
+ display_state->url_len = i - 3;
+
+ if (verbosity < 0)
+ return;
- adjust_refcol_width(rm);
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT:
+ display_state->refcol_width = refcol_width(ref_map,
+ display_state->format == DISPLAY_FORMAT_COMPACT);
+ break;
+ case DISPLAY_FORMAT_PORCELAIN:
+ /* We don't need to precompute anything here. */
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
}
}
-static void print_remote_to_local(struct strbuf *display,
+static void display_state_release(struct display_state *display_state)
+{
+ strbuf_release(&display_state->buf);
+ free(display_state->url);
+}
+
+static void print_remote_to_local(struct display_state *display_state,
const char *remote, const char *local)
{
- strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
+ strbuf_addf(&display_state->buf, "%-*s -> %s",
+ display_state->refcol_width, remote, local);
}
static int find_and_replace(struct strbuf *haystack,
@@ -837,14 +810,14 @@ static int find_and_replace(struct strbuf *haystack,
return 1;
}
-static void print_compact(struct strbuf *display,
+static void print_compact(struct display_state *display_state,
const char *remote, const char *local)
{
struct strbuf r = STRBUF_INIT;
struct strbuf l = STRBUF_INIT;
if (!strcmp(remote, local)) {
- strbuf_addf(display, "%-*s -> *", refcol_width, remote);
+ strbuf_addf(&display_state->buf, "%-*s -> *", display_state->refcol_width, remote);
return;
}
@@ -853,40 +826,74 @@ static void print_compact(struct strbuf *display,
if (!find_and_replace(&r, local, "*"))
find_and_replace(&l, remote, "*");
- print_remote_to_local(display, r.buf, l.buf);
+ print_remote_to_local(display_state, r.buf, l.buf);
strbuf_release(&r);
strbuf_release(&l);
}
-static void format_display(struct strbuf *display, char code,
- const char *summary, const char *error,
- const char *remote, const char *local,
- int summary_width)
+static void display_ref_update(struct display_state *display_state, char code,
+ const char *summary, const char *error,
+ const char *remote, const char *local,
+ const struct object_id *old_oid,
+ const struct object_id *new_oid,
+ int summary_width)
{
- int width;
+ FILE *f = stderr;
if (verbosity < 0)
return;
- width = (summary_width + strlen(summary) - gettext_width(summary));
+ strbuf_reset(&display_state->buf);
- strbuf_addf(display, "%c %-*s ", code, width, summary);
- if (!compact_format)
- print_remote_to_local(display, remote, local);
- else
- print_compact(display, remote, local);
- if (error)
- strbuf_addf(display, " (%s)", error);
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT: {
+ int width;
+
+ if (!display_state->shown_url) {
+ strbuf_addf(&display_state->buf, _("From %.*s\n"),
+ display_state->url_len, display_state->url);
+ display_state->shown_url = 1;
+ }
+
+ width = (summary_width + strlen(summary) - gettext_width(summary));
+ remote = prettify_refname(remote);
+ local = prettify_refname(local);
+
+ strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+
+ if (display_state->format != DISPLAY_FORMAT_COMPACT)
+ print_remote_to_local(display_state, remote, local);
+ else
+ print_compact(display_state, remote, local);
+
+ if (error)
+ strbuf_addf(&display_state->buf, " (%s)", error);
+
+ break;
+ }
+ case DISPLAY_FORMAT_PORCELAIN:
+ strbuf_addf(&display_state->buf, "%c %s %s %s", code,
+ oid_to_hex(old_oid), oid_to_hex(new_oid), local);
+ f = stdout;
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
+ };
+ strbuf_addch(&display_state->buf, '\n');
+
+ fputs(display_state->buf.buf, f);
}
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
- const char *remote, const struct ref *remote_ref,
- struct strbuf *display, int summary_width)
+ struct display_state *display_state,
+ const struct ref *remote_ref,
+ int summary_width,
+ const struct fetch_config *config)
{
struct commit *current = NULL, *updated;
- const char *pretty_ref = prettify_refname(ref->name);
int fast_forward = 0;
if (!repo_has_object_file(the_repository, &ref->new_oid))
@@ -894,8 +901,9 @@ static int update_local_ref(struct ref *ref,
if (oideq(&ref->old_oid, &ref->new_oid)) {
if (verbosity > 0)
- format_display(display, '=', _("[up to date]"), NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '=', _("[up to date]"), NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 0;
}
@@ -906,9 +914,10 @@ static int update_local_ref(struct ref *ref,
* If this is the head, and it's not okay to update
* the head, and the old value of the head isn't empty...
*/
- format_display(display, '!', _("[rejected]"),
- _("can't fetch into checked-out branch"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("can't fetch into checked-out branch"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
@@ -917,13 +926,16 @@ static int update_local_ref(struct ref *ref,
if (force || ref->force) {
int r;
r = s_update_ref("updating tag", ref, transaction, 0);
- format_display(display, r ? '!' : 't', _("[tag update]"),
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("would clobber existing tag"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("would clobber existing tag"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -941,11 +953,10 @@ static int update_local_ref(struct ref *ref,
* Base this on the remote's ref name, as it's
* more likely to follow a standard layout.
*/
- const char *name = remote_ref ? remote_ref->name : "";
- if (starts_with(name, "refs/tags/")) {
+ if (starts_with(remote_ref->name, "refs/tags/")) {
msg = "storing tag";
what = _("[new tag]");
- } else if (starts_with(name, "refs/heads/")) {
+ } else if (starts_with(remote_ref->name, "refs/heads/")) {
msg = "storing head";
what = _("[new branch]");
} else {
@@ -954,15 +965,17 @@ static int update_local_ref(struct ref *ref,
}
r = s_update_ref(msg, ref, transaction, 0);
- format_display(display, r ? '!' : '*', what,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '*', what,
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
}
- if (fetch_show_forced_updates) {
+ if (config->show_forced_updates) {
uint64_t t_before = getnanotime();
- fast_forward = in_merge_bases(current, updated);
+ fast_forward = repo_in_merge_bases(the_repository, current,
+ updated);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -976,9 +989,10 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "..");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("fast-forward", ref, transaction, 1);
- format_display(display, r ? '!' : ' ', quickref.buf,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
+ r ? _("unable to update local ref") : NULL,
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else if (force || ref->force) {
@@ -988,14 +1002,16 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "...");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("forced-update", ref, transaction, 1);
- format_display(display, r ? '!' : '+', quickref.buf,
- r ? _("unable to update local ref") : _("forced update"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '+', quickref.buf,
+ r ? _("unable to update local ref") : _("forced update"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -1105,39 +1121,35 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
"'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
"to avoid this check\n");
-static int store_updated_refs(const char *raw_url, const char *remote_name,
+static int store_updated_refs(struct display_state *display_state,
+ const char *remote_name,
int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
- int url_len, i, rc = 0;
+ int rc = 0;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
- char *url;
int want_status;
int summary_width = 0;
if (verbosity >= 0)
summary_width = transport_summary_width(ref_map);
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
+ opt.exclude_hidden_refs_section = "fetch";
rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
- rc = error(_("%s did not send all necessary objects\n"), url);
+ rc = error(_("%s did not send all necessary objects\n"),
+ display_state->url);
goto abort;
}
}
- prepare_format_display(ref_map);
-
/*
* We do a pass for each fetch_head_status type in their enum order, so
* merged entries are written before not-for-merge. That lets readers
@@ -1197,7 +1209,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
ref->force = rm->peer_ref->force;
}
- if (recurse_submodules != RECURSE_SUBMODULES_OFF &&
+ if (config->recurse_submodules != RECURSE_SUBMODULES_OFF &&
(!rm->peer_ref || !oideq(&ref->old_oid, &ref->new_oid))) {
check_for_new_submodule_commits(&rm->old_oid);
}
@@ -1205,25 +1217,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (!strcmp(rm->name, "HEAD")) {
kind = "";
what = "";
- }
- else if (skip_prefix(rm->name, "refs/heads/", &what))
+ } else if (skip_prefix(rm->name, "refs/heads/", &what)) {
kind = "branch";
- else if (skip_prefix(rm->name, "refs/tags/", &what))
+ } else if (skip_prefix(rm->name, "refs/tags/", &what)) {
kind = "tag";
- else if (skip_prefix(rm->name, "refs/remotes/", &what))
+ } else if (skip_prefix(rm->name, "refs/remotes/", &what)) {
kind = "remote-tracking branch";
- else {
+ } else {
kind = "";
what = rm->name;
}
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
strbuf_reset(&note);
if (*what) {
if (*kind)
@@ -1233,12 +1237,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
append_fetch_head(fetch_head, &rm->old_oid,
rm->fetch_head_status,
- note.buf, url, url_len);
+ note.buf, display_state->url,
+ display_state->url_len);
- strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, transaction, what,
- rm, &note, summary_width);
+ rc |= update_local_ref(ref, transaction, display_state,
+ rm, summary_width, config);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1246,18 +1250,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
* would be written to FETCH_HEAD, if --dry-run
* is set).
*/
- format_display(&note, '*',
- *kind ? kind : "branch", NULL,
- *what ? what : "HEAD",
- "FETCH_HEAD", summary_width);
- }
- if (note.len) {
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"),
- url_len, url);
- shown_url = 1;
- }
- fprintf(stderr, " %s\n", note.buf);
+ display_ref_update(display_state, '*',
+ *kind ? kind : "branch", NULL,
+ rm->name,
+ "FETCH_HEAD",
+ &rm->new_oid, &rm->old_oid,
+ summary_width);
}
}
}
@@ -1268,7 +1266,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
"branches"), remote_name);
if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
- if (!fetch_show_forced_updates) {
+ if (!config->show_forced_updates) {
warning(_(warn_show_forced_updates));
} else if (forced_updates_ms > FORCED_UPDATES_DELAY_WARNING_IN_MS) {
warning(_(warn_time_show_forced_updates),
@@ -1278,7 +1276,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
- free(url);
return rc;
}
@@ -1316,19 +1313,22 @@ 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 (!repo_has_object_file_with_flags(the_repository, &r->old_oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
return -1;
}
opt.quiet = 1;
+ opt.exclude_hidden_refs_section = "fetch";
return check_connected(iterate_ref_map, &rm, &opt);
}
-static int fetch_and_consume_refs(struct transport *transport,
+static int fetch_and_consume_refs(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
int connectivity_checked = 1;
int ret;
@@ -1349,9 +1349,9 @@ static int fetch_and_consume_refs(struct transport *transport,
}
trace2_region_enter("fetch", "consume_refs", the_repository);
- ret = store_updated_refs(transport->url, transport->remote->name,
+ ret = store_updated_refs(display_state, transport->remote->name,
connectivity_checked, transaction, ref_map,
- fetch_head);
+ fetch_head, config);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1359,32 +1359,18 @@ out:
return ret;
}
-static int prune_refs(struct refspec *rs,
+static int prune_refs(struct display_state *display_state,
+ struct refspec *rs,
struct ref_transaction *transaction,
- struct ref *ref_map,
- const char *raw_url)
+ struct ref *ref_map)
{
- int url_len, i, result = 0;
+ int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT;
- char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
-
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
if (!dry_run) {
if (transaction) {
for (ref = stale_refs; ref; ref = ref->next) {
@@ -1408,23 +1394,16 @@ static int prune_refs(struct refspec *rs,
int summary_width = transport_summary_width(stale_refs);
for (ref = stale_refs; ref; ref = ref->next) {
- struct strbuf sb = STRBUF_INIT;
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"), url_len, url);
- shown_url = 1;
- }
- format_display(&sb, '-', _("[deleted]"), NULL,
- _("(none)"), prettify_refname(ref->name),
- summary_width);
- fprintf(stderr, " %s\n",sb.buf);
- strbuf_release(&sb);
+ display_ref_update(display_state, '-', _("[deleted]"), NULL,
+ _("(none)"), ref->name,
+ &ref->new_oid, &ref->old_oid,
+ summary_width);
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
cleanup:
strbuf_release(&err);
- free(url);
free_refs(stale_refs);
return result;
}
@@ -1484,7 +1463,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
int old_nr;
if (!has_glob_specials(s)) {
struct object_id oid;
- if (get_oid(s, &oid))
+ if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s);
if (!has_object(the_repository, &oid, 0))
die(_("the object %s does not exist"), s);
@@ -1539,10 +1518,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
return transport;
}
-static int backfill_tags(struct transport *transport,
+static int backfill_tags(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
- struct fetch_head *fetch_head)
+ struct fetch_head *fetch_head,
+ const struct fetch_config *config)
{
int retcode, cannot_reuse;
@@ -1563,7 +1544,8 @@ static int backfill_tags(struct transport *transport,
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
- retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head);
+ retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
+ fetch_head, config);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1574,10 +1556,12 @@ static int backfill_tags(struct transport *transport,
}
static int do_fetch(struct transport *transport,
- struct refspec *rs)
+ struct refspec *rs,
+ const struct fetch_config *config)
{
struct ref_transaction *transaction = NULL;
struct ref *ref_map = NULL;
+ struct display_state display_state = { 0 };
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
const struct ref *remote_refs;
@@ -1659,10 +1643,13 @@ static int do_fetch(struct transport *transport,
if (retcode)
goto cleanup;
+ display_state_init(&display_state, ref_map, transport->url,
+ config->display_format);
+
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
- retcode = error("%s", err.buf);
+ retcode = -1;
goto cleanup;
}
}
@@ -1676,17 +1663,17 @@ static int do_fetch(struct transport *transport,
* don't care whether --tags was specified.
*/
if (rs->nr) {
- retcode = prune_refs(rs, transaction, ref_map, transport->url);
+ retcode = prune_refs(&display_state, rs, transaction, ref_map);
} else {
- retcode = prune_refs(&transport->remote->fetch,
- transaction, ref_map,
- transport->url);
+ retcode = prune_refs(&display_state, &transport->remote->fetch,
+ transaction, ref_map);
}
if (retcode != 0)
retcode = 1;
}
- if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
+ if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
+ &fetch_head, config)) {
retcode = 1;
goto cleanup;
}
@@ -1708,8 +1695,8 @@ static int do_fetch(struct transport *transport,
* when `--atomic` is passed: in that case we'll abort
* the transaction and don't commit anything.
*/
- if (backfill_tags(transport, transaction, tags_ref_map,
- &fetch_head))
+ if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
+ &fetch_head, config))
retcode = 1;
}
@@ -1722,7 +1709,6 @@ static int do_fetch(struct transport *transport,
retcode = ref_transaction_commit(transaction, &err);
if (retcode) {
- error("%s", err.buf);
ref_transaction_free(transaction);
transaction = NULL;
goto cleanup;
@@ -1786,11 +1772,17 @@ static int do_fetch(struct transport *transport,
}
cleanup:
- if (retcode && transaction) {
- ref_transaction_abort(transaction, &err);
- error("%s", err.buf);
+ if (retcode) {
+ if (err.len) {
+ error("%s", err.buf);
+ strbuf_reset(&err);
+ }
+ if (transaction && ref_transaction_abort(transaction, &err) &&
+ err.len)
+ error("%s", err.buf);
}
+ display_state_release(&display_state);
close_fetch_head(&fetch_head);
strbuf_release(&err);
free_refs(ref_map);
@@ -1810,7 +1802,9 @@ struct remote_group_data {
struct string_list *list;
};
-static int get_remote_group(const char *key, const char *value, void *priv)
+static int get_remote_group(const char *key, const char *value,
+ const struct config_context *ctx UNUSED,
+ void *priv)
{
struct remote_group_data *g = priv;
@@ -1845,7 +1839,8 @@ static int add_remote_or_group(const char *name, struct string_list *list)
return 1;
}
-static void add_options_to_argv(struct strvec *argv)
+static void add_options_to_argv(struct strvec *argv,
+ const struct fetch_config *config)
{
if (dry_run)
strvec_push(argv, "--dry-run");
@@ -1859,9 +1854,11 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--force");
if (keep)
strvec_push(argv, "--keep");
- if (recurse_submodules == RECURSE_SUBMODULES_ON)
+ if (config->recurse_submodules == RECURSE_SUBMODULES_ON)
strvec_push(argv, "--recurse-submodules");
- else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+ else if (config->recurse_submodules == RECURSE_SUBMODULES_OFF)
+ strvec_push(argv, "--no-recurse-submodules");
+ else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
strvec_push(argv, "--recurse-submodules=on-demand");
if (tags == TAGS_SET)
strvec_push(argv, "--tags");
@@ -1877,6 +1874,10 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--ipv4");
else if (family == TRANSPORT_FAMILY_IPV6)
strvec_push(argv, "--ipv6");
+ if (!write_fetch_head)
+ strvec_push(argv, "--no-write-fetch-head");
+ if (config->display_format == DISPLAY_FORMAT_PORCELAIN)
+ strvec_pushf(argv, "--porcelain");
}
/* Fetch multiple remotes in parallel */
@@ -1885,9 +1886,11 @@ struct parallel_fetch_state {
const char **argv;
struct string_list *remotes;
int next, result;
+ const struct fetch_config *config;
};
-static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
+static int fetch_next_remote(struct child_process *cp,
+ struct strbuf *out UNUSED,
void *cb, void **task_cb)
{
struct parallel_fetch_state *state = cb;
@@ -1903,13 +1906,14 @@ static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
strvec_push(&cp->args, remote);
cp->git_cmd = 1;
- if (verbosity >= 0)
+ if (verbosity >= 0 && state->config->display_format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), remote);
return 1;
}
-static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
+static int fetch_failed_to_start(struct strbuf *out UNUSED,
+ void *cb, void *task_cb)
{
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
@@ -1934,7 +1938,8 @@ static int fetch_finished(int result, struct strbuf *out,
return 0;
}
-static int fetch_multiple(struct string_list *list, int max_children)
+static int fetch_multiple(struct string_list *list, int max_children,
+ const struct fetch_config *config)
{
int i, result = 0;
struct strvec argv = STRVEC_INIT;
@@ -1945,34 +1950,47 @@ static int fetch_multiple(struct string_list *list, int max_children)
return errcode;
}
- strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+ /*
+ * Cancel out the fetch.bundleURI config when running subprocesses,
+ * to avoid fetching from the same bundle list multiple times.
+ */
+ strvec_pushl(&argv, "-c", "fetch.bundleURI=",
+ "fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
- add_options_to_argv(&argv);
+ add_options_to_argv(&argv, config);
if (max_children != 1 && list->nr != 1) {
- struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+ struct parallel_fetch_state state = { argv.v, list, 0, 0, config };
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "fetch",
+ .tr2_label = "parallel/fetch",
+
+ .processes = max_children,
+
+ .get_next_task = &fetch_next_remote,
+ .start_failure = &fetch_failed_to_start,
+ .task_finished = &fetch_finished,
+ .data = &state,
+ };
strvec_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;
+
+ run_processes_parallel(&opts);
+ result = state.result;
} else
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
- strvec_push(&argv, name);
- if (verbosity >= 0)
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushv(&cmd.args, argv.v);
+ strvec_push(&cmd.args, name);
+ if (verbosity >= 0 && config->display_format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), name);
- if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
+ cmd.git_cmd = 1;
+ if (run_command(&cmd)) {
error(_("could not fetch %s"), name);
result = 1;
}
- strvec_pop(&argv);
}
strvec_clear(&argv);
@@ -1996,7 +2014,7 @@ 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 (!repo_has_promisor_remote(the_repository) && !filter_options.choice)
return;
/*
@@ -2021,7 +2039,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
}
static int fetch_one(struct remote *remote, int argc, const char **argv,
- int prune_tags_ok, int use_stdin_refspecs)
+ int prune_tags_ok, int use_stdin_refspecs,
+ const struct fetch_config *config)
{
struct refspec rs = REFSPEC_INIT_FETCH;
int i;
@@ -2039,8 +2058,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
/* no command line request */
if (0 <= remote->prune)
prune = remote->prune;
- else if (0 <= fetch_prune_config)
- prune = fetch_prune_config;
+ else if (0 <= config->prune)
+ prune = config->prune;
else
prune = PRUNE_BY_DEFAULT;
}
@@ -2049,8 +2068,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
/* no command line request */
if (0 <= remote->prune_tags)
prune_tags = remote->prune_tags;
- else if (0 <= fetch_prune_tags_config)
- prune_tags = fetch_prune_tags_config;
+ else if (0 <= config->prune_tags)
+ prune_tags = config->prune_tags;
else
prune_tags = PRUNE_TAGS_BY_DEFAULT;
}
@@ -2088,7 +2107,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack_atexit);
sigchain_push(SIGPIPE, SIG_IGN);
- exit_code = do_fetch(gtransport, &rs);
+ exit_code = do_fetch(gtransport, &rs, config);
sigchain_pop(SIGPIPE);
refspec_clear(&rs);
transport_disconnect(gtransport);
@@ -2098,11 +2117,116 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
- int i;
+ struct fetch_config config = {
+ .display_format = DISPLAY_FORMAT_FULL,
+ .prune = -1,
+ .prune_tags = -1,
+ .show_forced_updates = 1,
+ .recurse_submodules = RECURSE_SUBMODULES_DEFAULT,
+ .parallel = 1,
+ .submodule_fetch_jobs = -1,
+ };
+ const char *submodule_prefix = "";
+ const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
+ int all = 0, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
+ int enable_auto_gc = 1;
+ int unshallow = 0;
+ int max_jobs = -1;
+ int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+ int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
+ int fetch_write_commit_graph = -1;
+ int stdin_refspecs = 0;
+ int negotiate_only = 0;
+ int porcelain = 0;
+ int i;
+
+ 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_BOOL(0, "atomic", &atomic_fetch,
+ N_("use atomic transaction to update references")),
+ OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+ N_("path to upload pack on remote end")),
+ OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
+ OPT_BOOL('m', "multiple", &multiple,
+ N_("fetch from multiple remotes")),
+ OPT_SET_INT('t', "tags", &tags,
+ 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,
+ N_("number of submodules fetched in parallel")),
+ OPT_BOOL(0, "prefetch", &prefetch,
+ N_("modify the refspec to place all refs within refs/prefetch/")),
+ OPT_BOOL('p', "prune", &prune,
+ N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('P', "prune-tags", &prune_tags,
+ N_("prune local tags no longer on remote and clobber changed tags")),
+ OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
+ N_("control recursive fetching of submodules"),
+ PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "dry-run", &dry_run,
+ N_("dry run")),
+ OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+ OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+ N_("write fetched references to the FETCH_HEAD file")),
+ OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+ OPT_BOOL('u', "update-head-ok", &update_head_ok,
+ N_("allow updating of HEAD ref")),
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_STRING(0, "depth", &depth, N_("depth"),
+ N_("deepen history of shallow clone")),
+ OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
+ N_("deepen history of shallow repository based on time")),
+ OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
+ N_("deepen history of shallow clone, excluding rev")),
+ OPT_INTEGER(0, "deepen", &deepen_relative,
+ N_("deepen history of shallow clone")),
+ OPT_SET_INT_F(0, "unshallow", &unshallow,
+ N_("convert to a complete repository"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "refetch", &refetch,
+ N_("re-fetch without negotiating common commits"),
+ 1, PARSE_OPT_NONEG),
+ { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+ N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+ OPT_CALLBACK_F(0, "recurse-submodules-default",
+ &recurse_submodules_default, N_("on-demand"),
+ N_("default for recursive fetching of submodules "
+ "(lower priority than config files)"),
+ PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "update-shallow", &update_shallow,
+ N_("accept refs that update .git/shallow")),
+ OPT_CALLBACK_F(0, "refmap", &refmap, N_("refmap"),
+ N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
+ OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
+ OPT_IPVERSION(&family),
+ OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+ N_("report that we have only objects reachable from this object")),
+ OPT_BOOL(0, "negotiate-only", &negotiate_only,
+ N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "auto-gc", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "show-forced-updates", &config.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_BOOL(0, "stdin", &stdin_refspecs,
+ N_("accept refspecs from stdin")),
+ OPT_END()
+ };
packet_trace_identity("fetch");
@@ -2116,7 +2240,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
free(anon);
}
- git_config(git_fetch_config, NULL);
+ git_config(git_fetch_config, &config);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -2126,7 +2250,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
builtin_fetch_options, builtin_fetch_usage, 0);
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
- recurse_submodules = recurse_submodules_cli;
+ config.recurse_submodules = recurse_submodules_cli;
if (negotiate_only) {
switch (recurse_submodules_cli) {
@@ -2137,7 +2261,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
* submodules. Skip it by setting recurse_submodules to
* RECURSE_SUBMODULES_OFF.
*/
- recurse_submodules = RECURSE_SUBMODULES_OFF;
+ config.recurse_submodules = RECURSE_SUBMODULES_OFF;
break;
default:
@@ -2146,15 +2270,35 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
- if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
- int *sfjc = submodule_fetch_jobs_config == -1
- ? &submodule_fetch_jobs_config : NULL;
- int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
- ? &recurse_submodules : NULL;
+ if (config.recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ int *sfjc = config.submodule_fetch_jobs == -1
+ ? &config.submodule_fetch_jobs : NULL;
+ int *rs = config.recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+ ? &config.recurse_submodules : NULL;
fetch_config_from_gitmodules(sfjc, rs);
}
+
+ if (porcelain) {
+ switch (recurse_submodules_cli) {
+ case RECURSE_SUBMODULES_OFF:
+ case RECURSE_SUBMODULES_DEFAULT:
+ /*
+ * Reference updates in submodules would be ambiguous
+ * in porcelain mode, so we reject this combination.
+ */
+ config.recurse_submodules = RECURSE_SUBMODULES_OFF;
+ break;
+
+ default:
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--porcelain", "--recurse-submodules");
+ }
+
+ config.display_format = DISPLAY_FORMAT_PORCELAIN;
+ }
+
if (negotiate_only && !negotiation_tip.nr)
die(_("--negotiate-only needs one or more --negotiation-tip=*"));
@@ -2184,6 +2328,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (dry_run)
write_fetch_head = 0;
+ if (!max_jobs)
+ max_jobs = online_cpus();
+
+ if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+ fetch_bundle_uri(the_repository, bundle_uri, NULL))
+ warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
@@ -2218,6 +2369,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
argv++;
}
}
+ string_list_remove_duplicates(&list, 0);
if (negotiate_only) {
struct oidset acked_commits = OIDSET_INIT;
@@ -2243,9 +2395,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
printf("%s\n", oid_to_hex(oid));
oidset_clear(&acked_commits);
} else if (remote) {
- if (filter_options.choice || has_promisor_remote())
+ if (filter_options.choice || repo_has_promisor_remote(the_repository))
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
+ result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
+ &config);
} else {
int max_children = max_jobs;
@@ -2262,13 +2415,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
"from one remote"));
if (max_children < 0)
- max_children = fetch_parallel_config;
+ max_children = config.parallel;
/* TODO should this also die if we have a previous partial-clone? */
- result = fetch_multiple(&list, max_children);
+ result = fetch_multiple(&list, max_children, &config);
}
-
/*
* This is only needed after fetch_one(), which does not fetch
* submodules by itself.
@@ -2278,20 +2430,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
* the fetched history from each remote, so there is no need
* to fetch submodules from here.
*/
- if (!result && remote && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+ if (!result && remote && (config.recurse_submodules != RECURSE_SUBMODULES_OFF)) {
struct strvec options = STRVEC_INIT;
int max_children = max_jobs;
if (max_children < 0)
- max_children = submodule_fetch_jobs_config;
+ max_children = config.submodule_fetch_jobs;
if (max_children < 0)
- max_children = fetch_parallel_config;
+ max_children = config.parallel;
- add_options_to_argv(&options);
+ add_options_to_argv(&options, &config);
result = fetch_submodules(the_repository,
&options,
submodule_prefix,
- recurse_submodules,
+ config.recurse_submodules,
recurse_submodules_default,
verbosity < 0,
max_children);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 8d8fd393f8..0f9855b680 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "config.h"
#include "fmt-merge-msg.h"
+#include "gettext.h"
#include "parse-options.h"
static const char * const fmt_merge_msg_usage[] = {
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 6f62f40d12..3885a9c28e 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,10 +1,12 @@
#include "builtin.h"
-#include "cache.h"
+#include "commit.h"
#include "config.h"
-#include "refs.h"
+#include "gettext.h"
#include "object.h"
#include "parse-options.h"
#include "ref-filter.h"
+#include "strbuf.h"
+#include "strvec.h"
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
@@ -16,15 +18,13 @@ static char const * const for_each_ref_usage[] = {
int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
{
- int i;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
- int maxcount = 0, icase = 0;
- struct ref_array array;
- struct ref_filter filter;
+ int icase = 0;
+ struct ref_filter filter = REF_FILTER_INIT;
struct ref_format format = REF_FORMAT_INIT;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
+ int from_stdin = 0;
+ struct strvec vec = STRVEC_INIT;
struct option opts[] = {
OPT_BIT('s', "shell", &format.quote_style,
@@ -35,11 +35,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", &format.quote_style,
N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_GROUP(""),
- OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
+ OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
+ OPT_REF_FILTER_EXCLUDE(&filter),
OPT_REF_SORT(&sorting_options),
OPT_CALLBACK(0, "points-at", &filter.points_at,
N_("object"), N_("print only refs which points at the given object"),
@@ -49,19 +52,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+ OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
OPT_END(),
};
- memset(&array, 0, sizeof(array));
- memset(&filter, 0, sizeof(filter));
-
format.format = "%(objectname) %(objecttype)\t%(refname)";
git_config(git_default_config, NULL);
+ /* Set default (refname) sorting */
+ string_list_append(&sorting_options, "refname");
+
parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
- if (maxcount < 0) {
- error("invalid --count argument: `%d'", maxcount);
+ if (format.array_opts.max_count < 0) {
+ error("invalid --count argument: `%d'", format.array_opts.max_count);
usage_with_options(for_each_ref_usage, opts);
}
if (HAS_MULTI_BITS(format.quote_style)) {
@@ -75,27 +79,28 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
- filter.name_patterns = argv;
- filter.match_as_path = 1;
- filter_refs(&array, &filter, FILTER_REFS_ALL);
- ref_array_sort(sorting, &array);
-
- if (!maxcount || array.nr < maxcount)
- maxcount = array.nr;
- for (i = 0; i < maxcount; i++) {
- strbuf_reset(&err);
- strbuf_reset(&output);
- if (format_ref_array_item(array.items[i], &format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- putchar('\n');
+ if (from_stdin) {
+ struct strbuf line = STRBUF_INIT;
+
+ if (argv[0])
+ die(_("unknown arguments supplied with --stdin"));
+
+ while (strbuf_getline(&line, stdin) != EOF)
+ strvec_push(&vec, line.buf);
+
+ strbuf_release(&line);
+
+ /* vec.v is NULL-terminated, just like 'argv'. */
+ filter.name_patterns = vec.v;
+ } else {
+ filter.name_patterns = argv;
}
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
- free_commit_list(filter.with_commit);
- free_commit_list(filter.no_commit);
+ filter.match_as_path = 1;
+ filter_and_format_refs(&filter, FILTER_REFS_ALL, sorting, &format);
+
+ ref_filter_clear(&filter);
ref_sorting_release(sorting);
+ strvec_clear(&vec);
return 0;
}
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index fd86e5a861..28186b30f5 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -1,12 +1,14 @@
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "repository.h"
#include "run-command.h"
#include "string-list.h"
static const char * const for_each_repo_usage[] = {
- N_("git for-each-repo --config=<config> <command-args>"),
+ N_("git for-each-repo --config=<config> [--] <arguments>"),
NULL
};
@@ -14,13 +16,16 @@ static int run_command_on_repo(const char *path, int argc, const char ** argv)
{
int i;
struct child_process child = CHILD_PROCESS_INIT;
+ char *abspath = interpolate_path(path, 0);
child.git_cmd = 1;
- strvec_pushl(&child.args, "-C", path, NULL);
+ strvec_pushl(&child.args, "-C", abspath, NULL);
for (i = 0; i < argc; i++)
strvec_push(&child.args, argv[i]);
+ free(abspath);
+
return run_command(&child);
}
@@ -29,6 +34,7 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
static const char *config_key = NULL;
int i, result = 0;
const struct string_list *values;
+ int err;
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
@@ -42,14 +48,11 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
if (!config_key)
die(_("missing --config=<config>"));
- values = repo_config_get_value_multi(the_repository,
- config_key);
-
- /*
- * Do nothing on an empty list, which is equivalent to the case
- * where the config variable does not exist at all.
- */
- if (!values)
+ err = repo_config_get_string_multi(the_repository, config_key, &values);
+ if (err < 0)
+ usage_msg_optf(_("got bad config --config=%s"),
+ for_each_repo_usage, options, config_key);
+ else if (err)
return 0;
for (i = 0; !result && i < values->nr; i++)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 41acbc229e..a7cf94f67e 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1,6 +1,6 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "commit.h"
@@ -10,18 +10,23 @@
#include "refs.h"
#include "pack.h"
#include "cache-tree.h"
-#include "tree-walk.h"
#include "fsck.h"
#include "parse-options.h"
-#include "dir.h"
#include "progress.h"
#include "streaming.h"
-#include "decorate.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "replace-object.h"
#include "resolve-undo.h"
#include "run-command.h"
+#include "sparse-index.h"
#include "worktree.h"
+#include "pack-revindex.h"
+#include "pack-bitmap.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -51,6 +56,8 @@ static int name_objects;
#define ERROR_REFS 010
#define ERROR_COMMIT_GRAPH 020
#define ERROR_MULTI_PACK_INDEX 040
+#define ERROR_PACK_REV_INDEX 0100
+#define ERROR_BITMAP 0200
static const char *describe_object(const struct object_id *oid)
{
@@ -82,11 +89,11 @@ static int objerror(struct object *obj, const char *err)
return -1;
}
-static int fsck_error_func(struct fsck_options *o,
+static int fsck_error_func(struct fsck_options *o UNUSED,
const struct object_id *oid,
enum object_type object_type,
enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
+ enum fsck_msg_id msg_id UNUSED,
const char *message)
{
switch (msg_type) {
@@ -111,7 +118,7 @@ static int fsck_error_func(struct fsck_options *o,
static struct object_array pending;
static int mark_object(struct object *obj, enum object_type type,
- void *data, struct fsck_options *options)
+ void *data, struct fsck_options *options UNUSED)
{
struct object *parent = data;
@@ -196,8 +203,8 @@ static int traverse_reachable(void)
return !!result;
}
-static int mark_used(struct object *obj, enum object_type object_type,
- void *data, struct fsck_options *options)
+static int mark_used(struct object *obj, enum object_type type UNUSED,
+ void *data UNUSED, struct fsck_options *options UNUSED)
{
if (!obj)
return 1;
@@ -233,17 +240,17 @@ static void mark_unreachable_referents(const struct object_id *oid)
}
static int mark_loose_unreachable_referents(const struct object_id *oid,
- const char *path,
- void *data)
+ const char *path UNUSED,
+ void *data UNUSED)
{
mark_unreachable_referents(oid);
return 0;
}
static int mark_packed_unreachable_referents(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data)
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
+ void *data UNUSED)
{
mark_unreachable_referents(oid);
return 0;
@@ -661,14 +668,15 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
return 0; /* keep checking other objects, even if we saw an error */
}
-static int fsck_cruft(const char *basename, const char *path, void *data)
+static int fsck_cruft(const char *basename, const char *path,
+ void *data UNUSED)
{
if (!starts_with(basename, "tmp_obj_"))
fprintf_ln(stderr, _("bad sha1 file: %s"), path);
return 0;
}
-static int fsck_subdir(unsigned int nr, const char *path, void *data)
+static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
{
struct for_each_loose_cb *cb_data = data;
struct progress *progress = cb_data->progress;
@@ -732,19 +740,19 @@ static int fsck_head_link(const char *head_ref_name,
return 0;
}
-static int fsck_cache_tree(struct cache_tree *it)
+static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
{
int i;
int err = 0;
if (verbose)
- fprintf_ln(stderr, _("Checking cache tree"));
+ fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
if (0 <= it->entry_count) {
struct object *obj = parse_object(the_repository, &it->oid);
if (!obj) {
- error(_("%s: invalid sha1 pointer in cache-tree"),
- oid_to_hex(&it->oid));
+ error(_("%s: invalid sha1 pointer in cache-tree of %s"),
+ oid_to_hex(&it->oid), index_path);
errors_found |= ERROR_REFS;
return 1;
}
@@ -755,11 +763,12 @@ static int fsck_cache_tree(struct cache_tree *it)
err |= objerror(obj, _("non-tree in cache-tree"));
}
for (i = 0; i < it->subtree_nr; i++)
- err |= fsck_cache_tree(it->down[i]->cache_tree);
+ err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
return err;
}
-static int fsck_resolve_undo(struct index_state *istate)
+static int fsck_resolve_undo(struct index_state *istate,
+ const char *index_path)
{
struct string_list_item *item;
struct string_list *resolve_undo = istate->resolve_undo;
@@ -782,8 +791,9 @@ static int fsck_resolve_undo(struct index_state *istate)
obj = parse_object(the_repository, &ru->oid[i]);
if (!obj) {
- error(_("%s: invalid sha1 pointer in resolve-undo"),
- oid_to_hex(&ru->oid[i]));
+ error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
+ oid_to_hex(&ru->oid[i]),
+ index_path);
errors_found |= ERROR_REFS;
continue;
}
@@ -796,6 +806,38 @@ static int fsck_resolve_undo(struct index_state *istate)
return 0;
}
+static void fsck_index(struct index_state *istate, const char *index_path,
+ int is_current_worktree)
+{
+ unsigned int i;
+
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(istate);
+ for (i = 0; i < istate->cache_nr; i++) {
+ unsigned int mode;
+ struct blob *blob;
+ struct object *obj;
+
+ mode = istate->cache[i]->ce_mode;
+ if (S_ISGITLINK(mode))
+ continue;
+ blob = lookup_blob(the_repository,
+ &istate->cache[i]->oid);
+ if (!blob)
+ continue;
+ obj = &blob->object;
+ obj->flags |= USED;
+ fsck_put_object_name(&fsck_walk_options, &obj->oid,
+ "%s:%s",
+ is_current_worktree ? "" : index_path,
+ istate->cache[i]->name);
+ mark_object_reachable(obj);
+ }
+ if (istate->cache_tree)
+ fsck_cache_tree(istate->cache_tree, index_path);
+ fsck_resolve_undo(istate, index_path);
+}
+
static void mark_object_for_connectivity(const struct object_id *oid)
{
struct object *obj = lookup_unknown_object(the_repository, oid);
@@ -803,24 +845,59 @@ static void mark_object_for_connectivity(const struct object_id *oid)
}
static int mark_loose_for_connectivity(const struct object_id *oid,
- const char *path,
- void *data)
+ const char *path UNUSED,
+ void *data UNUSED)
{
mark_object_for_connectivity(oid);
return 0;
}
static int mark_packed_for_connectivity(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data)
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED,
+ void *data UNUSED)
{
mark_object_for_connectivity(oid);
return 0;
}
+static int check_pack_rev_indexes(struct repository *r, int show_progress)
+{
+ struct progress *progress = NULL;
+ uint32_t pack_count = 0;
+ int res = 0;
+
+ if (show_progress) {
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next)
+ pack_count++;
+ progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count);
+ pack_count = 0;
+ }
+
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
+ int load_error = load_pack_revindex_from_disk(p);
+
+ if (load_error < 0) {
+ error(_("unable to load rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ } else if (!load_error &&
+ !load_pack_revindex(r, p) &&
+ verify_pack_revindex(p)) {
+ error(_("invalid rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ }
+ display_progress(progress, ++pack_count);
+ }
+ stop_progress(&progress);
+
+ return res;
+}
+
static char const * const fsck_usage[] = {
- N_("git fsck [<options>] [<object>...]"),
+ N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
+ " [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
+ " [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
+ " [--[no-]name-objects] [<object>...]"),
NULL
};
@@ -851,7 +928,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
fetch_if_missing = 0;
errors_found = 0;
- read_replace_refs = 0;
+ disable_replace_refs();
save_commit_buffer = 0;
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
@@ -920,7 +997,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
struct object_id oid;
- if (!get_oid(arg, &oid)) {
+ if (!repo_get_oid(the_repository, arg, &oid)) {
struct object *obj = lookup_object(the_repository,
&oid);
@@ -953,34 +1030,36 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (keep_cache_objects) {
+ struct worktree **worktrees, **p;
+
verify_index_checksum = 1;
verify_ce_order = 1;
- read_cache();
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++) {
- unsigned int mode;
- struct blob *blob;
- struct object *obj;
- mode = active_cache[i]->ce_mode;
- if (S_ISGITLINK(mode))
- continue;
- blob = lookup_blob(the_repository,
- &active_cache[i]->oid);
- if (!blob)
- continue;
- obj = &blob->object;
- obj->flags |= USED;
- fsck_put_object_name(&fsck_walk_options, &obj->oid,
- ":%s", active_cache[i]->name);
- mark_object_reachable(obj);
+ worktrees = get_worktrees();
+ for (p = worktrees; *p; p++) {
+ struct worktree *wt = *p;
+ struct index_state istate =
+ INDEX_STATE_INIT(the_repository);
+ char *path;
+
+ /*
+ * Make a copy since the buffer is reusable
+ * and may get overwritten by other calls
+ * while we're examining the index.
+ */
+ path = xstrdup(worktree_git_path(wt, "index"));
+ read_index_from(&istate, path, get_worktree_git_dir(wt));
+ fsck_index(&istate, path, wt->is_current);
+ discard_index(&istate);
+ free(path);
}
- if (active_cache_tree)
- fsck_cache_tree(active_cache_tree);
- fsck_resolve_undo(&the_index);
+ free_worktrees(worktrees);
}
+ errors_found |= check_pack_rev_indexes(the_repository, show_progress);
+ if (verify_bitmap_files(the_repository))
+ errors_found |= ERROR_BITMAP;
+
check_connectivity();
if (the_repository->settings.core_commit_graph) {
@@ -992,6 +1071,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
commit_graph_verify.git_cmd = 1;
strvec_pushl(&commit_graph_verify.args, "commit-graph",
"verify", "--object-dir", odb->path, NULL);
+ if (show_progress)
+ strvec_push(&commit_graph_verify.args, "--progress");
+ else
+ strvec_push(&commit_graph_verify.args, "--no-progress");
if (run_command(&commit_graph_verify))
errors_found |= ERROR_COMMIT_GRAPH;
}
@@ -1006,6 +1089,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
midx_verify.git_cmd = 1;
strvec_pushl(&midx_verify.args, "multi-pack-index",
"verify", "--object-dir", odb->path, NULL);
+ if (show_progress)
+ strvec_push(&midx_verify.args, "--progress");
+ else
+ strvec_push(&midx_verify.args, "--no-progress");
if (run_command(&midx_verify))
errors_found |= ERROR_MULTI_PACK_INDEX;
}
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index c69da93ece..1593713f4c 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1,14 +1,22 @@
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "repository.h"
#include "simple-ipc.h"
#include "khash.h"
-#include "pkt-line.h"
+#include "run-command.h"
+#include "trace.h"
+#include "trace2.h"
static const char * const builtin_fsmonitor__daemon_usage[] = {
N_("git fsmonitor--daemon start [<options>]"),
@@ -31,10 +39,11 @@ static int fsmonitor__start_timeout_sec = 60;
#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
static int fsmonitor__announce_startup = 0;
-static int fsmonitor_config(const char *var, const char *value, void *cb)
+static int fsmonitor_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, FSMONITOR__IPC_THREADS)) {
- int i = git_config_int(var, value);
+ int i = git_config_int(var, value, ctx->kvi);
if (i < 1)
return error(_("value of '%s' out of range: %d"),
FSMONITOR__IPC_THREADS, i);
@@ -43,7 +52,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, FSMONITOR__START_TIMEOUT)) {
- int i = git_config_int(var, value);
+ int i = git_config_int(var, value, ctx->kvi);
if (i < 0)
return error(_("value of '%s' out of range: %d"),
FSMONITOR__START_TIMEOUT, i);
@@ -53,7 +62,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) {
int is_bool;
- int i = git_config_bool_or_int(var, value, &is_bool);
+ int i = git_config_bool_or_int(var, value, ctx->kvi, &is_bool);
if (i < 0)
return error(_("value of '%s' not bool or int: %d"),
var, i);
@@ -61,7 +70,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
/*
@@ -121,8 +130,9 @@ struct fsmonitor_cookie_item {
enum fsmonitor_cookie_item_result result;
};
-static int cookies_cmp(const void *data, const struct hashmap_entry *he1,
- const struct hashmap_entry *he2, const void *keydata)
+static int cookies_cmp(const void *data UNUSED,
+ const struct hashmap_entry *he1,
+ const struct hashmap_entry *he2, const void *keydata)
{
const struct fsmonitor_cookie_item *a =
container_of(he1, const struct fsmonitor_cookie_item, entry);
@@ -709,6 +719,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
"fsmonitor: unsupported V1 protocol '%s'"),
command);
do_trivial = 1;
+ do_cookie = 1;
} else {
/* We have "builtin:*" */
@@ -718,6 +729,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
"fsmonitor: invalid V2 protocol token '%s'",
command);
do_trivial = 1;
+ do_cookie = 1;
} else {
/*
@@ -1208,7 +1220,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
* events.
*/
if (pthread_create(&state->listener_thread, NULL,
- fsm_listen__thread_proc, state) < 0) {
+ fsm_listen__thread_proc, state)) {
ipc_server_stop_async(state->ipc_server_data);
err = error(_("could not start fsmonitor listener thread"));
goto cleanup;
@@ -1219,7 +1231,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
* Start the health thread to watch over our process.
*/
if (pthread_create(&state->health_thread, NULL,
- fsm_health__thread_proc, state) < 0) {
+ fsm_health__thread_proc, state)) {
ipc_server_stop_async(state->ipc_server_data);
err = error(_("could not start fsmonitor health thread"));
goto cleanup;
@@ -1282,6 +1294,11 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ strbuf_init(&state.alias.alias, 0);
+ strbuf_init(&state.alias.points_to, 0);
+ if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)))
+ goto done;
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
@@ -1343,7 +1360,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
@@ -1390,11 +1408,13 @@ done:
strbuf_release(&state.path_gitdir_watch);
strbuf_release(&state.path_cookie_prefix);
strbuf_release(&state.path_ipc);
+ strbuf_release(&state.alias.alias);
+ strbuf_release(&state.alias.points_to);
return err;
}
-static int try_to_run_foreground_daemon(int detach_console)
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
{
/*
* Technically, we don't need to probe for an existing daemon
@@ -1424,7 +1444,8 @@ static int try_to_run_foreground_daemon(int detach_console)
static start_bg_wait_cb bg_wait_cb;
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+ void *cb_data UNUSED)
{
enum ipc_active_state s = fsmonitor_ipc__get_state();
@@ -1563,7 +1584,7 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
}
#else
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED)
{
struct option options[] = {
OPT_END()
diff --git a/builtin/gc.c b/builtin/gc.c
index ceff31ea00..7c11d5ebef 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -11,6 +11,10 @@
*/
#include "builtin.h"
+#include "abspath.h"
+#include "date.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "tempfile.h"
@@ -22,16 +26,21 @@
#include "commit.h"
#include "commit-graph.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "pack.h"
#include "pack-objects.h"
+#include "path.h"
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
#include "refs.h"
#include "remote.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "hook.h"
+#include "setup.h"
+#include "trace2.h"
#define FAILED_RUN "failed to run %s"
@@ -42,7 +51,8 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
-static int cruft_packs = 0;
+static int cruft_packs = 1;
+static unsigned long max_cruft_size;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -52,6 +62,8 @@ static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
static const char *prune_expire = "2.weeks.ago";
static const char *prune_worktrees_expire = "3.months.ago";
+static char *repack_filter;
+static char *repack_filter_to;
static unsigned long big_pack_threshold;
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
@@ -154,6 +166,7 @@ static void gc_config(void)
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_bool("gc.cruftpacks", &cruft_packs);
+ git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_get_expiry("gc.logexpiry", &gc_log_expire);
@@ -161,15 +174,20 @@ static void gc_config(void)
git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+ git_config_get_string("gc.repackfilter", &repack_filter);
+ git_config_get_string("gc.repackfilterto", &repack_filter_to);
+
git_config(git_default_config, NULL);
}
struct maintenance_run_opts;
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
- const char *argv[] = { "pack-refs", "--all", "--prune", NULL };
+ struct child_process cmd = CHILD_PROCESS_INIT;
- return run_command_v_opt(argv, RUN_GIT_CMD);
+ cmd.git_cmd = 1;
+ strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
+ return run_command(&cmd);
}
static int too_many_loose_objects(void)
@@ -211,7 +229,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
struct packed_git *p, *base = NULL;
for (p = get_all_packs(the_repository); p; p = p->next) {
- if (!p->pack_local)
+ if (!p->pack_local || p->is_cruft)
continue;
if (limit) {
if (p->pack_size >= limit)
@@ -282,7 +300,7 @@ static uint64_t total_ram(void)
static uint64_t estimate_repack_memory(struct packed_git *pack)
{
- unsigned long nr_objects = approximate_object_count();
+ unsigned long nr_objects = repo_approximate_object_count(the_repository);
size_t os_cache, heap;
if (!pack || !nr_objects)
@@ -322,7 +340,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
return os_cache + heap;
}
-static int keep_one_pack(struct string_list_item *item, void *data)
+static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
{
strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
return 0;
@@ -336,6 +354,9 @@ static void add_repack_all_option(struct string_list *keep_pack)
strvec_push(&repack, "--cruft");
if (prune_expire)
strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+ if (max_cruft_size)
+ strvec_pushf(&repack, "--max-cruft-size=%lu",
+ max_cruft_size);
} else {
strvec_push(&repack, "-A");
if (prune_expire)
@@ -344,6 +365,11 @@ static void add_repack_all_option(struct string_list *keep_pack)
if (keep_pack)
for_each_string_list(keep_pack, keep_one_pack, NULL);
+
+ if (repack_filter && *repack_filter)
+ strvec_pushf(&repack, "--filter=%s", repack_filter);
+ if (repack_filter_to && *repack_filter_to)
+ strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
}
static void add_repack_incremental_option(void)
@@ -535,8 +561,14 @@ static void gc_before_repack(void)
if (pack_refs && maintenance_task_pack_refs(NULL))
die(FAILED_RUN, "pack-refs");
- if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
- die(FAILED_RUN, reflog.v[0]);
+ if (prune_reflogs) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ cmd.git_cmd = 1;
+ strvec_pushv(&cmd.args, reflog.v);
+ if (run_command(&cmd))
+ die(FAILED_RUN, reflog.v[0]);
+ }
}
int cmd_gc(int argc, const char **argv, const char *prefix)
@@ -550,6 +582,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int daemonized = 0;
int keep_largest_pack = -1;
timestamp_t dummy;
+ struct child_process rerere_cmd = CHILD_PROCESS_INIT;
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -557,6 +590,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
@@ -671,30 +706,44 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
gc_before_repack();
if (!repository_format_precious_objects) {
- if (run_command_v_opt(repack.v,
- RUN_GIT_CMD | RUN_CLOSE_OBJECT_STORE))
+ struct child_process repack_cmd = CHILD_PROCESS_INIT;
+
+ repack_cmd.git_cmd = 1;
+ repack_cmd.close_object_store = 1;
+ strvec_pushv(&repack_cmd.args, repack.v);
+ if (run_command(&repack_cmd))
die(FAILED_RUN, repack.v[0]);
if (prune_expire) {
+ struct child_process prune_cmd = CHILD_PROCESS_INIT;
+
/* run `git prune` even if using cruft packs */
strvec_push(&prune, prune_expire);
if (quiet)
strvec_push(&prune, "--no-progress");
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&prune,
"--exclude-promisor-objects");
- if (run_command_v_opt(prune.v, RUN_GIT_CMD))
+ prune_cmd.git_cmd = 1;
+ strvec_pushv(&prune_cmd.args, prune.v);
+ if (run_command(&prune_cmd))
die(FAILED_RUN, prune.v[0]);
}
}
if (prune_worktrees_expire) {
+ struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
+
strvec_push(&prune_worktrees, prune_worktrees_expire);
- if (run_command_v_opt(prune_worktrees.v, RUN_GIT_CMD))
+ prune_worktrees_cmd.git_cmd = 1;
+ strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
+ if (run_command(&prune_worktrees_cmd))
die(FAILED_RUN, prune_worktrees.v[0]);
}
- if (run_command_v_opt(rerere.v, RUN_GIT_CMD))
+ rerere_cmd.git_cmd = 1;
+ strvec_pushv(&rerere_cmd.args, rerere.v);
+ if (run_command(&rerere_cmd))
die(FAILED_RUN, rerere.v[0]);
report_garbage = report_pack_garbage;
@@ -704,7 +753,6 @@ 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,
@@ -794,7 +842,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = lookup_commit(the_repository, oid);
if (!commit)
return 0;
- if (parse_commit(commit) ||
+ if (repo_parse_commit(the_repository, commit) ||
commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return 0;
@@ -811,7 +859,7 @@ static int dfs_on_ref(const char *refname UNUSED,
commit = pop_commit(&stack);
for (parent = commit->parents; parent; parent = parent->next) {
- if (parse_commit(parent->item) ||
+ if (repo_parse_commit(the_repository, parent->item) ||
commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
parent->item->object.flags & SEEN)
continue;
@@ -950,9 +998,9 @@ struct write_loose_object_data {
static int loose_object_auto_limit = 100;
-static int loose_object_count(const struct object_id *oid,
- const char *path,
- void *data)
+static int loose_object_count(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data)
{
int *count = (int*)data;
if (++(*count) >= loose_object_auto_limit)
@@ -977,15 +1025,15 @@ static int loose_object_auto_condition(void)
NULL, NULL, &count);
}
-static int bail_on_loose(const struct object_id *oid,
- const char *path,
- void *data)
+static int bail_on_loose(const struct object_id *oid UNUSED,
+ const char *path UNUSED,
+ void *data UNUSED)
{
return 1;
}
static int write_loose_object_to_stdin(const struct object_id *oid,
- const char *path,
+ const char *path UNUSED,
void *data)
{
struct write_loose_object_data *d = (struct write_loose_object_data *)data;
@@ -1372,7 +1420,7 @@ static void initialize_task_config(int schedule)
strbuf_release(&config_name);
}
-static int task_option_parse(const struct option *opt,
+static int task_option_parse(const struct option *opt UNUSED,
const char *arg, int unset)
{
int i, num_selected = 0;
@@ -1454,20 +1502,22 @@ static char *get_maintpath(void)
}
static char const * const builtin_maintenance_register_usage[] = {
- "git maintenance register",
+ "git maintenance register [--config-file <path>]",
NULL
};
static int maintenance_register(int argc, const char **argv, const char *prefix)
{
+ char *config_file = NULL;
struct option options[] = {
+ OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
OPT_END(),
};
- int rc;
- char *config_value;
- struct child_process config_set = CHILD_PROCESS_INIT;
- struct child_process config_get = CHILD_PROCESS_INIT;
+ int found = 0;
+ const char *key = "maintenance.repo";
char *maintpath = get_maintpath();
+ struct string_list_item *item;
+ const struct string_list *list;
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_register_usage, 0);
@@ -1479,51 +1529,65 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
git_config_set("maintenance.auto", "false");
/* Set maintenance strategy, if unset */
- if (!git_config_get_string("maintenance.strategy", &config_value))
- free(config_value);
- else
+ if (git_config_get("maintenance.strategy"))
git_config_set("maintenance.strategy", "incremental");
- config_get.git_cmd = 1;
- strvec_pushl(&config_get.args, "config", "--global", "--get",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
- config_get.out = -1;
-
- if (start_command(&config_get)) {
- rc = error(_("failed to run 'git config'"));
- goto done;
- }
-
- /* We already have this value in our config! */
- if (!finish_command(&config_get)) {
- rc = 0;
- goto done;
+ if (!git_config_get_string_multi(key, &list)) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
}
- config_set.git_cmd = 1;
- strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
- maintpath, NULL);
+ if (!found) {
+ int rc;
+ char *user_config = NULL, *xdg_config = NULL;
- rc = run_command(&config_set);
+ if (!config_file) {
+ git_global_config(&user_config, &xdg_config);
+ config_file = user_config;
+ if (!user_config)
+ die(_("$HOME not set"));
+ }
+ rc = git_config_set_multivar_in_file_gently(
+ config_file, "maintenance.repo", maintpath,
+ CONFIG_REGEX_NONE, 0);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc)
+ die(_("unable to add '%s' value of '%s'"),
+ key, maintpath);
+ }
-done:
free(maintpath);
- return rc;
+ return 0;
}
static char const * const builtin_maintenance_unregister_usage[] = {
- "git maintenance unregister",
+ "git maintenance unregister [--config-file <path>] [--force]",
NULL
};
static int maintenance_unregister(int argc, const char **argv, const char *prefix)
{
+ int force = 0;
+ char *config_file = NULL;
struct option options[] = {
+ OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
+ OPT__FORCE(&force,
+ N_("return success even if repository was not registered"),
+ PARSE_OPT_NOCOMPLETE),
OPT_END(),
};
- int rc;
- struct child_process config_unset = CHILD_PROCESS_INIT;
+ const char *key = "maintenance.repo";
char *maintpath = get_maintpath();
+ int found = 0;
+ struct string_list_item *item;
+ const struct string_list *list;
+ struct config_set cs = { { 0 } };
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_unregister_usage, 0);
@@ -1531,13 +1595,47 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
usage_with_options(builtin_maintenance_unregister_usage,
options);
- config_unset.git_cmd = 1;
- strvec_pushl(&config_unset.args, "config", "--global", "--unset",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
+ if (config_file) {
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, config_file);
+ }
+ if (!(config_file
+ ? git_configset_get_string_multi(&cs, key, &list)
+ : git_config_get_string_multi(key, &list))) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ int rc;
+ char *user_config = NULL, *xdg_config = NULL;
+ if (!config_file) {
+ git_global_config(&user_config, &xdg_config);
+ config_file = user_config;
+ if (!user_config)
+ die(_("$HOME not set"));
+ }
+ rc = git_config_set_multivar_in_file_gently(
+ config_file, key, NULL, maintpath,
+ CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc &&
+ (!force || rc == CONFIG_NOTHING_SET))
+ die(_("unable to unset '%s' value of '%s'"),
+ key, maintpath);
+ } else if (!force) {
+ die(_("repository '%s' is not registered"), maintpath);
+ }
- rc = run_command(&config_unset);
+ git_configset_clear(&cs);
free(maintpath);
- return rc;
+ return 0;
}
static const char *get_frequency(enum schedule_priority schedule)
@@ -1605,11 +1703,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
if (is_available)
*is_available = 0;
- string_list_split_in_place(&list, testing, ',', -1);
+ string_list_split_in_place(&list, testing, ",", -1);
for_each_string_list_item(item, &list) {
struct string_list pair = STRING_LIST_INIT_NODUP;
- if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
+ if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
continue;
if (!strcmp(*cmd, pair.items[0].string)) {
@@ -1627,6 +1725,15 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
return 1;
}
+static int get_random_minute(void)
+{
+ /* Use a static value when under tests. */
+ if (getenv("GIT_TEST_MAINT_SCHEDULER"))
+ return 13;
+
+ return git_rand() % 60;
+}
+
static int is_launchctl_available(void)
{
const char *cmd = "launchctl";
@@ -1739,6 +1846,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
struct stat st;
const char *cmd = "launchctl";
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
preamble = "<?xml version=\"1.0\"?>\n"
@@ -1764,29 +1872,30 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
case SCHEDULE_HOURLY:
repeat = "<dict>\n"
"<key>Hour</key><integer>%d</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 23; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_DAILY:
repeat = "<dict>\n"
"<key>Day</key><integer>%d</integer>\n"
"<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 6; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_WEEKLY:
- strbuf_addstr(&plist,
- "<dict>\n"
- "<key>Day</key><integer>0</integer>\n"
- "<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
- "</dict>\n");
+ strbuf_addf(&plist,
+ "<dict>\n"
+ "<key>Day</key><integer>0</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
+ "</dict>\n",
+ minute);
break;
default:
@@ -1842,7 +1951,7 @@ static int launchctl_add_plists(void)
launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY);
}
-static int launchctl_update_schedule(int run_maintenance, int fd)
+static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return launchctl_add_plists();
@@ -1874,20 +1983,16 @@ static char *schtasks_task_name(const char *frequency)
static int schtasks_remove_task(enum schedule_priority schedule)
{
const char *cmd = "schtasks";
- int result;
- struct strvec args = STRVEC_INIT;
+ struct child_process child = CHILD_PROCESS_INIT;
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
get_schedule_cmd(&cmd, NULL);
- strvec_split(&args, cmd);
- strvec_pushl(&args, "/delete", "/tn", name, "/f", NULL);
-
- result = run_command_v_opt(args.v, 0);
-
- strvec_clear(&args);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
free(name);
- return result;
+
+ return run_command(&child);
}
static int schtasks_remove_tasks(void)
@@ -1907,6 +2012,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
struct strbuf tfilename = STRBUF_INIT;
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
@@ -1927,7 +2033,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
switch (schedule) {
case SCHEDULE_HOURLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T01:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T01:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByDay>\n"
"<DaysInterval>1</DaysInterval>\n"
@@ -1936,12 +2042,13 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Interval>PT1H</Interval>\n"
"<Duration>PT23H</Duration>\n"
"<StopAtDurationEnd>false</StopAtDurationEnd>\n"
- "</Repetition>\n");
+ "</Repetition>\n",
+ minute);
break;
case SCHEDULE_DAILY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
@@ -1953,19 +2060,21 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Saturday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
case SCHEDULE_WEEKLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
"<Sunday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
default:
@@ -1991,7 +2100,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"</Settings>\n"
"<Actions Context=\"Author\">\n"
"<Exec>\n"
- "<Command>\"%s\\git.exe\"</Command>\n"
+ "<Command>\"%s\\headless-git.exe\"</Command>\n"
"<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
"</Exec>\n"
"</Actions>\n"
@@ -2023,7 +2132,7 @@ static int schtasks_schedule_tasks(void)
schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY);
}
-static int schtasks_update_schedule(int run_maintenance, int fd)
+static int schtasks_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return schtasks_schedule_tasks();
@@ -2082,6 +2191,7 @@ static int crontab_update_schedule(int run_maintenance, int fd)
FILE *cron_list, *cron_in;
struct strbuf line = STRBUF_INIT;
struct tempfile *tmpedit = NULL;
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
strvec_split(&crontab_list.args, cmd);
@@ -2136,11 +2246,11 @@ static int crontab_update_schedule(int run_maintenance, int fd)
"# replaced in the future by a Git command.\n\n");
strbuf_addf(&line_format,
- "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
+ "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
exec_path, exec_path);
- fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly");
- fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily");
- fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly");
+ fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
+ fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
+ fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
strbuf_release(&line_format);
fprintf(cron_in, "\n%s\n", END_LINE);
@@ -2199,77 +2309,54 @@ static char *xdg_config_home_systemd(const char *filename)
return xdg_config_home_for("systemd/user", filename);
}
-static int systemd_timer_enable_unit(int enable,
- enum schedule_priority schedule)
-{
- const char *cmd = "systemctl";
- struct child_process child = CHILD_PROCESS_INIT;
- const char *frequency = get_frequency(schedule);
-
- /*
- * Disabling the systemd unit while it is already disabled makes
- * systemctl print an error.
- * Let's ignore it since it means we already are in the expected state:
- * the unit is disabled.
- *
- * On the other hand, enabling a systemd unit which is already enabled
- * produces no error.
- */
- if (!enable)
- child.no_stderr = 1;
-
- get_schedule_cmd(&cmd, NULL);
- strvec_split(&child.args, cmd);
- strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
- "--now", NULL);
- strvec_pushf(&child.args, "git-maintenance@%s.timer", frequency);
-
- if (start_command(&child))
- return error(_("failed to start systemctl"));
- if (finish_command(&child))
- /*
- * Disabling an already disabled systemd unit makes
- * systemctl fail.
- * Let's ignore this failure.
- *
- * Enabling an enabled systemd unit doesn't fail.
- */
- if (enable)
- return error(_("failed to run systemctl"));
- return 0;
-}
+#define SYSTEMD_UNIT_FORMAT "git-maintenance@%s.%s"
-static int systemd_timer_delete_unit_templates(void)
+static int systemd_timer_delete_timer_file(enum schedule_priority priority)
{
int ret = 0;
- char *filename = xdg_config_home_systemd("git-maintenance@.timer");
- if (unlink(filename) && !is_missing_file_error(errno))
- ret = error_errno(_("failed to delete '%s'"), filename);
- FREE_AND_NULL(filename);
+ const char *frequency = get_frequency(priority);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+ char *filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.service");
if (unlink(filename) && !is_missing_file_error(errno))
ret = error_errno(_("failed to delete '%s'"), filename);
free(filename);
+ free(local_timer_name);
return ret;
}
-static int systemd_timer_delete_units(void)
+static int systemd_timer_delete_service_template(void)
{
- return systemd_timer_enable_unit(0, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(0, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(0, SCHEDULE_WEEKLY) ||
- systemd_timer_delete_unit_templates();
+ int ret = 0;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+ char *filename = xdg_config_home_systemd(local_service_name);
+ if (unlink(filename) && !is_missing_file_error(errno))
+ ret = error_errno(_("failed to delete '%s'"), filename);
+
+ free(filename);
+ free(local_service_name);
+ return ret;
}
-static int systemd_timer_write_unit_templates(const char *exec_path)
+/*
+ * Write the schedule information into a git-maintenance@<schedule>.timer
+ * file using a custom minute. This timer file cannot use the templating
+ * system, so we generate a specific file for each.
+ */
+static int systemd_timer_write_timer_file(enum schedule_priority schedule,
+ int minute)
{
+ int res = -1;
char *filename;
FILE *file;
const char *unit;
+ char *schedule_pattern = NULL;
+ const char *frequency = get_frequency(schedule);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.timer");
if (safe_create_leading_directories(filename)) {
error(_("failed to create directories for '%s'"), filename);
goto error;
@@ -2278,6 +2365,23 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
if (!file)
goto error;
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ schedule_pattern = xstrfmt("*-*-* 1..23:%02d:00", minute);
+ break;
+
+ case SCHEDULE_DAILY:
+ schedule_pattern = xstrfmt("Tue..Sun *-*-* 0:%02d:00", minute);
+ break;
+
+ case SCHEDULE_WEEKLY:
+ schedule_pattern = xstrfmt("Mon 0:%02d:00", minute);
+ break;
+
+ default:
+ BUG("Unhandled schedule_priority");
+ }
+
unit = "# This file was created and is maintained by Git.\n"
"# Any edits made in this file might be replaced in the future\n"
"# by a Git command.\n"
@@ -2286,12 +2390,12 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"Description=Optimize Git repositories data\n"
"\n"
"[Timer]\n"
- "OnCalendar=%i\n"
+ "OnCalendar=%s\n"
"Persistent=true\n"
"\n"
"[Install]\n"
"WantedBy=timers.target\n";
- if (fputs(unit, file) == EOF) {
+ if (fprintf(file, unit, schedule_pattern) < 0) {
error(_("failed to write to '%s'"), filename);
fclose(file);
goto error;
@@ -2300,9 +2404,36 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
+
+ res = 0;
+
+error:
+ free(schedule_pattern);
+ free(local_timer_name);
free(filename);
+ return res;
+}
- filename = xdg_config_home_systemd("git-maintenance@.service");
+/*
+ * No matter the schedule, we use the same service and can make use of the
+ * templating system. When installing git-maintenance@<schedule>.timer,
+ * systemd will notice that git-maintenance@.service exists as a template
+ * and will use this file and insert the <schedule> into the template at
+ * the position of "%i".
+ */
+static int systemd_timer_write_service_template(const char *exec_path)
+{
+ int res = -1;
+ char *filename;
+ FILE *file;
+ const char *unit;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+
+ filename = xdg_config_home_systemd(local_service_name);
+ if (safe_create_leading_directories(filename)) {
+ error(_("failed to create directories for '%s'"), filename);
+ goto error;
+ }
file = fopen_or_warn(filename, "w");
if (!file)
goto error;
@@ -2320,7 +2451,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"LockPersonality=yes\n"
"MemoryDenyWriteExecute=yes\n"
"NoNewPrivileges=yes\n"
- "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\n"
+ "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_VSOCK\n"
"RestrictNamespaces=yes\n"
"RestrictRealtime=yes\n"
"RestrictSUIDSGID=yes\n"
@@ -2335,29 +2466,114 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
+
+ res = 0;
+
+error:
+ free(local_service_name);
free(filename);
+ return res;
+}
+
+static int systemd_timer_enable_unit(int enable,
+ enum schedule_priority schedule,
+ int minute)
+{
+ const char *cmd = "systemctl";
+ struct child_process child = CHILD_PROCESS_INIT;
+ const char *frequency = get_frequency(schedule);
+
+ /*
+ * Disabling the systemd unit while it is already disabled makes
+ * systemctl print an error.
+ * Let's ignore it since it means we already are in the expected state:
+ * the unit is disabled.
+ *
+ * On the other hand, enabling a systemd unit which is already enabled
+ * produces no error.
+ */
+ if (!enable)
+ child.no_stderr = 1;
+ else if (systemd_timer_write_timer_file(schedule, minute))
+ return -1;
+
+ get_schedule_cmd(&cmd, NULL);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
+ "--now", NULL);
+ strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ if (start_command(&child))
+ return error(_("failed to start systemctl"));
+ if (finish_command(&child))
+ /*
+ * Disabling an already disabled systemd unit makes
+ * systemctl fail.
+ * Let's ignore this failure.
+ *
+ * Enabling an enabled systemd unit doesn't fail.
+ */
+ if (enable)
+ return error(_("failed to run systemctl"));
return 0;
+}
+
+/*
+ * A previous version of Git wrote the timer units as template files.
+ * Clean these up, if they exist.
+ */
+static void systemd_timer_delete_stale_timer_templates(void)
+{
+ char *timer_template_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "timer");
+ char *filename = xdg_config_home_systemd(timer_template_name);
+
+ if (unlink(filename) && !is_missing_file_error(errno))
+ warning(_("failed to delete '%s'"), filename);
-error:
free(filename);
- systemd_timer_delete_unit_templates();
- return -1;
+ free(timer_template_name);
+}
+
+static int systemd_timer_delete_unit_files(void)
+{
+ systemd_timer_delete_stale_timer_templates();
+
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_delete_timer_file(SCHEDULE_HOURLY) |
+ systemd_timer_delete_timer_file(SCHEDULE_DAILY) |
+ systemd_timer_delete_timer_file(SCHEDULE_WEEKLY) |
+ systemd_timer_delete_service_template();
+}
+
+static int systemd_timer_delete_units(void)
+{
+ int minute = get_random_minute();
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_DAILY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, minute) |
+ systemd_timer_delete_unit_files();
}
static int systemd_timer_setup_units(void)
{
+ int minute = get_random_minute();
const char *exec_path = git_exec_path();
- int ret = systemd_timer_write_unit_templates(exec_path) ||
- systemd_timer_enable_unit(1, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(1, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(1, SCHEDULE_WEEKLY);
+ int ret = systemd_timer_write_service_template(exec_path) ||
+ systemd_timer_enable_unit(1, SCHEDULE_HOURLY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_DAILY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, minute);
+
if (ret)
systemd_timer_delete_units();
+ else
+ systemd_timer_delete_stale_timer_templates();
+
return ret;
}
-static int systemd_timer_update_schedule(int run_maintenance, int fd)
+static int systemd_timer_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return systemd_timer_setup_units();
@@ -2529,9 +2745,12 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
opts.scheduler = resolve_scheduler(opts.scheduler);
validate_scheduler(opts.scheduler);
+ if (update_background_schedule(&opts, 1))
+ die(_("failed to set up maintenance schedule"));
+
if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL))
warning(_("failed to add repo to global config"));
- return update_background_schedule(&opts, 1);
+ return 0;
}
static const char *const builtin_maintenance_stop_usage[] = {
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 491af9202d..66a7389f9f 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -1,11 +1,9 @@
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "tar.h"
-#include "builtin.h"
-#include "quote.h"
static const char builtin_get_tar_commit_id_usage[] =
"git get-tar-commit-id";
@@ -14,7 +12,7 @@ static const char builtin_get_tar_commit_id_usage[] =
#define RECORDSIZE (512)
#define HEADERSIZE (2 * RECORDSIZE)
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
+int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix)
{
char buffer[HEADERSIZE];
struct ustar_header *header = (struct ustar_header *)buffer;
@@ -24,6 +22,8 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
long len;
char *end;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 1)
usage(builtin_get_tar_commit_id_usage);
@@ -32,7 +32,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
die_errno("git get-tar-commit-id: read error");
if (n != HEADERSIZE)
die_errno("git get-tar-commit-id: EOF before reading tar header");
- if (header->typeflag[0] != 'g')
+ if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
return 1;
len = strtol(content, &end, 10);
diff --git a/builtin/grep.c b/builtin/grep.c
index e6bcdf860c..c8e33f9775 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -3,28 +3,32 @@
*
* Copyright (c) 2006 Junio C Hamano
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
-#include "blob.h"
-#include "tree.h"
-#include "commit.h"
#include "tag.h"
#include "tree-walk.h"
-#include "builtin.h"
#include "parse-options.h"
#include "string-list.h"
#include "run-command.h"
-#include "userdiff.h"
#include "grep.h"
#include "quote.h"
#include "dir.h"
#include "pathspec.h"
+#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "packfile.h"
+#include "pager.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "write-or-die.h"
static const char *grep_prefix;
@@ -283,14 +287,18 @@ static int wait_all(void)
return hit;
}
-static int grep_cmd_config(const char *var, const char *value, void *cb)
+static int grep_cmd_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int st = grep_config(var, value, cb);
- if (git_color_default_config(var, value, NULL) < 0)
+ int st = grep_config(var, value, ctx, cb);
+
+ if (git_color_config(var, value, cb) < 0)
+ st = -1;
+ else if (git_default_config(var, value, ctx, cb) < 0)
st = -1;
if (!strcmp(var, "grep.threads")) {
- num_threads = git_config_int(var, value);
+ num_threads = git_config_int(var, value, ctx->kvi);
if (num_threads < 0)
die(_("invalid number of threads specified (%d) for %s"),
num_threads, var);
@@ -458,6 +466,33 @@ static int grep_submodule(struct grep_opt *opt,
* subrepo's odbs to the in-memory alternates list.
*/
obj_read_lock();
+
+ /*
+ * NEEDSWORK: when reading a submodule, the sparsity settings in the
+ * superproject are incorrectly forgotten or misused. For example:
+ *
+ * 1. "command_requires_full_index"
+ * When this setting is turned on for `grep`, only the superproject
+ * knows it. All the submodules are read with their own configs
+ * and get prepare_repo_settings()'d. Therefore, these submodules
+ * "forget" the sparse-index feature switch. As a result, the index
+ * of these submodules are expanded unexpectedly.
+ *
+ * 2. "core_apply_sparse_checkout"
+ * When running `grep` in the superproject, this setting is
+ * populated using the superproject's configs. However, once
+ * initialized, this config is globally accessible and is read by
+ * prepare_repo_settings() for the submodules. For instance, if a
+ * submodule is using a sparse-checkout, however, the superproject
+ * is not, the result is that the config from the superproject will
+ * dictate the behavior for the submodule, making it "forget" its
+ * sparse-checkout state.
+ *
+ * 3. "core_sparse_checkout_cone"
+ * ditto.
+ *
+ * Note that this list is not exhaustive.
+ */
repo_read_gitmodules(subrepo, 0);
/*
@@ -520,8 +555,6 @@ static int grep_cache(struct grep_opt *opt,
if (repo_read_index(repo) < 0)
die(_("index file corrupt"));
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(repo->index);
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
@@ -530,8 +563,21 @@ static int grep_cache(struct grep_opt *opt,
strbuf_setlen(&name, name_base_len);
strbuf_addstr(&name, ce->name);
+ if (S_ISSPARSEDIR(ce->ce_mode)) {
+ enum object_type type;
+ struct tree_desc tree;
+ void *data;
+ unsigned long size;
+
+ data = repo_read_object_file(the_repository, &ce->oid,
+ &type, &size);
+ init_tree_desc(&tree, data, size);
- if (S_ISREG(ce->ce_mode) &&
+ hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
+ strbuf_setlen(&name, name_base_len);
+ strbuf_addstr(&name, ce->name);
+ free(data);
+ } else if (S_ISREG(ce->ce_mode) &&
match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,
S_ISDIR(ce->ce_mode) ||
S_ISGITLINK(ce->ce_mode))) {
@@ -594,7 +640,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_addstr(&name, base->buf + tn_len);
match = tree_entry_interesting(repo->index,
&entry, &name,
- 0, pathspec);
+ pathspec);
strbuf_setlen(&name, name_base_len);
if (match == all_entries_not_interesting)
@@ -614,7 +660,8 @@ 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 = repo_read_object_file(the_repository,
+ &entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid));
@@ -762,14 +809,20 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
int from_stdin;
+ const char *filename = arg;
FILE *patterns;
int lno = 0;
struct strbuf sb = STRBUF_INIT;
BUG_ON_OPT_NEG(unset);
- from_stdin = !strcmp(arg, "-");
- patterns = from_stdin ? stdin : fopen(arg, "r");
+ if (!*filename)
+ ; /* leave it as-is */
+ else
+ filename = prefix_filename_except_for_dash(grep_prefix, filename);
+
+ from_stdin = !strcmp(filename, "-");
+ patterns = from_stdin ? stdin : fopen(filename, "r");
if (!patterns)
die_errno(_("cannot open '%s'"), arg);
while (strbuf_getline(&sb, patterns) == 0) {
@@ -783,6 +836,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
if (!from_stdin)
fclose(patterns);
strbuf_release(&sb);
+ if (filename != arg)
+ free((void *)filename);
return 0;
}
@@ -874,9 +929,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("process binary files with textconv filters")),
OPT_SET_INT('r', "recursive", &opt.max_depth,
N_("search in subdirectories (default)"), -1),
- { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
- N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
- NULL, 1 },
+ OPT_INTEGER_F(0, "max-depth", &opt.max_depth,
+ N_("descend at most <n> levels"), PARSE_OPT_NONEG),
OPT_GROUP(""),
OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
N_("use extended POSIX regular expressions"),
@@ -940,7 +994,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F(0, "and", &opt, NULL,
N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback),
- OPT_BOOL(0, "or", &dummy, ""),
+ OPT_BOOL_F(0, "or", &dummy, "", PARSE_OPT_NONEG),
OPT_CALLBACK_F(0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback),
OPT_CALLBACK_F('(', NULL, &opt, NULL, "",
@@ -984,6 +1038,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION);
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
+
if (use_index && !startup_info->have_repository) {
int fallback = 0;
git_config_get_bool("grep.fallbacktonoindex", &fallback);
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index fbae878c2b..82ca6d2bfd 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -5,12 +5,18 @@
* Copyright (C) Junio C Hamano, 2005
*/
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
-#include "exec-cmd.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "write-or-die.h"
/*
* This is to create corrupt objects for debugging and as such it
@@ -27,6 +33,7 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
else
ret = write_object_file_literally(buf.buf, buf.len, type, oid,
flags);
+ close(fd);
strbuf_release(&buf);
return ret;
}
@@ -80,8 +87,9 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
int cmd_hash_object(int argc, const char **argv, const char *prefix)
{
static const char * const hash_object_usage[] = {
- N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
- "git hash-object --stdin-paths",
+ N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
+ " [--stdin [--literally]] [--] <file>..."),
+ N_("git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"),
NULL
};
const char *type = blob_type;
diff --git a/builtin/help.c b/builtin/help.c
index 6f2796f211..dc1fbe2b98 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -1,15 +1,18 @@
/*
* Builtin help command
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
#include "exec-cmd.h"
+#include "gettext.h"
+#include "pager.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
#include "config-list.h"
#include "help.h"
#include "alias.h"
+#include "setup.h"
#ifndef DEFAULT_HELP_FORMAT
#define DEFAULT_HELP_FORMAT "man"
@@ -88,7 +91,7 @@ static struct option builtin_help_options[] = {
};
static const char * const builtin_help_usage[] = {
- "git help [-a|--all] [--[no-]verbose]] [--[no-]external-commands] [--[no-]aliases]",
+ "git help [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]",
N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"),
"git help [-g|--guides]",
"git help [-c|--config]",
@@ -394,7 +397,8 @@ static int add_man_viewer_info(const char *var, const char *value)
return 0;
}
-static int git_help_config(const char *var, const char *value, void *cb)
+static int git_help_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "help.format")) {
if (!value)
@@ -417,7 +421,7 @@ static int git_help_config(const char *var, const char *value, void *cb)
if (starts_with(var, "man."))
return add_man_viewer_info(var, value);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static struct cmdnames main_cmds, other_cmds;
diff --git a/builtin/hook.c b/builtin/hook.c
index b6530d189a..5234693a94 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,13 +1,12 @@
-#include "cache.h"
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
-#include "strbuf.h"
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -28,6 +27,8 @@ static int run(int argc, const char **argv, const char *prefix)
struct option run_options[] = {
OPT_BOOL(0, "ignore-missing", &ignore_missing,
N_("silently ignore missing requested <hook-name>")),
+ OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
+ N_("file to read into hooks' stdin")),
OPT_END(),
};
int ret;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 00c756df5d..1ea87e01f2 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1,20 +1,27 @@
#include "builtin.h"
#include "config.h"
#include "delta.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "pack.h"
#include "csum-file.h"
#include "blob.h"
#include "commit.h"
-#include "tag.h"
#include "tree.h"
#include "progress.h"
#include "fsck.h"
-#include "exec-cmd.h"
+#include "strbuf.h"
#include "streaming.h"
#include "thread-utils.h"
#include "packfile.h"
-#include "object-store.h"
+#include "pack-revindex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "replace-object.h"
#include "promisor-remote.h"
+#include "setup.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -212,7 +219,8 @@ static void cleanup_thread(void)
}
static int mark_link(struct object *obj, enum object_type type,
- void *data, struct fsck_options *options)
+ void *data UNUSED,
+ struct fsck_options *options UNUSED)
{
if (!obj)
return -1;
@@ -801,7 +809,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (startup_info->have_repository) {
read_lock();
collision_test_needed =
- has_object_file_with_flags(oid, OBJECT_INFO_QUICK);
+ repo_has_object_file_with_flags(the_repository, oid,
+ OBJECT_INFO_QUICK);
read_unlock();
}
@@ -821,7 +830,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
- has_data = read_object_file(oid, &has_type, &has_size);
+ has_data = repo_read_object_file(the_repository, oid,
+ &has_type, &has_size);
read_unlock();
if (!data)
data = new_data = get_data_from_pack(obj_entry);
@@ -1154,6 +1164,7 @@ static void parse_pack_objects(unsigned char *hash)
struct ofs_delta_entry *ofs_delta = ofs_deltas;
struct object_id ref_delta_oid;
struct stat st;
+ git_hash_ctx tmp_ctx;
if (verbose)
progress = start_progress(
@@ -1190,7 +1201,9 @@ static void parse_pack_objects(unsigned char *hash)
/* Check pack integrity */
flush();
- the_hash_algo->final_fn(hash, &input_ctx);
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
+ the_hash_algo->final_fn(hash, &tmp_ctx);
if (!hasheq(fill(the_hash_algo->rawsz), hash))
die(_("pack is corrupted (SHA1 mismatch)"));
use(the_hash_algo->rawsz);
@@ -1390,7 +1403,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 (repo_has_promisor_remote(the_repository)) {
/*
* Prefetch the delta bases.
*/
@@ -1416,7 +1429,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- data = read_object_file(&d->oid, &type, &size);
+ data = repo_read_object_file(the_repository, &d->oid, &type,
+ &size);
if (!data)
continue;
@@ -1570,18 +1584,19 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
strbuf_release(&pack_name);
}
-static int git_index_pack_config(const char *k, const char *v, void *cb)
+static int git_index_pack_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
struct pack_idx_option *opts = cb;
if (!strcmp(k, "pack.indexversion")) {
- opts->version = git_config_int(k, v);
+ opts->version = git_config_int(k, v, ctx->kvi);
if (opts->version > 2)
die(_("bad pack.indexVersion=%"PRIu32), opts->version);
return 0;
}
if (!strcmp(k, "pack.threads")) {
- nr_threads = git_config_int(k, v);
+ nr_threads = git_config_int(k, v, ctx->kvi);
if (nr_threads < 0)
die(_("invalid number of threads specified (%d)"),
nr_threads);
@@ -1597,7 +1612,7 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
else
opts->flags &= ~WRITE_REV;
}
- return git_default_config(k, v, cb);
+ return git_default_config(k, v, ctx, cb);
}
static int cmp_uint32(const void *a_, const void *b_)
@@ -1741,16 +1756,17 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(index_pack_usage);
- read_replace_refs = 0;
+ disable_replace_refs();
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
+ opts.flags |= WRITE_REV;
git_config(git_index_pack_config, &opts);
if (prefix && chdir(prefix))
die(_("Cannot come back to cwd"));
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- rev_index = 1;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ rev_index = 0;
else
rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 546f9c595e..0170469b84 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -3,476 +3,17 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
-#include "config.h"
-#include "refs.h"
#include "builtin.h"
-#include "exec-cmd.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
#include "parse-options.h"
-#include "worktree.h"
-
-#ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
-#endif
-
-#ifdef NO_TRUSTABLE_FILEMODE
-#define TEST_FILEMODE 0
-#else
-#define TEST_FILEMODE 1
-#endif
-
-#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
-
-static int init_is_bare_repository = 0;
-static int init_shared_repository = -1;
-
-static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
- DIR *dir)
-{
- size_t path_baselen = path->len;
- size_t template_baselen = template_path->len;
- struct dirent *de;
-
- /* Note: if ".git/hooks" file exists in the repository being
- * re-initialized, /etc/core-git/templates/hooks/update would
- * cause "git init" to fail here. I think this is sane but
- * it means that the set of templates we ship by default, along
- * with the way the namespace under .git/ is organized, should
- * be really carefully chosen.
- */
- safe_create_dir(path->buf, 1);
- while ((de = readdir(dir)) != NULL) {
- struct stat st_git, st_template;
- int exists = 0;
-
- strbuf_setlen(path, path_baselen);
- strbuf_setlen(template_path, template_baselen);
-
- if (de->d_name[0] == '.')
- continue;
- strbuf_addstr(path, de->d_name);
- strbuf_addstr(template_path, de->d_name);
- if (lstat(path->buf, &st_git)) {
- if (errno != ENOENT)
- die_errno(_("cannot stat '%s'"), path->buf);
- }
- else
- exists = 1;
-
- if (lstat(template_path->buf, &st_template))
- die_errno(_("cannot stat template '%s'"), template_path->buf);
-
- if (S_ISDIR(st_template.st_mode)) {
- DIR *subdir = opendir(template_path->buf);
- if (!subdir)
- die_errno(_("cannot opendir '%s'"), template_path->buf);
- strbuf_addch(path, '/');
- strbuf_addch(template_path, '/');
- copy_templates_1(path, template_path, subdir);
- closedir(subdir);
- }
- else if (exists)
- continue;
- else if (S_ISLNK(st_template.st_mode)) {
- struct strbuf lnk = STRBUF_INIT;
- if (strbuf_readlink(&lnk, template_path->buf,
- st_template.st_size) < 0)
- die_errno(_("cannot readlink '%s'"), template_path->buf);
- if (symlink(lnk.buf, path->buf))
- die_errno(_("cannot symlink '%s' '%s'"),
- lnk.buf, path->buf);
- strbuf_release(&lnk);
- }
- else if (S_ISREG(st_template.st_mode)) {
- if (copy_file(path->buf, template_path->buf, st_template.st_mode))
- die_errno(_("cannot copy '%s' to '%s'"),
- template_path->buf, path->buf);
- }
- else
- error(_("ignoring template %s"), template_path->buf);
- }
-}
-
-static void copy_templates(const char *template_dir, const char *init_template_dir)
-{
- struct strbuf path = STRBUF_INIT;
- struct strbuf template_path = STRBUF_INIT;
- size_t template_len;
- struct repository_format template_format = REPOSITORY_FORMAT_INIT;
- struct strbuf err = STRBUF_INIT;
- DIR *dir;
- char *to_free = NULL;
-
- if (!template_dir)
- template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
- if (!template_dir)
- template_dir = init_template_dir;
- if (!template_dir)
- template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
- if (!template_dir[0]) {
- free(to_free);
- return;
- }
-
- strbuf_addstr(&template_path, template_dir);
- strbuf_complete(&template_path, '/');
- template_len = template_path.len;
-
- dir = opendir(template_path.buf);
- if (!dir) {
- warning(_("templates not found in %s"), template_dir);
- goto free_return;
- }
-
- /* Make sure that template is from the correct vintage */
- strbuf_addstr(&template_path, "config");
- read_repository_format(&template_format, template_path.buf);
- strbuf_setlen(&template_path, template_len);
-
- /*
- * No mention of version at all is OK, but anything else should be
- * verified.
- */
- if (template_format.version >= 0 &&
- verify_repository_format(&template_format, &err) < 0) {
- warning(_("not copying templates from '%s': %s"),
- template_dir, err.buf);
- strbuf_release(&err);
- goto close_free_return;
- }
-
- strbuf_addstr(&path, get_git_common_dir());
- strbuf_complete(&path, '/');
- copy_templates_1(&path, &template_path, dir);
-close_free_return:
- closedir(dir);
-free_return:
- free(to_free);
- strbuf_release(&path);
- strbuf_release(&template_path);
- clear_repository_format(&template_format);
-}
-
-/*
- * If the git_dir is not directly inside the working tree, then git will not
- * find it by default, and we need to set the worktree explicitly.
- */
-static int needs_work_tree_config(const char *git_dir, const char *work_tree)
-{
- if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
- return 0;
- if (skip_prefix(git_dir, work_tree, &git_dir) &&
- !strcmp(git_dir, "/.git"))
- return 0;
- return 1;
-}
-
-void initialize_repository_version(int hash_algo, int reinit)
-{
- char repo_version_string[10];
- int repo_version = GIT_REPO_VERSION;
-
- if (hash_algo != GIT_HASH_SHA1)
- repo_version = GIT_REPO_VERSION_READ;
-
- /* This forces creation of new config file */
- xsnprintf(repo_version_string, sizeof(repo_version_string),
- "%d", repo_version);
- git_config_set("core.repositoryformatversion", repo_version_string);
-
- if (hash_algo != GIT_HASH_SHA1)
- git_config_set("extensions.objectformat",
- hash_algos[hash_algo].name);
- else if (reinit)
- git_config_set_gently("extensions.objectformat", NULL);
-}
-
-static int create_default_files(const char *template_path,
- const char *original_git_dir,
- const char *initial_branch,
- const struct repository_format *fmt,
- int quiet)
-{
- struct stat st1;
- struct strbuf buf = STRBUF_INIT;
- char *path;
- char junk[2];
- int reinit;
- int filemode;
- struct strbuf err = STRBUF_INIT;
- const char *init_template_dir = NULL;
- const char *work_tree = get_git_work_tree();
-
- /*
- * First copy the templates -- we might have the default
- * config file there, in which case we would want to read
- * from it after installing.
- *
- * Before reading that config, we also need to clear out any cached
- * values (since we've just potentially changed what's available on
- * disk).
- */
- git_config_get_pathname("init.templatedir", &init_template_dir);
- copy_templates(template_path, init_template_dir);
- free((char *)init_template_dir);
- git_config_clear();
- reset_shared_repository();
- git_config(git_default_config, NULL);
-
- /*
- * We must make sure command-line options continue to override any
- * values we might have just re-read from the config.
- */
- is_bare_repository_cfg = init_is_bare_repository || !work_tree;
- if (init_shared_repository != -1)
- set_shared_repository(init_shared_repository);
-
- /*
- * We would have created the above under user's umask -- under
- * shared-repository settings, we would need to fix them up.
- */
- if (get_shared_repository()) {
- adjust_shared_perm(get_git_dir());
- }
-
- /*
- * We need to create a "refs" dir in any case so that older
- * versions of git can tell that this is a repository.
- */
- safe_create_dir(git_path("refs"), 1);
- adjust_shared_perm(git_path("refs"));
-
- if (refs_init_db(&err))
- die("failed to set up refs db: %s", err.buf);
-
- /*
- * Point the HEAD symref to the initial branch with if HEAD does
- * not yet exist.
- */
- path = git_path_buf(&buf, "HEAD");
- reinit = (!access(path, R_OK)
- || readlink(path, junk, sizeof(junk)-1) != -1);
- if (!reinit) {
- char *ref;
-
- if (!initial_branch)
- initial_branch = git_default_branch_name(quiet);
-
- ref = xstrfmt("refs/heads/%s", initial_branch);
- if (check_refname_format(ref, 0) < 0)
- die(_("invalid initial branch name: '%s'"),
- initial_branch);
-
- if (create_symref("HEAD", ref, NULL) < 0)
- exit(1);
- free(ref);
- }
-
- initialize_repository_version(fmt->hash_algo, 0);
-
- /* Check filemode trustability */
- path = git_path_buf(&buf, "config");
- filemode = TEST_FILEMODE;
- if (TEST_FILEMODE && !lstat(path, &st1)) {
- struct stat st2;
- filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
- !lstat(path, &st2) &&
- st1.st_mode != st2.st_mode &&
- !chmod(path, st1.st_mode));
- if (filemode && !reinit && (st1.st_mode & S_IXUSR))
- filemode = 0;
- }
- git_config_set("core.filemode", filemode ? "true" : "false");
-
- if (is_bare_repository())
- git_config_set("core.bare", "true");
- else {
- git_config_set("core.bare", "false");
- /* allow template config file to override the default */
- if (log_all_ref_updates == LOG_REFS_UNSET)
- git_config_set("core.logallrefupdates", "true");
- if (needs_work_tree_config(original_git_dir, work_tree))
- git_config_set("core.worktree", work_tree);
- }
-
- if (!reinit) {
- /* Check if symlink is supported in the work tree */
- path = git_path_buf(&buf, "tXXXXXX");
- if (!close(xmkstemp(path)) &&
- !unlink(path) &&
- !symlink("testing", path) &&
- !lstat(path, &st1) &&
- S_ISLNK(st1.st_mode))
- unlink(path); /* good */
- else
- git_config_set("core.symlinks", "false");
-
- /* Check if the filesystem is case-insensitive */
- path = git_path_buf(&buf, "CoNfIg");
- if (!access(path, F_OK))
- git_config_set("core.ignorecase", "true");
- probe_utf8_pathname_composition();
- }
-
- strbuf_release(&buf);
- return reinit;
-}
-
-static void create_object_directory(void)
-{
- struct strbuf path = STRBUF_INIT;
- size_t baselen;
-
- strbuf_addstr(&path, get_object_directory());
- baselen = path.len;
-
- safe_create_dir(path.buf, 1);
-
- strbuf_setlen(&path, baselen);
- strbuf_addstr(&path, "/pack");
- safe_create_dir(path.buf, 1);
-
- strbuf_setlen(&path, baselen);
- strbuf_addstr(&path, "/info");
- safe_create_dir(path.buf, 1);
-
- strbuf_release(&path);
-}
-
-static void separate_git_dir(const char *git_dir, const char *git_link)
-{
- struct stat st;
-
- if (!stat(git_link, &st)) {
- const char *src;
-
- if (S_ISREG(st.st_mode))
- src = read_gitfile(git_link);
- else if (S_ISDIR(st.st_mode))
- src = git_link;
- else
- die(_("unable to handle file type %d"), (int)st.st_mode);
-
- if (rename(src, git_dir))
- die_errno(_("unable to move %s to %s"), src, git_dir);
- repair_worktrees(NULL, NULL);
- }
-
- write_file(git_link, "gitdir: %s", git_dir);
-}
-
-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
-{
- const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
- /*
- * If we already have an initialized repo, don't allow the user to
- * specify a different algorithm, as that could cause corruption.
- * Otherwise, if the user has specified one on the command line, use it.
- */
- if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
- die(_("attempt to reinitialize repository with different hash"));
- else if (hash != GIT_HASH_UNKNOWN)
- repo_fmt->hash_algo = hash;
- else if (env) {
- int env_algo = hash_algo_by_name(env);
- if (env_algo == GIT_HASH_UNKNOWN)
- die(_("unknown hash algorithm '%s'"), env);
- repo_fmt->hash_algo = env_algo;
- }
-}
-
-int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, int hash, const char *initial_branch,
- unsigned int flags)
-{
- int reinit;
- int exist_ok = flags & INIT_DB_EXIST_OK;
- char *original_git_dir = real_pathdup(git_dir, 1);
- struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
-
- if (real_git_dir) {
- struct stat st;
-
- if (!exist_ok && !stat(git_dir, &st))
- die(_("%s already exists"), git_dir);
-
- if (!exist_ok && !stat(real_git_dir, &st))
- die(_("%s already exists"), real_git_dir);
-
- set_git_dir(real_git_dir, 1);
- git_dir = get_git_dir();
- separate_git_dir(git_dir, original_git_dir);
- }
- else {
- set_git_dir(git_dir, 1);
- git_dir = get_git_dir();
- }
- startup_info->have_repository = 1;
-
- /* Ensure `core.hidedotfiles` is processed */
- git_config(platform_core_config, NULL);
-
- safe_create_dir(git_dir, 0);
-
- init_is_bare_repository = is_bare_repository();
-
- /* Check to see if the repository version is right.
- * Note that a newly created repository does not have
- * config file, so this will not fail. What we are catching
- * is an attempt to reinitialize new repository with an old tool.
- */
- check_repository_format(&repo_fmt);
-
- validate_hash_algorithm(&repo_fmt, hash);
-
- reinit = create_default_files(template_dir, original_git_dir,
- initial_branch, &repo_fmt,
- flags & INIT_DB_QUIET);
- if (reinit && initial_branch)
- warning(_("re-init: ignored --initial-branch=%s"),
- initial_branch);
-
- create_object_directory();
-
- if (get_shared_repository()) {
- char buf[10];
- /* We do not spell "group" and such, so that
- * the configuration can be read by older version
- * of git. Note, we use octal numbers for new share modes,
- * and compatibility values for PERM_GROUP and
- * PERM_EVERYBODY.
- */
- if (get_shared_repository() < 0)
- /* force to the mode value */
- xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
- else if (get_shared_repository() == PERM_GROUP)
- xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
- else if (get_shared_repository() == PERM_EVERYBODY)
- xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
- else
- BUG("invalid value for shared_repository");
- git_config_set("core.sharedrepository", buf);
- git_config_set("receive.denyNonFastforwards", "true");
- }
-
- if (!(flags & INIT_DB_QUIET)) {
- int len = strlen(git_dir);
-
- if (reinit)
- printf(get_shared_repository()
- ? _("Reinitialized existing shared Git repository in %s%s\n")
- : _("Reinitialized existing Git repository in %s%s\n"),
- git_dir, len && git_dir[len-1] != '/' ? "/" : "");
- else
- printf(get_shared_repository()
- ? _("Initialized empty shared Git repository in %s%s\n")
- : _("Initialized empty Git repository in %s%s\n"),
- git_dir, len && git_dir[len-1] != '/' ? "/" : "");
- }
-
- free(original_git_dir);
- return 0;
-}
+#include "path.h"
+#include "refs.h"
+#include "repository.h"
+#include "setup.h"
+#include "strbuf.h"
static int guess_repository_type(const char *git_dir)
{
@@ -515,7 +56,11 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
}
static const char *const init_db_usage[] = {
- N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
+ N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
+ " [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+ " [--ref-format=<format>]\n"
+ " [-b <branch-name> | --initial-branch=<branch-name>]\n"
+ " [--shared[=<permissions>]] [<directory>]"),
NULL
};
@@ -533,8 +78,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *template_dir = NULL;
unsigned int flags = 0;
const char *object_format = NULL;
+ const char *ref_format = NULL;
const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
+ unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+ int init_shared_repository = -1;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
N_("directory from which templates will be used")),
@@ -551,6 +99,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
N_("override the name of the initial branch")),
OPT_STRING(0, "object-format", &object_format, N_("hash"),
N_("specify the hash algorithm to use")),
+ OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_END()
};
@@ -614,6 +164,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
die(_("unknown hash algorithm '%s'"), object_format);
}
+ if (ref_format) {
+ ref_storage_format = ref_storage_format_by_name(ref_format);
+ if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_format);
+ }
+
if (init_shared_repository != -1)
set_shared_repository(init_shared_repository);
@@ -692,5 +248,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
flags |= INIT_DB_EXIST_OK;
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
- initial_branch, flags);
+ ref_storage_format, initial_branch,
+ init_shared_repository, flags);
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 84748eafc0..033bd1556c 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -5,15 +5,17 @@
*
*/
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
#include "trailer.h"
#include "config.h"
static const char * const git_interpret_trailers_usage[] = {
- N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
+ N_("git interpret-trailers [--in-place] [--trim-empty]\n"
+ " [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
+ " [--parse] [<file>...]"),
NULL
};
@@ -22,21 +24,24 @@ static enum trailer_if_exists if_exists;
static enum trailer_if_missing if_missing;
static int option_parse_where(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_where(&where, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_where(opt->value, arg);
}
static int option_parse_if_exists(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_exists(&if_exists, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_exists(opt->value, arg);
}
static int option_parse_if_missing(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_missing(&if_missing, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_missing(opt->value, arg);
}
static void new_trailers_clear(struct list_head *trailers)
@@ -95,19 +100,19 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
- OPT_CALLBACK(0, "where", NULL, N_("action"),
+ OPT_CALLBACK(0, "where", &where, N_("placement"),
N_("where to place the new trailer"), option_parse_where),
- OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
N_("action if trailer already exists"), option_parse_if_exists),
- OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
N_("action if trailer is missing"), option_parse_if_missing),
OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
- OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
- OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
- OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("set parsing options"),
+ OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
+ OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
+ OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
- OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
+ OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
N_("trailer(s) to add"), option_parse_trailer),
OPT_END()
diff --git a/builtin/log.c b/builtin/log.c
index ee19dc5d45..db1808d7c1 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -4,11 +4,17 @@
* (C) Copyright 2006 Linus Torvalds
* 2006 Junio Hamano
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#include "git-compat-util.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
@@ -16,10 +22,10 @@
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
+#include "oid-array.h"
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
-#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
#include "string-list.h"
@@ -29,13 +35,14 @@
#include "streaming.h"
#include "version.h"
#include "mailmap.h"
-#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
#include "repository.h"
#include "commit-reach.h"
#include "range-diff.h"
#include "tmp-objdir.h"
+#include "tree.h"
+#include "write-or-die.h"
#define MAIL_DEFAULT_WRAP 72
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
@@ -53,9 +60,11 @@ static int decoration_style;
static int decoration_given;
static int use_mailmap_config = 1;
static unsigned int force_in_body_from;
+static int stdout_mboxrd;
static const char *fmt_patch_subject_prefix = "PATCH";
static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
static const char *fmt_pretty;
+static int format_no_prefix;
static const char * const builtin_log_usage[] = {
N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
@@ -107,16 +116,19 @@ static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
-static int clear_decorations_callback(const struct option *opt,
- const char *arg, int unset)
+static int clear_decorations_callback(const struct option *opt UNUSED,
+ const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
string_list_clear(&decorate_refs_include, 0);
string_list_clear(&decorate_refs_exclude, 0);
use_default_decoration_filter = 0;
return 0;
}
-static int decorate_callback(const struct option *opt, const char *arg, int unset)
+static int decorate_callback(const struct option *opt UNUSED, const char *arg,
+ int unset)
{
if (unset)
decoration_style = 0;
@@ -162,16 +174,15 @@ static void cmd_log_init_defaults(struct rev_info *rev)
if (default_follow)
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
+ init_diffstat_widths(&rev->diffopt);
rev->diffopt.flags.recursive = 1;
- rev->diffopt.stat_width = -1; /* use full terminal width */
- rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
+ rev->diffopt.flags.allow_textconv = 1;
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->patch_name_max = fmt_patch_name_max;
rev->show_signature = default_show_signature;
rev->encode_email_headers = default_encode_email_headers;
- rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
parse_date_format(default_date_mode, &rev->date_mode);
@@ -182,10 +193,10 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
int i;
char *value = NULL;
struct string_list *include = decoration_filter->include_ref_pattern;
- const struct string_list *config_exclude =
- git_config_get_value_multi("log.excludeDecoration");
+ const struct string_list *config_exclude;
- if (config_exclude) {
+ if (!git_config_get_string_multi("log.excludeDecoration",
+ &config_exclude)) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
string_list_append(decoration_filter->exclude_ref_config_pattern,
@@ -436,7 +447,7 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
-static void early_output(int signal)
+static void early_output(int signal UNUSED)
{
show_early_output = log_show_early;
}
@@ -538,7 +549,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
rev->diffopt.flags.check_failed) {
return 02;
}
- return diff_result_code(&rev->diffopt, 0);
+ return diff_result_code(&rev->diffopt);
}
static int cmd_log_walk(struct rev_info *rev)
@@ -552,7 +563,8 @@ static int cmd_log_walk(struct rev_info *rev)
return retval;
}
-static int git_log_config(const char *var, const char *value, void *cb)
+static int git_log_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
const char *slot_name;
@@ -561,7 +573,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.subjectprefix"))
return git_config_string(&fmt_patch_subject_prefix, var, value);
if (!strcmp(var, "format.filenamemaxlength")) {
- fmt_patch_name_max = git_config_int(var, value);
+ fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "format.encodeemailheaders")) {
@@ -580,8 +592,11 @@ static int git_log_config(const char *var, const char *value, void *cb)
decoration_style = 0; /* maybe warn? */
return 0;
}
- if (!strcmp(var, "log.diffmerges"))
+ if (!strcmp(var, "log.diffmerges")) {
+ if (!value)
+ return config_error_nonbool(var);
return diff_merges_config(value);
+ }
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
@@ -601,9 +616,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
return 0;
}
- if (git_gpg_config(var, value, cb) < 0)
- return -1;
- return git_diff_ui_config(var, value, cb);
+ return git_diff_ui_config(var, value, ctx, cb);
}
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
@@ -675,7 +688,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
- char *buf = read_object_file(oid, &type, &size);
+ char *buf = repo_read_object_file(the_repository, oid, &type, &size);
int offset = 0;
if (!buf)
@@ -708,8 +721,7 @@ static int show_tree_object(const struct object_id *oid UNUSED,
return 0;
}
-static void show_setup_revisions_tweak(struct rev_info *rev,
- struct setup_revision_opt *opt)
+static void show_setup_revisions_tweak(struct rev_info *rev)
{
if (rev->first_parent_only)
diff_merges_default_to_first_parent(rev);
@@ -852,11 +864,10 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
return cmd_log_deinit(cmd_log_walk(&rev), &rev);
}
-static void log_setup_revisions_tweak(struct rev_info *rev,
- struct setup_revision_opt *opt)
+static void log_setup_revisions_tweak(struct rev_info *rev)
{
if (rev->diffopt.flags.default_follow_renames &&
- rev->prune_data.nr == 1)
+ diff_check_follow_pathspec(&rev->prune_data, 0))
rev->diffopt.flags.follow_renames = 1;
if (rev->first_parent_only)
@@ -969,7 +980,8 @@ static enum cover_from_description parse_cover_from_description(const char *arg)
die(_("%s: invalid cover from description mode"), arg);
}
-static int git_format_config(const char *var, const char *value, void *cb)
+static int git_format_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "format.headers")) {
if (!value)
@@ -1007,6 +1019,8 @@ static int git_format_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.attach")) {
if (value && *value)
default_attach = xstrdup(value);
+ else if (value && !*value)
+ FREE_AND_NULL(default_attach);
else
default_attach = xstrdup(git_version_string);
return 0;
@@ -1078,8 +1092,25 @@ static int git_format_config(const char *var, const char *value, void *cb)
cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
+ if (!strcmp(var, "format.mboxrd")) {
+ stdout_mboxrd = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "format.noprefix")) {
+ format_no_prefix = 1;
+ return 0;
+ }
+
+ /*
+ * ignore some porcelain config which would otherwise be parsed by
+ * git_diff_ui_config(), via git_log_config(); we can't just avoid
+ * diff_ui_config completely, because we do care about some ui options
+ * like color.
+ */
+ if (!strcmp(var, "diff.noprefix"))
+ return 0;
- return git_log_config(var, value, cb);
+ return git_log_config(var, value, ctx, cb);
}
static const char *output_directory = NULL;
@@ -1198,7 +1229,8 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
+ if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid,
+ &full_ref, 0) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
@@ -1224,7 +1256,15 @@ static void show_diffstat(struct rev_info *rev,
fprintf(rev->diffopt.file, "\n");
}
+static void read_desc_file(struct strbuf *buf, const char *desc_file)
+{
+ if (strbuf_read_file(buf, desc_file, 0) < 0)
+ die_errno(_("unable to read branch description file '%s'"),
+ desc_file);
+}
+
static void prepare_cover_text(struct pretty_print_context *pp,
+ const char *description_file,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
@@ -1238,7 +1278,9 @@ static void prepare_cover_text(struct pretty_print_context *pp,
if (cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
- if (branch_name && *branch_name)
+ if (description_file && *description_file)
+ read_desc_file(&description_sb, description_file);
+ else if (branch_name && *branch_name)
read_branch_desc(&description_sb, branch_name);
if (!description_sb.len)
goto do_pp;
@@ -1284,6 +1326,7 @@ static void get_notes_args(struct strvec *arg, struct rev_info *rev)
static void make_cover_letter(struct rev_info *rev, int use_separate_file,
struct commit *origin,
int nr, struct commit **list,
+ const char *description_file,
const char *branch_name,
int quiet)
{
@@ -1308,10 +1351,11 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
for (i = 0; !need_8bit_cte && i < nr; i++) {
- const char *buf = get_commit_buffer(list[i], NULL);
+ const char *buf = repo_get_commit_buffer(the_repository,
+ list[i], NULL);
if (has_non_ascii(buf))
need_8bit_cte = 1;
- unuse_commit_buffer(list[i], buf);
+ repo_unuse_commit_buffer(the_repository, list[i], buf);
}
if (!branch_name)
@@ -1321,8 +1365,10 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
pp.date_mode.type = DATE_RFC2822;
pp.rev = rev;
pp.print_email_subject = 1;
+ pp.encode_email_headers = rev->encode_email_headers;
pp_user_info(&pp, NULL, &sb, committer, encoding);
- prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
+ prepare_cover_text(&pp, description_file, branch_name, &sb,
+ encoding, need_8bit_cte);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
strbuf_release(&sb);
@@ -1334,6 +1380,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
log.in2 = 4;
log.file = rev->diffopt.file;
log.groups = SHORTLOG_GROUP_AUTHOR;
+ shortlog_finish_setup(&log);
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
@@ -1363,7 +1410,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
.other_arg = &other_arg
};
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.file = rev->diffopt.file;
opts.use_color = rev->diffopt.use_color;
diff_setup_done(&opts);
@@ -1374,7 +1421,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
}
}
-static const char *clean_message_id(const char *msg_id)
+static char *clean_message_id(const char *msg_id)
{
char ch;
const char *a, *z, *m;
@@ -1392,7 +1439,7 @@ static const char *clean_message_id(const char *msg_id)
if (!z)
die(_("insane in-reply-to: %s"), msg_id);
if (++z == m)
- return a;
+ return xstrdup(a);
return xmemdupz(a, z - a);
}
@@ -1437,19 +1484,16 @@ static int subject_prefix = 0;
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct strbuf *sprefix;
+
BUG_ON_OPT_NEG(unset);
+ sprefix = opt->value;
subject_prefix = 1;
- ((struct rev_info *)opt->value)->subject_prefix = arg;
+ strbuf_reset(sprefix);
+ strbuf_addstr(sprefix, arg);
return 0;
}
-static int rfc_callback(const struct option *opt, const char *arg, int unset)
-{
- BUG_ON_OPT_NEG(unset);
- BUG_ON_OPT_ARG(arg);
- return subject_prefix_callback(opt, "RFC PATCH", unset);
-}
-
static int numbered_cmdline_opt = 0;
static int numbered_callback(const struct option *opt, const char *arg,
@@ -1524,7 +1568,8 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int header_callback(const struct option *opt, const char *arg, int unset)
+static int header_callback(const struct option *opt UNUSED, const char *arg,
+ int unset)
{
if (unset) {
string_list_clear(&extra_hdr, 0);
@@ -1536,24 +1581,6 @@ static int header_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int to_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_to, 0);
- else
- string_list_append(&extra_to, arg);
- return 0;
-}
-
-static int cc_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_cc, 0);
- else
- string_list_append(&extra_cc, arg);
- return 0;
-}
-
static int from_callback(const struct option *opt, const char *arg, int unset)
{
char **from = opt->value;
@@ -1635,14 +1662,16 @@ static struct commit *get_base_commit(const char *base_commit,
struct commit *commit;
struct object_id oid;
- if (get_oid(upstream, &oid)) {
+ if (repo_get_oid(the_repository, upstream, &oid)) {
if (die_on_failure)
die(_("failed to resolve '%s' as a valid ref"), upstream);
else
return NULL;
}
commit = lookup_commit_or_die(&oid, "upstream base");
- base_list = get_merge_bases_many(commit, total, list);
+ base_list = repo_get_merge_bases_many(the_repository,
+ commit, total,
+ list);
/* There should be one and only one merge base. */
if (!base_list || base_list->next) {
if (die_on_failure) {
@@ -1676,7 +1705,9 @@ static struct commit *get_base_commit(const char *base_commit,
while (rev_nr > 1) {
for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base;
- merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
+ merge_base = repo_get_merge_bases(the_repository,
+ rev[2 * i],
+ rev[2 * i + 1]);
if (!merge_base || merge_base->next) {
if (die_on_failure) {
die(_("failed to find exact merge base"));
@@ -1694,7 +1725,7 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!in_merge_bases(base, rev[0])) {
+ if (!repo_in_merge_bases(the_repository, base, rev[0])) {
if (die_on_failure) {
die(_("base commit should be the ancestor of revision list"));
} else {
@@ -1763,7 +1794,7 @@ static void prepare_bases(struct base_tree_info *bases,
struct object_id *patch_id;
if (*commit_base_at(&commit_base, commit))
continue;
- if (commit_patch_id(commit, &diffopt, &oid, 0, 1))
+ if (commit_patch_id(commit, &diffopt, &oid, 0))
die(_("cannot get patch id"));
ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
patch_id = bases->patch_id + bases->nr_patch_id;
@@ -1858,6 +1889,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int quiet = 0;
const char *reroll_count = NULL;
char *cover_from_description_arg = NULL;
+ char *description_file = NULL;
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
@@ -1870,7 +1902,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
+ struct strbuf sprefix = STRBUF_INIT;
int creation_factor = -1;
+ int rfc = 0;
const struct option builtin_format_patch_options[] = {
OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
@@ -1894,13 +1928,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("mark the series as Nth re-roll")),
OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
N_("max length of output filename")),
- OPT_CALLBACK_F(0, "rfc", &rev, NULL,
- N_("use [RFC PATCH] instead of [PATCH]"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
+ OPT_BOOL(0, "rfc", &rfc, N_("use [RFC PATCH] instead of [PATCH]")),
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")),
- OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
+ OPT_FILENAME(0, "description-file", &description_file,
+ N_("use branch description from file")),
+ OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
@@ -1921,8 +1955,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_GROUP(N_("Messaging")),
OPT_CALLBACK(0, "add-header", NULL, N_("header"),
N_("add email header"), header_callback),
- OPT_CALLBACK(0, "to", NULL, N_("email"), N_("add To: header"), to_callback),
- OPT_CALLBACK(0, "cc", NULL, N_("email"), N_("add Cc: header"), cc_callback),
+ OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
+ OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
OPT_CALLBACK_F(0, "from", &from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
@@ -1980,11 +2014,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.max_parents = 1;
rev.diffopt.flags.recursive = 1;
rev.diffopt.no_free = 1;
- rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
+ strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
+ if (format_no_prefix)
+ diff_set_noprefix(&rev.diffopt);
+
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
@@ -2009,15 +2046,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (cover_from_description_arg)
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
- if (reroll_count) {
- struct strbuf sprefix = STRBUF_INIT;
+ if (rfc)
+ strbuf_insertstr(&sprefix, 0, "RFC ");
- strbuf_addf(&sprefix, "%s v%s",
- rev.subject_prefix, reroll_count);
+ if (reroll_count) {
+ strbuf_addf(&sprefix, " v%s", reroll_count);
rev.reroll_count = reroll_count;
- rev.subject_prefix = strbuf_detach(&sprefix, NULL);
}
+ rev.subject_prefix = sprefix.buf;
+
for (i = 0; i < extra_hdr.nr; i++) {
strbuf_addstr(&buf, extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
@@ -2091,6 +2129,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
/* Always generate a patch */
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+ rev.always_show_header = 1;
rev.zero_commit = zero_commit;
rev.patch_name_max = fmt_patch_name_max;
@@ -2105,6 +2144,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diffopt.close_file, "--output",
!!output_directory, "--output-directory");
+ if (use_stdout && stdout_mboxrd)
+ rev.commit_format = CMIT_FMT_MBOXRD;
+
if (use_stdout) {
setup_pager();
} else if (!rev.diffopt.close_file) {
@@ -2268,11 +2310,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (in_reply_to || thread || cover_letter) {
rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
- string_list_init_nodup(rev.ref_message_ids);
+ string_list_init_dup(rev.ref_message_ids);
}
if (in_reply_to) {
- const char *msgid = clean_message_id(in_reply_to);
- string_list_append(rev.ref_message_ids, msgid);
+ char *msgid = clean_message_id(in_reply_to);
+ string_list_append_nodup(rev.ref_message_ids, msgid);
}
rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
@@ -2280,7 +2322,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, !!output_directory,
- origin, nr, list, branch_name, quiet);
+ origin, nr, list, description_file, branch_name, quiet);
print_bases(&bases, rev.diffopt.file);
print_signature(rev.diffopt.file);
total++;
@@ -2328,8 +2370,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
else
- string_list_append(rev.ref_message_ids,
- rev.message_id);
+ string_list_append_nodup(rev.ref_message_ids,
+ rev.message_id);
}
gen_message_id(&rev, oid_to_hex(&commit->object.oid));
}
@@ -2376,7 +2418,9 @@ done:
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
+ strbuf_release(&sprefix);
free(to_free);
+ free(rev.message_id);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
free(rev.ref_message_ids);
@@ -2386,7 +2430,7 @@ done:
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
struct object_id oid;
- if (get_oid(arg, &oid) == 0) {
+ if (repo_get_oid(the_repository, arg, &oid) == 0) {
struct commit *commit = lookup_commit_reference(the_repository,
&oid);
if (commit) {
@@ -2408,12 +2452,12 @@ static void print_commit(char sign, struct commit *commit, int verbose,
{
if (!verbose) {
fprintf(file, "%c %s\n", sign,
- find_unique_abbrev(&commit->object.oid, abbrev));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev));
} else {
struct strbuf buf = STRBUF_INIT;
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
fprintf(file, "%c %s %s\n", sign,
- find_unique_abbrev(&commit->object.oid, abbrev),
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev),
buf.buf);
strbuf_release(&buf);
}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4cf8a23648..92f94e65bf 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -5,22 +5,27 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "repository.h"
#include "config.h"
+#include "convert.h"
#include "quote.h"
#include "dir.h"
-#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "strbuf.h"
-#include "tree.h"
-#include "cache-tree.h"
#include "parse-options.h"
#include "resolve-undo.h"
#include "string-list.h"
+#include "path.h"
#include "pathspec.h"
-#include "run-command.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
+#include "object-store.h"
+#include "hex.h"
+
static int abbrev;
static int show_deleted;
@@ -89,12 +94,15 @@ static void write_name(const char *name)
static void write_name_to_buf(struct strbuf *sb, const char *name)
{
- const char *rel = relative_path(name, prefix_len ? prefix : NULL, sb);
+ struct strbuf buf = STRBUF_INIT;
+ const char *rel = relative_path(name, prefix_len ? prefix : NULL, &buf);
if (line_terminator)
quote_c_style(rel, sb, NULL, 0);
else
strbuf_addstr(sb, rel);
+
+ strbuf_release(&buf);
}
static const char *get_tag(const struct cache_entry *ce, const char *tag)
@@ -234,68 +242,75 @@ static void show_submodule(struct repository *superproject,
repo_clear(&subrepo);
}
-struct show_index_data {
- const char *pathname;
- struct index_state *istate;
- const struct cache_entry *ce;
-};
-
-static size_t expand_show_index(struct strbuf *sb, const char *start,
- void *context)
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+ const enum object_type type, unsigned int padded)
{
- struct show_index_data *data = context;
- const char *end;
- const char *p;
- size_t len = strbuf_expand_literal_cb(sb, start, NULL);
- struct stat st;
-
- if (len)
- return len;
- if (*start != '(')
- die(_("bad ls-files format: element '%s' "
- "does not start with '('"), start);
-
- end = strchr(start + 1, ')');
- if (!end)
- die(_("bad ls-files format: element '%s' "
- "does not end in ')'"), start);
-
- len = end - start + 1;
- if (skip_prefix(start, "(objectmode)", &p))
- strbuf_addf(sb, "%06o", data->ce->ce_mode);
- else if (skip_prefix(start, "(objectname)", &p))
- strbuf_add_unique_abbrev(sb, &data->ce->oid, abbrev);
- else if (skip_prefix(start, "(stage)", &p))
- strbuf_addf(sb, "%d", ce_stage(data->ce));
- else if (skip_prefix(start, "(eolinfo:index)", &p))
- strbuf_addstr(sb, S_ISREG(data->ce->ce_mode) ?
- get_cached_convert_stats_ascii(data->istate,
- data->ce->name) : "");
- else if (skip_prefix(start, "(eolinfo:worktree)", &p))
- strbuf_addstr(sb, !lstat(data->pathname, &st) &&
- S_ISREG(st.st_mode) ?
- get_wt_convert_stats_ascii(data->pathname) : "");
- else if (skip_prefix(start, "(eolattr)", &p))
- strbuf_addstr(sb, get_convert_attr_ascii(data->istate,
- data->pathname));
- else if (skip_prefix(start, "(path)", &p))
- write_name_to_buf(sb, data->pathname);
- else
- die(_("bad ls-files format: %%%.*s"), (int)len, start);
-
- return len;
+ if (type == OBJ_BLOB) {
+ unsigned long size;
+ if (oid_object_info(the_repository, oid, &size) < 0)
+ die(_("could not get object info about '%s'"),
+ oid_to_hex(oid));
+ if (padded)
+ strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+ else
+ strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+ } else if (padded) {
+ strbuf_addf(line, "%7s", "-");
+ } else {
+ strbuf_addstr(line, "-");
+ }
}
static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
const char *format, const char *fullname) {
- struct show_index_data data = {
- .pathname = fullname,
- .istate = repo->index,
- .ce = ce,
- };
struct strbuf sb = STRBUF_INIT;
- strbuf_expand(&sb, format, expand_show_index, &data);
+ while (strbuf_expand_step(&sb, &format)) {
+ const char *end;
+ size_t len;
+ struct stat st;
+
+ if (skip_prefix(format, "%", &format))
+ strbuf_addch(&sb, '%');
+ else if ((len = strbuf_expand_literal(&sb, format)))
+ format += len;
+ else if (*format != '(')
+ die(_("bad ls-files format: element '%s' "
+ "does not start with '('"), format);
+ else if (!(end = strchr(format + 1, ')')))
+ die(_("bad ls-files format: element '%s' "
+ "does not end in ')'"), format);
+ else if (skip_prefix(format, "(objectmode)", &format))
+ strbuf_addf(&sb, "%06o", ce->ce_mode);
+ else if (skip_prefix(format, "(objectname)", &format))
+ strbuf_add_unique_abbrev(&sb, &ce->oid, abbrev);
+ else if (skip_prefix(format, "(objecttype)", &format))
+ strbuf_addstr(&sb, type_name(object_type(ce->ce_mode)));
+ else if (skip_prefix(format, "(objectsize:padded)", &format))
+ expand_objectsize(&sb, &ce->oid,
+ object_type(ce->ce_mode), 1);
+ else if (skip_prefix(format, "(objectsize)", &format))
+ expand_objectsize(&sb, &ce->oid,
+ object_type(ce->ce_mode), 0);
+ else if (skip_prefix(format, "(stage)", &format))
+ strbuf_addf(&sb, "%d", ce_stage(ce));
+ else if (skip_prefix(format, "(eolinfo:index)", &format))
+ strbuf_addstr(&sb, S_ISREG(ce->ce_mode) ?
+ get_cached_convert_stats_ascii(repo->index,
+ ce->name) : "");
+ else if (skip_prefix(format, "(eolinfo:worktree)", &format))
+ strbuf_addstr(&sb, !lstat(fullname, &st) &&
+ S_ISREG(st.st_mode) ?
+ get_wt_convert_stats_ascii(fullname) : "");
+ else if (skip_prefix(format, "(eolattr)", &format))
+ strbuf_addstr(&sb, get_convert_attr_ascii(repo->index,
+ fullname));
+ else if (skip_prefix(format, "(path)", &format))
+ write_name_to_buf(&sb, fullname);
+ else
+ die(_("bad ls-files format: %%%.*s"),
+ (int)(end - format + 1), format);
+ }
strbuf_addch(&sb, line_terminator);
fwrite(sb.buf, sb.len, 1, stdout);
strbuf_release(&sb);
@@ -360,7 +375,7 @@ static void show_ru_info(struct index_state *istate)
if (!ui->mode[i])
continue;
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
- find_unique_abbrev(&ui->oid[i], abbrev),
+ repo_find_unique_abbrev(the_repository, &ui->oid[i], abbrev),
i + 1);
write_name(path);
}
@@ -509,142 +524,6 @@ static int get_common_prefix_len(const char *common_prefix)
return common_prefix_len;
}
-static int read_one_entry_opt(struct index_state *istate,
- const struct object_id *oid,
- struct strbuf *base,
- const char *pathname,
- unsigned mode, int opt)
-{
- int len;
- struct cache_entry *ce;
-
- if (S_ISDIR(mode))
- return READ_TREE_RECURSIVE;
-
- len = strlen(pathname);
- ce = make_empty_cache_entry(istate, base->len + len);
-
- ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = create_ce_flags(1);
- ce->ce_namelen = base->len + len;
- memcpy(ce->name, base->buf, base->len);
- memcpy(ce->name + base->len, pathname, len+1);
- oidcpy(&ce->oid, oid);
- return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode,
- void *context)
-{
- struct index_state *istate = context;
- return read_one_entry_opt(istate, oid, base, pathname,
- mode,
- ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode,
- void *context)
-{
- struct index_state *istate = context;
- return read_one_entry_opt(istate, oid, base, pathname,
- mode, ADD_CACHE_JUST_APPEND);
-}
-
-/*
- * Read the tree specified with --with-tree option
- * (typically, HEAD) into stage #1 and then
- * squash them down to stage #0. This is used for
- * --error-unmatch to list and check the path patterns
- * that were given from the command line. We are not
- * going to write this index out.
- */
-void overlay_tree_on_index(struct index_state *istate,
- const char *tree_name, const char *prefix)
-{
- struct tree *tree;
- struct object_id oid;
- struct pathspec pathspec;
- struct cache_entry *last_stage0 = NULL;
- int i;
- read_tree_fn_t fn = NULL;
- int err;
-
- if (get_oid(tree_name, &oid))
- die("tree-ish %s not found.", tree_name);
- tree = parse_tree_indirect(&oid);
- if (!tree)
- die("bad tree-ish %s", tree_name);
-
- /* Hoist the unmerged entries up to stage #3 to make room */
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(istate);
- for (i = 0; i < istate->cache_nr; i++) {
- struct cache_entry *ce = istate->cache[i];
- if (!ce_stage(ce))
- continue;
- ce->ce_flags |= CE_STAGEMASK;
- }
-
- if (prefix) {
- static const char *(matchbuf[1]);
- matchbuf[0] = NULL;
- parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
- PATHSPEC_PREFER_CWD, prefix, matchbuf);
- } else
- memset(&pathspec, 0, sizeof(pathspec));
-
- /*
- * See if we have cache entry at the stage. If so,
- * do it the original slow way, otherwise, append and then
- * sort at the end.
- */
- for (i = 0; !fn && i < istate->cache_nr; i++) {
- const struct cache_entry *ce = istate->cache[i];
- if (ce_stage(ce) == 1)
- fn = read_one_entry;
- }
-
- if (!fn)
- fn = read_one_entry_quick;
- err = read_tree(the_repository, tree, &pathspec, fn, istate);
- if (err)
- die("unable to read tree entries %s", tree_name);
-
- /*
- * Sort the cache entry -- we need to nuke the cache tree, though.
- */
- if (fn == read_one_entry_quick) {
- cache_tree_free(&istate->cache_tree);
- QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
- }
-
- for (i = 0; i < istate->cache_nr; i++) {
- struct cache_entry *ce = istate->cache[i];
- switch (ce_stage(ce)) {
- case 0:
- last_stage0 = ce;
- /* fallthru */
- default:
- continue;
- case 1:
- /*
- * If there is stage #0 entry for this, we do not
- * need to show it. We use CE_UPDATE bit to mark
- * such an entry.
- */
- if (last_stage0 &&
- !strcmp(last_stage0->name, ce->name))
- ce->ce_flags |= CE_UPDATE;
- }
- }
-}
-
static const char * const ls_files_usage[] = {
N_("git ls-files [<options>] [<file>...]"),
NULL
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index df44e5cc0d..e8d65ebbdc 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -1,14 +1,17 @@
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hex.h"
#include "transport.h"
+#include "pkt-line.h"
#include "ref-filter.h"
#include "remote.h"
-#include "refs.h"
+#include "parse-options.h"
+#include "wildmatch.h"
static const char * const ls_remote_usage[] = {
N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
- " [-q | --quiet] [--exit-code] [--get-url]\n"
- " [--symref] [<repository> [<refs>...]]"),
+ " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
+ " [--symref] [<repository> [<patterns>...]]"),
NULL
};
@@ -54,6 +57,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
struct transport *transport;
const struct ref *ref;
struct ref_array ref_array;
+ struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct option options[] = {
@@ -137,13 +141,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
item->symref = xstrdup_or_null(ref->symref);
}
- if (sorting_options.nr) {
- struct ref_sorting *sorting;
-
- sorting = ref_sorting_options(&sorting_options);
- ref_array_sort(sorting, &ref_array);
- ref_sorting_release(sorting);
- }
+ sorting = ref_sorting_options(&sorting_options);
+ ref_array_sort(sorting, &ref_array);
for (i = 0; i < ref_array.nr; i++) {
const struct ref_array_item *ref = ref_array.items[i];
@@ -153,6 +152,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
status = 0; /* we found something */
}
+ ref_sorting_release(sorting);
ref_array_clear(&ref_array);
if (transport_disconnect(transport))
status = 1;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index c3ea09281a..e4a891337c 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -3,48 +3,23 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
-#include "object-store.h"
-#include "blob.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "tree.h"
-#include "commit.h"
+#include "path.h"
#include "quote.h"
-#include "builtin.h"
#include "parse-options.h"
#include "pathspec.h"
-static int line_termination = '\n';
-#define LS_RECURSIVE 1
-#define LS_TREE_ONLY (1 << 1)
-#define LS_SHOW_TREES (1 << 2)
-static int abbrev;
-static int ls_options;
-static struct pathspec pathspec;
-static int chomp_prefix;
-static const char *ls_tree_prefix;
-static const char *format;
-struct show_tree_data {
- unsigned mode;
- enum object_type type;
- const struct object_id *oid;
- const char *pathname;
- struct strbuf *base;
-};
-
-static const char * const ls_tree_usage[] = {
+static const char * const ls_tree_usage[] = {
N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
-static enum ls_tree_cmdmode {
- MODE_DEFAULT = 0,
- MODE_LONG,
- MODE_NAME_ONLY,
- MODE_NAME_STATUS,
- MODE_OBJECT_ONLY,
-} cmdmode;
-
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
const enum object_type type, unsigned int padded)
{
@@ -64,65 +39,32 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
}
}
-static size_t expand_show_tree(struct strbuf *sb, const char *start,
- void *context)
-{
- struct show_tree_data *data = context;
- const char *end;
- const char *p;
- unsigned int errlen;
- size_t len = strbuf_expand_literal_cb(sb, start, NULL);
-
- if (len)
- return len;
- if (*start != '(')
- die(_("bad ls-tree format: element '%s' does not start with '('"), start);
-
- end = strchr(start + 1, ')');
- if (!end)
- die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
-
- len = end - start + 1;
- if (skip_prefix(start, "(objectmode)", &p)) {
- strbuf_addf(sb, "%06o", data->mode);
- } else if (skip_prefix(start, "(objecttype)", &p)) {
- strbuf_addstr(sb, type_name(data->type));
- } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
- expand_objectsize(sb, data->oid, data->type, 1);
- } else if (skip_prefix(start, "(objectsize)", &p)) {
- expand_objectsize(sb, data->oid, data->type, 0);
- } else if (skip_prefix(start, "(objectname)", &p)) {
- strbuf_add_unique_abbrev(sb, data->oid, abbrev);
- } else if (skip_prefix(start, "(path)", &p)) {
- const char *name = data->base->buf;
- const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
- struct strbuf quoted = STRBUF_INIT;
- struct strbuf sbuf = STRBUF_INIT;
- strbuf_addstr(data->base, data->pathname);
- name = relative_path(data->base->buf, prefix, &sbuf);
- quote_c_style(name, &quoted, NULL, 0);
- strbuf_addbuf(sb, &quoted);
- strbuf_release(&sbuf);
- strbuf_release(&quoted);
- } else {
- errlen = (unsigned long)len;
- die(_("bad ls-tree format: %%%.*s"), errlen, start);
- }
- return len;
-}
+struct ls_tree_options {
+ unsigned null_termination:1;
+ int abbrev;
+ enum ls_tree_path_options {
+ LS_RECURSIVE = 1 << 0,
+ LS_TREE_ONLY = 1 << 1,
+ LS_SHOW_TREES = 1 << 2,
+ } ls_options;
+ struct pathspec pathspec;
+ const char *prefix;
+ const char *format;
+};
-static int show_recursive(const char *base, size_t baselen, const char *pathname)
+static int show_recursive(struct ls_tree_options *options, const char *base,
+ size_t baselen, const char *pathname)
{
int i;
- if (ls_options & LS_RECURSIVE)
+ if (options->ls_options & LS_RECURSIVE)
return 1;
- if (!pathspec.nr)
+ if (!options->pathspec.nr)
return 0;
- for (i = 0; i < pathspec.nr; i++) {
- const char *spec = pathspec.items[i].match;
+ for (i = 0; i < options->pathspec.nr; i++) {
+ const char *spec = options->pathspec.items[i].match;
size_t len, speclen;
if (strncmp(base, spec, baselen))
@@ -142,109 +84,146 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
}
static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *context UNUSED)
+ const char *pathname, unsigned mode, void *context)
{
- size_t baselen;
+ struct ls_tree_options *options = context;
int recurse = 0;
struct strbuf sb = STRBUF_INIT;
enum object_type type = object_type(mode);
+ const char *format = options->format;
- struct show_tree_data data = {
- .mode = mode,
- .type = type,
- .oid = oid,
- .pathname = pathname,
- .base = base,
- };
-
- if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+ if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
recurse = READ_TREE_RECURSIVE;
- if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+ if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
return recurse;
- if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
+ if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
return 0;
- baselen = base->len;
- strbuf_expand(&sb, format, expand_show_tree, &data);
- strbuf_addch(&sb, line_termination);
+ while (strbuf_expand_step(&sb, &format)) {
+ const char *end;
+ size_t len;
+
+ if (skip_prefix(format, "%", &format))
+ strbuf_addch(&sb, '%');
+ else if ((len = strbuf_expand_literal(&sb, format)))
+ format += len;
+ else if (*format != '(')
+ die(_("bad ls-tree format: element '%s' "
+ "does not start with '('"), format);
+ else if (!(end = strchr(format + 1, ')')))
+ die(_("bad ls-tree format: element '%s' "
+ "does not end in ')'"), format);
+ else if (skip_prefix(format, "(objectmode)", &format))
+ strbuf_addf(&sb, "%06o", mode);
+ else if (skip_prefix(format, "(objecttype)", &format))
+ strbuf_addstr(&sb, type_name(type));
+ else if (skip_prefix(format, "(objectsize:padded)", &format))
+ expand_objectsize(&sb, oid, type, 1);
+ else if (skip_prefix(format, "(objectsize)", &format))
+ expand_objectsize(&sb, oid, type, 0);
+ else if (skip_prefix(format, "(objectname)", &format))
+ strbuf_add_unique_abbrev(&sb, oid, options->abbrev);
+ else if (skip_prefix(format, "(path)", &format)) {
+ const char *name;
+ const char *prefix = options->prefix;
+ struct strbuf sbuf = STRBUF_INIT;
+ size_t baselen = base->len;
+
+ strbuf_addstr(base, pathname);
+ name = relative_path(base->buf, prefix, &sbuf);
+ quote_c_style(name, &sb, NULL, 0);
+ strbuf_setlen(base, baselen);
+ strbuf_release(&sbuf);
+ } else
+ die(_("bad ls-tree format: %%%.*s"),
+ (int)(end - format + 1), format);
+ }
+ strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
fwrite(sb.buf, sb.len, 1, stdout);
strbuf_release(&sb);
- strbuf_setlen(base, baselen);
return recurse;
}
-static int show_tree_common(struct show_tree_data *data, int *recurse,
- const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode)
+static int show_tree_common(struct ls_tree_options *options, int *recurse,
+ struct strbuf *base, const char *pathname,
+ enum object_type type)
{
- enum object_type type = object_type(mode);
int ret = -1;
-
*recurse = 0;
- data->mode = mode;
- data->type = type;
- data->oid = oid;
- data->pathname = pathname;
- data->base = base;
if (type == OBJ_BLOB) {
- if (ls_options & LS_TREE_ONLY)
+ if (options->ls_options & LS_TREE_ONLY)
ret = 0;
} else if (type == OBJ_TREE &&
- show_recursive(base->buf, base->len, pathname)) {
+ show_recursive(options, base->buf, base->len, pathname)) {
*recurse = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
+ if (!(options->ls_options & LS_SHOW_TREES))
ret = *recurse;
}
return ret;
}
-static void show_tree_common_default_long(struct strbuf *base,
+static void show_tree_common_default_long(struct ls_tree_options *options,
+ struct strbuf *base,
const char *pathname,
const size_t baselen)
{
+ const char *prefix = options->prefix;
+
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL, stdout,
- line_termination);
+
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
+
strbuf_setlen(base, baselen);
}
static int show_tree_default(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%06o %s %s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev));
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s\t", mode, type_name(object_type(mode)),
+ repo_find_unique_abbrev(the_repository, oid, options->abbrev));
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
static int show_tree_long(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
char size_text[24];
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- if (data.type == OBJ_BLOB) {
+ if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+ if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text), "BAD");
else
xsnprintf(size_text, sizeof(size_text),
@@ -253,49 +232,78 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
xsnprintf(size_text, sizeof(size_text), "-");
}
- printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev), size_text);
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s %7s\t", mode, type_name(type),
+ repo_find_unique_abbrev(the_repository, oid, options->abbrev),
+ size_text);
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
-static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+static int show_tree_name_only(const struct object_id *oid UNUSED,
+ struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
const size_t baselen = base->len;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *prefix;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
+ prefix = options->prefix;
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL,
- stdout, line_termination);
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
strbuf_setlen(base, baselen);
return recurse;
}
static int show_tree_object(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *str;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
+ if (options->null_termination) {
+ fputs(str, stdout);
+ fputc('\0', stdout);
+ } else {
+ puts(str);
+ }
return recurse;
}
+enum ls_tree_cmdmode {
+ MODE_DEFAULT = 0,
+ MODE_LONG,
+ MODE_NAME_ONLY,
+ MODE_NAME_STATUS,
+ MODE_OBJECT_ONLY,
+};
+
struct ls_tree_cmdmode_to_fmt {
enum ls_tree_cmdmode mode;
const char *const fmt;
@@ -334,16 +342,20 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
struct object_id oid;
struct tree *tree;
int i, full_tree = 0;
+ int full_name = !prefix || !*prefix;
read_tree_fn_t fn = NULL;
+ enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
+ int null_termination = 0;
+ struct ls_tree_options options = { 0 };
const struct option ls_tree_options[] = {
- OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
+ OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
LS_TREE_ONLY),
- OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
+ OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
LS_RECURSIVE),
- OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
+ OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
LS_SHOW_TREES),
- OPT_SET_INT('z', NULL, &line_termination,
- N_("terminate entries with NUL byte"), 0),
+ OPT_BOOL('z', NULL, &null_termination,
+ N_("terminate entries with NUL byte")),
OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
MODE_LONG),
OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
@@ -352,30 +364,29 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
MODE_NAME_STATUS),
OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
MODE_OBJECT_ONLY),
- OPT_SET_INT(0, "full-name", &chomp_prefix,
- N_("use full path names"), 0),
+ OPT_BOOL(0, "full-name", &full_name, N_("use full path names")),
OPT_BOOL(0, "full-tree", &full_tree,
N_("list entire tree; not just current directory "
"(implies --full-name)")),
- OPT_STRING_F(0, "format", &format, N_("format"),
+ OPT_STRING_F(0, "format", &options.format, N_("format"),
N_("format to use for the output"),
PARSE_OPT_NONEG),
- OPT__ABBREV(&abbrev),
+ OPT__ABBREV(&options.abbrev),
OPT_END()
};
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+ int ret;
git_config(git_default_config, NULL);
- ls_tree_prefix = prefix;
- if (prefix)
- chomp_prefix = strlen(prefix);
argc = parse_options(argc, argv, prefix, ls_tree_options,
ls_tree_usage, 0);
- if (full_tree) {
- ls_tree_prefix = prefix = NULL;
- chomp_prefix = 0;
- }
+ options.null_termination = null_termination;
+
+ if (full_tree)
+ prefix = NULL;
+ options.prefix = full_name ? NULL : prefix;
+
/*
* We wanted to detect conflicts between --name-only and
* --name-status, but once we're done with that subsequent
@@ -386,16 +397,16 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
- ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
- ls_options |= LS_SHOW_TREES;
+ ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
+ options.ls_options |= LS_SHOW_TREES;
- if (format && cmdmode)
+ if (options.format && cmdmode)
usage_msg_opt(
_("--format can't be combined with other format-altering options"),
ls_tree_usage, ls_tree_options);
if (argc < 1)
usage_with_options(ls_tree_usage, ls_tree_options);
- if (get_oid(argv[0], &oid))
+ if (repo_get_oid(the_repository, argv[0], &oid))
die("Not a valid object name %s", argv[0]);
/*
@@ -404,13 +415,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* cannot be lifted until it is converted to use
* match_pathspec() or tree_entry_interesting()
*/
- parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
- ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+ parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
PATHSPEC_PREFER_CWD,
prefix, argv + 1);
- for (i = 0; i < pathspec.nr; i++)
- pathspec.items[i].nowildcard_len = pathspec.items[i].len;
- pathspec.has_wildcard = 0;
+ for (i = 0; i < options.pathspec.nr; i++)
+ options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
+ options.pathspec.has_wildcard = 0;
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
@@ -420,11 +431,11 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
*/
while (m2f) {
if (!m2f->fmt) {
- fn = format ? show_tree_fmt : show_tree_default;
- } else if (format && !strcmp(format, m2f->fmt)) {
+ fn = options.format ? show_tree_fmt : show_tree_default;
+ } else if (options.format && !strcmp(options.format, m2f->fmt)) {
cmdmode = m2f->mode;
fn = m2f->fn;
- } else if (!format && cmdmode == m2f->mode) {
+ } else if (!options.format && cmdmode == m2f->mode) {
fn = m2f->fn;
} else {
m2f++;
@@ -433,5 +444,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
break;
}
- return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
+ ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
+ clear_pathspec(&options.pathspec);
+ return ret;
}
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 01d16ef9e5..53a22645da 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -2,9 +2,10 @@
* Another stupid program, this one parsing the headers of an
* email to figure out authorship and subject
*/
-#include "cache.h"
#include "builtin.h"
-#include "utf8.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
#include "strbuf.h"
#include "mailinfo.h"
#include "parse-options.h"
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 73509f651b..3af9ddb8ae 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -4,8 +4,8 @@
* It just splits a mbox into a list of files: "0001" "0002" ..
* so you can process them further from there.
*/
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
#include "string-list.h"
#include "strbuf.h"
@@ -277,6 +277,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
const char **argp;
static const char *stdin_only[] = { "-", NULL };
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
for (argp = argv+1; *argp; argp++) {
const char *arg = *argp;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index a11f8c6e4b..d26e8fbf6f 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,10 +1,9 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "commit.h"
-#include "refs.h"
-#include "diff.h"
-#include "revision.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "repository.h"
#include "commit-reach.h"
@@ -13,7 +12,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
struct commit_list *result, *r;
- result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
+ result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
+ rev_nr - 1, rev + 1);
if (!result)
return 1;
@@ -31,8 +31,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
static const char * const merge_base_usage[] = {
N_("git merge-base [-a | --all] <commit> <commit>..."),
N_("git merge-base [-a | --all] --octopus <commit>..."),
- N_("git merge-base --independent <commit>..."),
N_("git merge-base --is-ancestor <commit> <commit>"),
+ N_("git merge-base --independent <commit>..."),
N_("git merge-base --fork-point <ref> [<commit>]"),
NULL
};
@@ -42,7 +42,7 @@ static struct commit *get_commit_reference(const char *arg)
struct object_id revkey;
struct commit *r;
- if (get_oid(arg, &revkey))
+ if (repo_get_oid(the_repository, arg, &revkey))
die("Not a valid object name %s", arg);
r = lookup_commit_reference(the_repository, &revkey);
if (!r)
@@ -105,7 +105,7 @@ static int handle_is_ancestor(int argc, const char **argv)
die("--is-ancestor takes exactly two commits");
one = get_commit_reference(argv[0]);
two = get_commit_reference(argv[1]);
- if (in_merge_bases(one, two))
+ if (repo_in_merge_bases(the_repository, one, two))
return 0;
else
return 1;
@@ -118,7 +118,7 @@ static int handle_fork_point(int argc, const char **argv)
const char *commitname;
commitname = (argc == 2) ? argv[1] : "HEAD";
- if (get_oid(commitname, &oid))
+ if (repo_get_oid(the_repository, commitname, &oid))
die("Not a valid object name: '%s'", commitname);
derived = lookup_commit_reference(the_repository, &oid);
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index c923bbf2ab..1f987334a3 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -1,6 +1,12 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
+#include "diff.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store.h"
#include "config.h"
+#include "gettext.h"
+#include "setup.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
#include "parse-options.h"
@@ -23,16 +29,41 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int set_diff_algorithm(xpparam_t *xpp,
+ const char *alg)
+{
+ long diff_algorithm = parse_algorithm_value(alg);
+ if (diff_algorithm < 0)
+ return -1;
+ xpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+ return 0;
+}
+
+static int diff_algorithm_cb(const struct option *opt,
+ const char *arg, int unset)
+{
+ xpparam_t *xpp = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (set_diff_algorithm(xpp, arg))
+ return error(_("option diff-algorithm accepts \"myers\", "
+ "\"minimal\", \"patience\" and \"histogram\""));
+
+ return 0;
+}
+
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
const char *names[3] = { 0 };
mmfile_t mmfs[3] = { 0 };
mmbuffer_t result = { 0 };
xmparam_t xmp = { 0 };
- int ret = 0, i = 0, to_stdout = 0;
+ int ret = 0, i = 0, to_stdout = 0, object_id = 0;
int quiet = 0;
struct option options[] = {
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
+ OPT_BOOL(0, "object-id", &object_id, N_("use object IDs instead of filenames")),
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
XDL_MERGE_ZEALOUS_DIFF3),
@@ -42,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
XDL_MERGE_FAVOR_THEIRS),
OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
XDL_MERGE_FAVOR_UNION),
+ OPT_CALLBACK_F(0, "diff-algorithm", &xmp.xpp, N_("<algorithm>"),
+ N_("choose a diff algorithm"),
+ PARSE_OPT_NONEG, diff_algorithm_cb),
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
N_("for conflicts, use this marker size")),
OPT__QUIET(&quiet, N_("do not warn about conflicts")),
@@ -69,8 +103,12 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
return error_errno("failed to redirect stderr to /dev/null");
}
+ if (object_id)
+ setup_git_directory();
+
for (i = 0; i < 3; i++) {
char *fname;
+ struct object_id oid;
mmfile_t *mmf = mmfs + i;
if (!names[i])
@@ -78,12 +116,22 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
fname = prefix_filename(prefix, argv[i]);
- if (read_mmfile(mmf, fname))
+ if (object_id) {
+ if (repo_get_oid(the_repository, argv[i], &oid))
+ ret = error(_("object '%s' does not exist"),
+ argv[i]);
+ else if (!oideq(&oid, the_hash_algo->empty_blob))
+ read_mmblob(mmf, &oid);
+ else
+ read_mmfile(mmf, "/dev/null");
+ } else if (read_mmfile(mmf, fname)) {
ret = -1;
- else if (mmf->size > MAX_XDIFF_SIZE ||
- buffer_is_binary(mmf->ptr, mmf->size))
+ }
+ if (ret != -1 && (mmf->size > MAX_XDIFF_SIZE ||
+ buffer_is_binary(mmf->ptr, mmf->size))) {
ret = error("Cannot merge binary files: %s",
argv[i]);
+ }
free(fname);
if (ret)
@@ -97,20 +145,32 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
if (ret >= 0) {
- const char *filename = argv[0];
- char *fpath = prefix_filename(prefix, argv[0]);
- FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
-
- if (!f)
- ret = error_errno("Could not open %s for writing",
- filename);
- else if (result.size &&
- fwrite(result.ptr, result.size, 1, f) != 1)
- ret = error_errno("Could not write to %s", filename);
- else if (fclose(f))
- ret = error_errno("Could not close %s", filename);
+ if (object_id && !to_stdout) {
+ struct object_id oid;
+ if (result.size) {
+ if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
+ ret = error(_("Could not write object file"));
+ } else {
+ oidcpy(&oid, the_hash_algo->empty_blob);
+ }
+ if (ret >= 0)
+ printf("%s\n", oid_to_hex(&oid));
+ } else {
+ const char *filename = argv[0];
+ char *fpath = prefix_filename(prefix, argv[0]);
+ FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
+
+ if (!f)
+ ret = error_errno("Could not open %s for writing",
+ filename);
+ else if (result.size &&
+ fwrite(result.ptr, result.size, 1, f) != 1)
+ ret = error_errno("Could not write to %s", filename);
+ else if (fclose(f))
+ ret = error_errno("Could not close %s", filename);
+ free(fpath);
+ }
free(result.ptr);
- free(fpath);
}
if (ret > 127)
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index c0383fe9df..270d5f644a 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,6 +1,10 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "hex.h"
+#include "read-cache-ll.h"
+#include "repository.h"
#include "run-command.h"
+#include "sparse-index.h"
static const char *pgm;
static int one_shot, quiet;
@@ -12,12 +16,13 @@ static int merge_entry(int pos, const char *path)
const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL };
char hexbuf[4][GIT_MAX_HEXSZ + 1];
char ownbuf[4][60];
+ struct child_process cmd = CHILD_PROCESS_INIT;
- if (pos >= active_nr)
+ if (pos >= the_index.cache_nr)
die("git merge-index: %s not in the cache", path);
found = 0;
do {
- const struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = the_index.cache[pos];
int stage = ce_stage(ce);
if (strcmp(ce->name, path))
@@ -27,11 +32,12 @@ static int merge_entry(int pos, const char *path)
xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
arguments[stage] = hexbuf[stage];
arguments[stage + 4] = ownbuf[stage];
- } while (++pos < active_nr);
+ } while (++pos < the_index.cache_nr);
if (!found)
die("git merge-index: %s not in the cache", path);
- if (run_command_v_opt(arguments, 0)) {
+ strvec_pushv(&cmd.args, arguments);
+ if (run_command(&cmd)) {
if (one_shot)
err++;
else {
@@ -45,7 +51,7 @@ static int merge_entry(int pos, const char *path)
static void merge_one_path(const char *path)
{
- int pos = cache_name_pos(path, strlen(path));
+ int pos = index_name_pos(&the_index, path, strlen(path));
/*
* If it already exists in the cache as stage0, it's
@@ -60,15 +66,15 @@ static void merge_all(void)
int i;
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ const struct cache_entry *ce = the_index.cache[i];
if (!ce_stage(ce))
continue;
i += merge_entry(i, ce->name)-1;
}
}
-int cmd_merge_index(int argc, const char **argv, const char *prefix)
+int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
{
int i, force_file = 0;
@@ -80,7 +86,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
if (argc < 3)
usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
- read_cache();
+ repo_read_index(the_repository);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 3583cff71c..932924e5d0 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -7,15 +7,15 @@
*
* Pretend we resolved the heads, but declare our tree trumps everybody else.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "git-compat-util.h"
#include "builtin.h"
#include "diff.h"
+#include "repository.h"
static const char builtin_merge_ours_usage[] =
"git merge-ours <base>... -- HEAD <remote>...";
-int cmd_merge_ours(int argc, const char **argv, const char *prefix)
+int cmd_merge_ours(int argc, const char **argv, const char *prefix UNUSED)
{
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_merge_ours_usage);
@@ -25,7 +25,7 @@ int cmd_merge_ours(int argc, const char **argv, const char *prefix)
* commit. The index must match HEAD, or this merge cannot go
* through.
*/
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die_errno("read_cache failed");
if (index_differs_from(the_repository, "HEAD", NULL, 0))
return 2;
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index b9acbf5d34..c2ce044a20 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,9 +1,10 @@
-#include "cache.h"
#include "builtin.h"
-#include "commit.h"
-#include "tag.h"
+#include "advice.h"
+#include "gettext.h"
+#include "hash.h"
#include "merge-recursive.h"
-#include "xdiff-interface.h"
+#include "object-name.h"
+#include "repository.h"
static const char builtin_merge_recursive_usage[] =
"git %s <base>... -- <head> <remote> ...";
@@ -20,7 +21,7 @@ static char *better_branch_name(const char *branch)
return xstrdup(name ? name : branch);
}
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
{
const struct object_id *bases[21];
unsigned bases_count = 0;
@@ -49,7 +50,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
}
if (bases_count < ARRAY_SIZE(bases)-1) {
struct object_id *oid = xmalloc(sizeof(struct object_id));
- if (get_oid(argv[i], oid))
+ if (repo_get_oid(the_repository, argv[i], oid))
die(_("could not parse object '%s'"), argv[i]);
bases[bases_count++] = oid;
}
@@ -70,9 +71,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
o.branch1 = argv[++i];
o.branch2 = argv[++i];
- if (get_oid(o.branch1, &h1))
+ if (repo_get_oid(the_repository, o.branch1, &h1))
die(_("could not resolve ref '%s'"), o.branch1);
- if (get_oid(o.branch2, &h2))
+ if (repo_get_oid(the_repository, o.branch2, &h2))
die(_("could not resolve ref '%s'"), o.branch2);
o.branch1 = better1 = better_branch_name(o.branch1);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index ae5782917b..3bdec53fbe 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,17 +1,23 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
+#include "gettext.h"
+#include "hex.h"
+#include "commit.h"
#include "commit-reach.h"
#include "merge-ort.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "parse-options.h"
#include "repository.h"
#include "blob.h"
-#include "exec-cmd.h"
#include "merge-blobs.h"
#include "quote.h"
+#include "tree.h"
+#include "config.h"
+#include "strvec.h"
static int line_termination = '\n';
@@ -68,7 +74,9 @@ static void *result(struct merge_list *entry, unsigned long *size)
const char *path = entry->path;
if (!entry->stage)
- return read_object_file(&entry->blob->object.oid, &type, size);
+ return repo_read_object_file(the_repository,
+ &entry->blob->object.oid, &type,
+ size);
base = NULL;
if (entry->stage == 1) {
base = entry->blob;
@@ -91,14 +99,15 @@ static void *origin(struct merge_list *entry, unsigned long *size)
enum object_type type;
while (entry) {
if (entry->stage == 2)
- return read_object_file(&entry->blob->object.oid,
- &type, size);
+ return repo_read_object_file(the_repository,
+ &entry->blob->object.oid,
+ &type, size);
entry = entry->link;
}
return NULL;
}
-static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf)
+static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)
{
int i;
for (i = 0; i < nbuf; i++)
@@ -315,7 +324,9 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
* The successful merge rules are the same as for the three-way merge
* in git-read-tree.
*/
-static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *info)
+static int threeway_callback(int n UNUSED, unsigned long mask,
+ unsigned long dirmask UNUSED,
+ struct name_entry *entry, struct traverse_info *info)
{
/* Same in both? */
if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
@@ -402,17 +413,22 @@ struct merge_tree_options {
int allow_unrelated_histories;
int show_messages;
int name_only;
+ int use_stdin;
+ struct merge_options merge_options;
};
static int real_merge(struct merge_tree_options *o,
+ const char *merge_base,
const char *branch1, const char *branch2,
const char *prefix)
{
struct commit *parent1, *parent2;
struct commit_list *merge_bases = NULL;
- struct merge_options opt;
struct merge_result result = { 0 };
+ int show_messages = o->show_messages;
+ struct merge_options opt;
+ copy_merge_options(&opt, &o->merge_options);
parent1 = get_merge_parent(branch1);
if (!parent1)
help_unknown_ref(branch1, "merge-tree",
@@ -423,29 +439,45 @@ static int real_merge(struct merge_tree_options *o,
help_unknown_ref(branch2, "merge-tree",
_("not something we can merge"));
- init_merge_options(&opt, the_repository);
-
opt.show_rename_progress = 0;
opt.branch1 = branch1;
opt.branch2 = branch2;
- /*
- * Get the merge bases, in reverse order; see comment above
- * merge_incore_recursive in merge-ort.h
- */
- merge_bases = get_merge_bases(parent1, parent2);
- if (!merge_bases && !o->allow_unrelated_histories)
- die(_("refusing to merge unrelated histories"));
- merge_bases = reverse_commit_list(merge_bases);
+ if (merge_base) {
+ struct commit *base_commit;
+ struct tree *base_tree, *parent1_tree, *parent2_tree;
+
+ base_commit = lookup_commit_reference_by_name(merge_base);
+ if (!base_commit)
+ die(_("could not lookup commit '%s'"), merge_base);
+
+ opt.ancestor = merge_base;
+ base_tree = repo_get_commit_tree(the_repository, base_commit);
+ parent1_tree = repo_get_commit_tree(the_repository, parent1);
+ parent2_tree = repo_get_commit_tree(the_repository, parent2);
+ merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
+ } else {
+ /*
+ * Get the merge bases, in reverse order; see comment above
+ * merge_incore_recursive in merge-ort.h
+ */
+ merge_bases = repo_get_merge_bases(the_repository, parent1,
+ parent2);
+ if (!merge_bases && !o->allow_unrelated_histories)
+ die(_("refusing to merge unrelated histories"));
+ merge_bases = reverse_commit_list(merge_bases);
+ merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ }
- merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
if (result.clean < 0)
die(_("failure to merge"));
- if (o->show_messages == -1)
- o->show_messages = !result.clean;
+ if (show_messages == -1)
+ show_messages = !result.clean;
+ if (o->use_stdin)
+ printf("%d%c", result.clean, line_termination);
printf("%s%c", oid_to_hex(&result.tree->object.oid), line_termination);
if (!result.clean) {
struct string_list conflicted_files = STRING_LIST_INIT_NODUP;
@@ -467,20 +499,25 @@ static int real_merge(struct merge_tree_options *o,
}
string_list_clear(&conflicted_files, 1);
}
- if (o->show_messages) {
+ if (show_messages) {
putchar(line_termination);
merge_display_update_messages(&opt, line_termination == '\0',
&result);
}
+ if (o->use_stdin)
+ putchar(line_termination);
merge_finalize(&opt, &result);
+ clear_merge_options(&opt);
return !result.clean; /* result.clean < 0 handled above */
}
int cmd_merge_tree(int argc, const char **argv, const char *prefix)
{
struct merge_tree_options o = { .show_messages = -1 };
+ struct strvec xopts = STRVEC_INIT;
int expected_remaining_argc;
int original_argc;
+ const char *merge_base = NULL;
const char * const merge_tree_usage[] = {
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -505,13 +542,78 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
&o.allow_unrelated_histories,
N_("allow merging unrelated histories"),
PARSE_OPT_NONEG),
+ OPT_BOOL_F(0, "stdin",
+ &o.use_stdin,
+ N_("perform multiple merges, one per line of input"),
+ PARSE_OPT_NONEG),
+ OPT_STRING(0, "merge-base",
+ &merge_base,
+ N_("commit"),
+ N_("specify a merge-base for the merge")),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_END()
};
+ /* Init merge options */
+ init_merge_options(&o.merge_options, the_repository);
+
/* Parse arguments */
original_argc = argc - 1; /* ignoring argv[0] */
argc = parse_options(argc, argv, prefix, mt_options,
merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (xopts.nr && o.mode == MODE_TRIVIAL)
+ die(_("--trivial-merge is incompatible with all other options"));
+ for (int x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o.merge_options, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
+ /* Handle --stdin */
+ if (o.use_stdin) {
+ struct strbuf buf = STRBUF_INIT;
+
+ if (o.mode == MODE_TRIVIAL)
+ die(_("--trivial-merge is incompatible with all other options"));
+ if (merge_base)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--merge-base", "--stdin");
+ line_termination = '\0';
+ while (strbuf_getline_lf(&buf, stdin) != EOF) {
+ struct strbuf **split;
+ int result;
+ const char *input_merge_base = NULL;
+
+ split = strbuf_split(&buf, ' ');
+ if (!split[0] || !split[1])
+ die(_("malformed input line: '%s'."), buf.buf);
+ strbuf_rtrim(split[0]);
+ strbuf_rtrim(split[1]);
+
+ /* parse the merge-base */
+ if (!strcmp(split[1]->buf, "--")) {
+ input_merge_base = split[0]->buf;
+ }
+
+ if (input_merge_base && split[2] && split[3] && !split[4]) {
+ strbuf_rtrim(split[2]);
+ strbuf_rtrim(split[3]);
+ result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
+ } else if (!input_merge_base && !split[2]) {
+ result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+ } else {
+ die(_("malformed input line: '%s'."), buf.buf);
+ }
+
+ if (result < 0)
+ die(_("merging cannot continue; got unclean result of %d"), result);
+ strbuf_list_free(split);
+ }
+ strbuf_release(&buf);
+ return 0;
+ }
+
+ /* Figure out which mode to use */
switch (o.mode) {
default:
BUG("unexpected command mode %d", o.mode);
@@ -543,9 +645,11 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (argc != expected_remaining_argc)
usage_with_options(merge_tree_usage, mt_options);
+ git_config(git_default_config, NULL);
+
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
- return real_merge(&o, argv[0], argv[1], prefix);
+ return real_merge(&o, merge_base, argv[0], argv[1], prefix);
else
return trivial_merge(argv[0], argv[1], argv[2]);
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 5900b81729..ebbe05033e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -6,11 +6,17 @@
* Based on git-merge.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
-#include "builtin.h"
#include "lockfile.h"
#include "run-command.h"
#include "hook.h"
@@ -20,24 +26,22 @@
#include "refspec.h"
#include "commit.h"
#include "diffcore.h"
+#include "path.h"
#include "revision.h"
#include "unpack-trees.h"
#include "cache-tree.h"
#include "dir.h"
-#include "utf8.h"
-#include "log-tree.h"
#include "color.h"
#include "rerere.h"
#include "help.h"
+#include "merge.h"
#include "merge-recursive.h"
#include "merge-ort-wrappers.h"
#include "resolve-undo.h"
#include "remote.h"
#include "fmt-merge-msg.h"
-#include "gpg-interface.h"
#include "sequencer.h"
#include "string-list.h"
-#include "packfile.h"
#include "tag.h"
#include "alias.h"
#include "branch.h"
@@ -71,8 +75,7 @@ static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
static size_t use_strategies_nr, use_strategies_alloc;
-static const char **xopts;
-static size_t xopts_nr, xopts_alloc;
+static struct strvec xopts = STRVEC_INIT;
static const char *branch;
static char *branch_mergeoptions;
static int verbosity;
@@ -188,7 +191,7 @@ static struct strategy *get_strategy(const char *name)
for (i = 0; i < main_cmds.cnt; i++) {
int j, found = 0;
struct cmdname *ent = main_cmds.names[i];
- for (j = 0; j < ARRAY_SIZE(all_strategy); j++)
+ for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
if (!strncmp(ent->name, all_strategy[j].name, ent->len)
&& !all_strategy[j].name[ent->len])
found = 1;
@@ -224,7 +227,7 @@ static void append_strategy(struct strategy *s)
use_strategies[use_strategies_nr++] = s;
}
-static int option_parse_strategy(const struct option *opt,
+static int option_parse_strategy(const struct option *opt UNUSED,
const char *name, int unset)
{
if (unset)
@@ -234,29 +237,9 @@ static int option_parse_strategy(const struct option *opt,
return 0;
}
-static int option_parse_x(const struct option *opt,
- const char *arg, int unset)
-{
- if (unset)
- return 0;
-
- ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
- xopts[xopts_nr++] = xstrdup(arg);
- return 0;
-}
-
-static int option_parse_n(const struct option *opt,
- const char *arg, int unset)
-{
- BUG_ON_OPT_ARG(arg);
- show_diffstat = unset;
- return 0;
-}
-
static struct option builtin_merge_options[] = {
- OPT_CALLBACK_F('n', NULL, NULL, NULL,
- N_("do not show a diffstat at the end of the merge"),
- PARSE_OPT_NOARG, option_parse_n),
+ OPT_SET_INT('n', NULL, &show_diffstat,
+ N_("do not show a diffstat at the end of the merge"), 0),
OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
@@ -277,10 +260,10 @@ static struct option builtin_merge_options[] = {
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),
- OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+ OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
N_("merge strategy to use"), option_parse_strategy),
- OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
- N_("option for selected merge strategy"), option_parse_x),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
@@ -318,7 +301,7 @@ static int save_state(struct object_id *stash)
int rc = -1;
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
repo_update_index_if_able(the_repository, &lock_file);
rollback_lock_file(&lock_file);
@@ -337,7 +320,7 @@ static int save_state(struct object_id *stash)
else if (!len) /* no changes */
goto out;
strbuf_setlen(&buffer, buffer.len-1);
- if (get_oid(buffer.buf, stash))
+ if (repo_get_oid(the_repository, buffer.buf, stash))
die(_("not a valid object: %s"), buffer.buf);
rc = 0;
out:
@@ -345,63 +328,53 @@ out:
return rc;
}
-static void read_empty(const struct object_id *oid, int verbose)
+static void read_empty(const struct object_id *oid)
{
- int i = 0;
- const char *args[7];
-
- args[i++] = "read-tree";
- if (verbose)
- args[i++] = "-v";
- args[i++] = "-m";
- args[i++] = "-u";
- args[i++] = empty_tree_oid_hex();
- args[i++] = oid_to_hex(oid);
- args[i] = NULL;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushl(&cmd.args, "read-tree", "-m", "-u", empty_tree_oid_hex(),
+ oid_to_hex(oid), NULL);
+ cmd.git_cmd = 1;
- if (run_command_v_opt(args, RUN_GIT_CMD))
+ if (run_command(&cmd))
die(_("read-tree failed"));
}
-static void reset_hard(const struct object_id *oid, int verbose)
+static void reset_hard(const struct object_id *oid)
{
- int i = 0;
- const char *args[6];
-
- args[i++] = "read-tree";
- if (verbose)
- args[i++] = "-v";
- args[i++] = "--reset";
- args[i++] = "-u";
- args[i++] = oid_to_hex(oid);
- args[i] = NULL;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushl(&cmd.args, "read-tree", "-v", "--reset", "-u",
+ oid_to_hex(oid), NULL);
+ cmd.git_cmd = 1;
- if (run_command_v_opt(args, RUN_GIT_CMD))
+ if (run_command(&cmd))
die(_("read-tree failed"));
}
static void restore_state(const struct object_id *head,
const struct object_id *stash)
{
- struct strvec args = STRVEC_INIT;
+ struct child_process cmd = CHILD_PROCESS_INIT;
- reset_hard(head, 1);
+ reset_hard(head);
if (is_null_oid(stash))
goto refresh_cache;
- strvec_pushl(&args, "stash", "apply", "--index", "--quiet", NULL);
- strvec_push(&args, oid_to_hex(stash));
+ strvec_pushl(&cmd.args, "stash", "apply", "--index", "--quiet", NULL);
+ strvec_push(&cmd.args, oid_to_hex(stash));
/*
* It is OK to ignore error here, for example when there was
* nothing to restore.
*/
- run_command_v_opt(args.v, RUN_GIT_CMD);
- strvec_clear(&args);
+ cmd.git_cmd = 1;
+ run_command(&cmd);
refresh_cache:
- if (discard_cache() < 0 || read_cache() < 0)
+ discard_index(&the_index);
+ if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
}
@@ -489,8 +462,7 @@ static void finish(struct commit *head_commit,
if (new_head && show_diffstat) {
struct diff_options opts;
repo_diff_setup(the_repository, &opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
@@ -527,7 +499,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref, 0) > 0) {
+ if (repo_dwim_ref(the_repository, remote, strlen(remote), &branch_head,
+ &found_ref, 0) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
@@ -623,7 +596,8 @@ static void parse_branch_merge_options(char *bmo)
free(argv);
}
-static int git_merge_config(const char *k, const char *v, void *cb)
+static int git_merge_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
int status;
const char *str;
@@ -668,13 +642,10 @@ static int git_merge_config(const char *k, const char *v, void *cb)
return 0;
}
- status = fmt_merge_msg_config(k, v, cb);
+ status = fmt_merge_msg_config(k, v, ctx, cb);
if (status)
return status;
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
- return git_diff_ui_config(k, v, cb);
+ return git_diff_ui_config(k, v, ctx, cb);
}
static int read_tree_trivial(struct object_id *common, struct object_id *head,
@@ -704,7 +675,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
if (!trees[nr_trees++])
return -1;
opts.fn = threeway_merge;
- cache_tree_free(&active_cache_tree);
+ cache_tree_free(&the_index.cache_tree);
for (i = 0; i < nr_trees; i++) {
parse_tree(trees[i]);
init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
@@ -716,7 +687,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
static void write_tree_trivial(struct object_id *oid)
{
- if (write_cache_as_tree(oid, 0, NULL))
+ if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
}
@@ -726,7 +697,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
{
const char *head_arg = "HEAD";
- if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+ SKIP_IF_UNCHANGED, 0, NULL, NULL,
+ NULL) < 0)
return error(_("Unable to write index."));
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
@@ -750,9 +723,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
o.show_rename_progress =
show_progress == -1 ? isatty(2) : show_progress;
- for (x = 0; x < xopts_nr; x++)
- if (parse_merge_opt(&o, xopts[x]))
- die(_("unknown strategy option: -X%s"), xopts[x]);
+ for (x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
o.branch1 = head_arg;
o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -760,7 +733,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
for (j = common; j; j = j->next)
commit_list_insert(j->item, &reversed);
- hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock,
+ LOCK_DIE_ON_ERROR);
if (!strcmp(strategy, "ort"))
clean = merge_ort_recursive(&o, head, remoteheads->item,
reversed, &result);
@@ -777,13 +751,13 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
return clean ? 0 : 1;
} else {
return try_merge_command(the_repository,
- strategy, xopts_nr, xopts,
+ strategy, xopts.nr, xopts.v,
common, head_arg, remoteheads);
}
}
static void count_diff_files(struct diff_queue_struct *q,
- struct diff_options *opt, void *data)
+ struct diff_options *opt UNUSED, void *data)
{
int *count = data;
@@ -794,8 +768,8 @@ static int count_unmerged_entries(void)
{
int i, ret = 0;
- for (i = 0; i < active_nr; i++)
- if (ce_stage(active_cache[i]))
+ for (i = 0; i < the_index.cache_nr; i++)
+ if (ce_stage(the_index.cache[i]))
ret++;
return ret;
@@ -869,9 +843,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
* the editor and after we invoke run_status above.
*/
if (invoked_hook)
- discard_cache();
+ discard_index(&the_index);
}
- read_cache_from(index_file);
+ read_index_from(&the_index, index_file, get_git_dir());
strbuf_addbuf(&msg, &merge_msg);
if (squash)
BUG("the control must not reach here under --squash");
@@ -879,17 +853,19 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_addch(&msg, '\n');
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
wt_status_append_cut_line(&msg);
- strbuf_commented_addf(&msg, "\n");
+ strbuf_commented_addf(&msg, comment_line_char, "\n");
}
- strbuf_commented_addf(&msg, _(merge_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(merge_editor_comment));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
- strbuf_commented_addf(&msg, _(scissors_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(scissors_editor_comment));
else
- strbuf_commented_addf(&msg,
+ strbuf_commented_addf(&msg, comment_line_char,
_(no_scissors_editor_comment), comment_line_char);
}
if (signoff)
- append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
+ append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
@@ -920,7 +896,9 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
- if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+ SKIP_IF_UNCHANGED, 0, NULL, NULL,
+ NULL) < 0)
return error(_("Unable to write index."));
write_tree_trivial(&result_tree);
@@ -1386,7 +1364,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- if (read_cache_unmerged())
+ if (repo_read_index_unmerged(the_repository))
die_resolve_conflict("merge");
if (file_exists(git_path_merge_head(the_repository))) {
@@ -1407,7 +1385,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
}
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
if (option_edit < 0)
option_edit = default_edit_option();
@@ -1470,7 +1448,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
check_trust_level);
remote_head_oid = &remoteheads->item->object.oid;
- read_empty(remote_head_oid, 0);
+ read_empty(remote_head_oid);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
goto done;
@@ -1536,7 +1514,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (!remoteheads)
; /* already up-to-date */
else if (!remoteheads->next)
- common = get_merge_bases(head_commit, remoteheads->item);
+ common = repo_get_merge_bases(the_repository, head_commit,
+ remoteheads->item);
else {
struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list);
@@ -1565,20 +1544,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
!common->next &&
oideq(&common->item->object.oid, &head_commit->object.oid)) {
/* Again the most common case of merging one remote. */
- struct strbuf msg = STRBUF_INIT;
+ const char *msg = have_message ?
+ "Fast-forward (no commit created; -m option ignored)" :
+ "Fast-forward";
struct commit *commit;
if (verbosity >= 0) {
printf(_("Updating %s..%s\n"),
- find_unique_abbrev(&head_commit->object.oid,
- DEFAULT_ABBREV),
- find_unique_abbrev(&remoteheads->item->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &head_commit->object.oid,
+ DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &remoteheads->item->object.oid,
+ DEFAULT_ABBREV));
}
- strbuf_addstr(&msg, "Fast-forward");
- if (have_message)
- strbuf_addstr(&msg,
- " (no commit created; -m option ignored)");
commit = remoteheads->item;
if (!commit) {
ret = 1;
@@ -1597,9 +1574,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- finish(head_commit, remoteheads, &commit->object.oid, msg.buf);
+ finish(head_commit, remoteheads, &commit->object.oid, msg);
remove_merge_branch_state(the_repository);
- strbuf_release(&msg);
goto done;
} else if (!remoteheads->next && common->next)
;
@@ -1612,13 +1588,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* We are not doing octopus, not fast-forward, and have
* only one common.
*/
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
if (allow_trivial && fast_forward != FF_ONLY) {
/*
* Must first ensure that index matches HEAD before
* attempting a trivial merge.
*/
- struct tree *head_tree = get_commit_tree(head_commit);
+ struct tree *head_tree = repo_get_commit_tree(the_repository,
+ head_commit);
struct strbuf sb = STRBUF_INIT;
if (repo_index_has_changes(the_repository, head_tree,
@@ -1626,7 +1603,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
error(_("Your local changes to the following files would be overwritten by merge:\n %s"),
sb.buf);
strbuf_release(&sb);
- return 2;
+ ret = 2;
+ goto done;
}
/* See if it is really trivial. */
@@ -1650,14 +1628,19 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
for (j = remoteheads; j; j = j->next) {
struct commit_list *common_one;
+ struct commit *common_item;
/*
* Here we *have* to calculate the individual
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
- common_one = get_merge_bases(head_commit, j->item);
- if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
+ common_one = repo_get_merge_bases(the_repository,
+ head_commit,
+ j->item);
+ common_item = common_one->item;
+ free_commit_list(common_one);
+ if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
up_to_date = 0;
break;
}
@@ -1794,5 +1777,6 @@ done:
}
strbuf_release(&buf);
free(branch_to_free);
+ discard_index(&the_index);
return ret;
}
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 5d22909122..4767f1a97e 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,8 +1,11 @@
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
-#include "tag.h"
+#include "strbuf.h"
#include "replace-object.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "fsck.h"
#include "config.h"
@@ -14,11 +17,11 @@ static int option_strict = 1;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
-static int mktag_fsck_error_func(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type,
+static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
+ const struct object_id *oid UNUSED,
+ enum object_type object_type UNUSED,
enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
+ enum fsck_msg_id msg_id UNUSED,
const char *message)
{
switch (msg_type) {
@@ -51,7 +54,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
void *buffer;
const struct object_id *repl;
- buffer = read_object_file(tagged_oid, &type, &size);
+ buffer = repo_read_object_file(the_repository, tagged_oid, &type,
+ &size);
if (!buffer)
die(_("could not read tagged object '%s'"),
oid_to_hex(tagged_oid));
@@ -80,7 +84,7 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
int tagged_type;
struct object_id result;
- argc = parse_options(argc, argv, NULL,
+ argc = parse_options(argc, argv, prefix,
builtin_mktag_options,
builtin_mktag_usage, 0);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 06d81400f5..9a22d4e277 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -4,10 +4,13 @@
* Copyright (c) Junio C Hamano, 2006, 2009
*/
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
#include "quote.h"
+#include "strbuf.h"
#include "tree.h"
#include "parse-options.h"
-#include "object-store.h"
+#include "object-store-ll.h"
static struct treeent {
unsigned mode;
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 9a18a82b05..a72aebecaa 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -1,10 +1,13 @@
#include "builtin.h"
-#include "cache.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
#include "midx.h"
+#include "strbuf.h"
#include "trace2.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
@@ -79,6 +82,7 @@ static struct option *add_common_options(struct option *prev)
}
static int git_multi_pack_index_write_config(const char *var, const char *value,
+ const struct config_context *ctx UNUSED,
void *cb UNUSED)
{
if (!strcmp(var, "pack.writebitmaphashcache")) {
diff --git a/builtin/mv.c b/builtin/mv.c
index 3413ad1c9b..22e64fc290 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,15 +3,23 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.h"
#include "pathspec.h"
#include "lockfile.h"
#include "dir.h"
-#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "setup.h"
#include "submodule.h"
#include "entry.h"
@@ -87,7 +95,7 @@ static void prepare_move_submodule(const char *src, int first,
const char **submodule_gitfile)
{
struct strbuf submodule_dotgit = STRBUF_INIT;
- if (!S_ISGITLINK(active_cache[first]->ce_mode))
+ if (!S_ISGITLINK(the_index.cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
if (!is_staging_gitmodules_ok(&the_index))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
@@ -106,13 +114,13 @@ static int index_range_of_same_dir(const char *src, int length,
const char *src_w_slash = add_slash(src);
int first, last, len_w_slash = length + 1;
- first = cache_name_pos(src_w_slash, len_w_slash);
+ first = index_name_pos(&the_index, src_w_slash, len_w_slash);
if (first >= 0)
die(_("%.*s is in index"), len_w_slash, src_w_slash);
first = -1 - first;
- for (last = first; last < active_nr; last++) {
- const char *path = active_cache[last]->name;
+ for (last = first; last < the_index.cache_nr; last++) {
+ const char *path = the_index.cache[last]->name;
if (strncmp(path, src_w_slash, len_w_slash))
break;
}
@@ -136,14 +144,14 @@ static int empty_dir_has_sparse_contents(const char *name)
const char *with_slash = add_slash(name);
int length = strlen(with_slash);
- int pos = cache_name_pos(with_slash, length);
+ int pos = index_name_pos(&the_index, with_slash, length);
const struct cache_entry *ce;
if (pos < 0) {
pos = -pos - 1;
if (pos >= the_index.cache_nr)
goto free_return;
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (strncmp(with_slash, ce->name, length))
goto free_return;
if (ce_skip_worktree(ce))
@@ -175,7 +183,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int src_dir_nr = 0, src_dir_alloc = 0;
struct strbuf a_src_dir = STRBUF_INIT;
enum update_mode *modes, dst_mode = 0;
- struct stat st;
+ struct stat st, dest_st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
@@ -189,8 +197,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (--argc < 1)
usage_with_options(builtin_mv_usage, builtin_mv_options);
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
- if (read_cache() < 0)
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
source = internal_prefix_pathspec(prefix, argv, argc, 0);
@@ -255,7 +263,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int pos;
const struct cache_entry *ce;
- pos = cache_name_pos(src, length);
+ pos = index_name_pos(&the_index, src, length);
if (pos < 0) {
const char *src_w_slash = add_slash(src);
if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
@@ -268,7 +276,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
bad = _("bad source");
goto act_on_entry;
}
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (!ce_skip_worktree(ce)) {
bad = _("bad source");
goto act_on_entry;
@@ -278,7 +286,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
goto act_on_entry;
}
/* Check if dst exists in index */
- if (cache_name_pos(dst, strlen(dst)) < 0) {
+ if (index_name_pos(&the_index, dst, strlen(dst)) < 0) {
modes[i] |= SPARSE;
goto act_on_entry;
}
@@ -295,15 +303,15 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
goto act_on_entry;
}
if (S_ISDIR(st.st_mode)
- && lstat(dst, &st) == 0) {
- bad = _("cannot move directory over file");
+ && lstat(dst, &dest_st) == 0) {
+ bad = _("destination already exists");
goto act_on_entry;
}
dir_check:
if (S_ISDIR(st.st_mode)) {
int j, dst_len, n;
- int first = cache_name_pos(src, length), last;
+ int first = index_name_pos(&the_index, src, length), last;
if (first >= 0) {
prepare_move_submodule(src, first,
@@ -331,7 +339,7 @@ dir_check:
dst_len = strlen(dst);
for (j = 0; j < last - first; j++) {
- const struct cache_entry *ce = active_cache[first + j];
+ const struct cache_entry *ce = the_index.cache[first + j];
const char *path = ce->name;
source[argc + j] = path;
destination[argc + j] =
@@ -343,7 +351,7 @@ dir_check:
argc += last - first;
goto act_on_entry;
}
- if (!(ce = cache_file_exists(src, length, 0))) {
+ if (!(ce = index_file_exists(&the_index, src, length, 0))) {
bad = _("not under version control");
goto act_on_entry;
}
@@ -468,11 +476,14 @@ remove_entry:
if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
continue;
- pos = cache_name_pos(src, strlen(src));
+ pos = index_name_pos(&the_index, src, strlen(src));
assert(pos >= 0);
if (!(mode & SPARSE) && !lstat(src, &st))
- sparse_and_dirty = ce_modified(active_cache[pos], &st, 0);
- rename_cache_entry_at(pos, dst);
+ sparse_and_dirty = ie_modified(&the_index,
+ the_index.cache[pos],
+ &st,
+ 0);
+ rename_index_entry_at(&the_index, pos, dst);
if (ignore_sparse &&
core_apply_sparse_checkout &&
@@ -486,8 +497,9 @@ remove_entry:
if ((mode & SPARSE) &&
path_in_sparse_checkout(dst, &the_index)) {
/* from out-of-cone to in-cone */
- int dst_pos = cache_name_pos(dst, strlen(dst));
- struct cache_entry *dst_ce = active_cache[dst_pos];
+ int dst_pos = index_name_pos(&the_index, dst,
+ strlen(dst));
+ struct cache_entry *dst_ce = the_index.cache[dst_pos];
dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -497,8 +509,9 @@ remove_entry:
!(mode & SPARSE) &&
!path_in_sparse_checkout(dst, &the_index)) {
/* from in-cone to out-of-cone */
- int dst_pos = cache_name_pos(dst, strlen(dst));
- struct cache_entry *dst_ce = active_cache[dst_pos];
+ int dst_pos = index_name_pos(&the_index, dst,
+ strlen(dst));
+ struct cache_entry *dst_ce = the_index.cache[dst_pos];
/*
* if src is clean, it will suffice to remove it
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 15535e914a..2dd1807c4e 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,15 +1,20 @@
#include "builtin.h"
-#include "cache.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tag.h"
#include "refs.h"
+#include "object-name.h"
+#include "pager.h"
#include "parse-options.h"
#include "prio-queue.h"
#include "hash-lookup.h"
#include "commit-slab.h"
#include "commit-graph.h"
+#include "wildmatch.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@@ -108,19 +113,11 @@ static int is_better_name(struct rev_name *name,
int name_distance = effective_distance(name->distance, name->generation);
int new_distance = effective_distance(distance, generation);
- /*
- * When comparing names based on tags, prefer names
- * based on the older tag, even if it is farther away.
- */
+ /* If both are tags, we prefer the nearer one. */
if (from_tag && name->from_tag)
- return (name->taggerdate > taggerdate ||
- (name->taggerdate == taggerdate &&
- name_distance > new_distance));
+ return name_distance > new_distance;
- /*
- * We know that at least one of them is a non-tag at this point.
- * favor a tag over a non-tag.
- */
+ /* Favor a tag over a non-tag. */
if (name->from_tag != from_tag)
return from_tag;
@@ -189,7 +186,7 @@ static void name_rev(struct commit *start_commit,
size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
struct rev_name *start_name;
- parse_commit(start_commit);
+ repo_parse_commit(the_repository, start_commit);
if (commit_is_before_cutoff(start_commit))
return;
@@ -219,7 +216,7 @@ static void name_rev(struct commit *start_commit,
struct rev_name *parent_name;
int generation, distance;
- parse_commit(parent);
+ repo_parse_commit(the_repository, parent);
if (commit_is_before_cutoff(parent))
continue;
@@ -273,17 +270,6 @@ static int subpath_matches(const char *path, const char *filter)
return -1;
}
-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);
- return refname;
-}
-
struct name_ref_data {
int tags_only;
int name_only;
@@ -309,11 +295,19 @@ 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)
{
- refname = name_ref_abbrev(refname, shorten_unambiguous);
+ char *short_refname = NULL;
+
+ if (shorten_unambiguous)
+ short_refname = shorten_unambiguous_ref(refname, 0);
+ else if (skip_prefix(refname, "refs/heads/", &refname))
+ ; /* refname already advanced */
+ else
+ skip_prefix(refname, "refs/", &refname);
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].refname = short_refname ?
+ short_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;
@@ -504,7 +498,8 @@ static void show_name(const struct object *obj,
else if (allow_undefined)
printf("undefined\n");
else if (always)
- printf("%s\n", find_unique_abbrev(oid, DEFAULT_ABBREV));
+ printf("%s\n",
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
else
die("cannot describe '%s'", oid_to_hex(oid));
strbuf_release(&buf);
@@ -538,7 +533,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
counter = 0;
*(p+1) = 0;
- if (!get_oid(p - (hexsz - 1), &oid)) {
+ if (!repo_get_oid(the_repository, p - (hexsz - 1), &oid)) {
struct object *o =
lookup_object(the_repository, &oid);
if (o)
@@ -578,17 +573,17 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
N_("ignore refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
- OPT_BOOL(0, "stdin", &transform_stdin, N_("deprecated: use --annotate-stdin instead")),
+ OPT_BOOL_F(0,
+ "stdin",
+ &transform_stdin,
+ N_("deprecated: use --annotate-stdin instead"),
+ PARSE_OPT_HIDDEN),
OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
- {
- /* A Hidden OPT_BOOL */
- OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
- N_("dereference tags in the input (internal use)"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
- },
+ OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
+ N_("dereference tags in the input (internal use)")),
OPT_END(),
};
@@ -615,7 +610,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
struct object *object;
struct commit *commit;
- if (get_oid(*argv, &oid)) {
+ if (repo_get_oid(the_repository, *argv, &oid)) {
fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
*argv);
continue;
diff --git a/builtin/notes.c b/builtin/notes.c
index be51f69225..e65cae0bcf 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -7,13 +7,17 @@
* and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "notes.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "repository.h"
-#include "blob.h"
#include "pretty.h"
#include "refs.h"
#include "exec-cmd.h"
@@ -23,12 +27,14 @@
#include "notes-merge.h"
#include "notes-utils.h"
#include "worktree.h"
+#include "write-or-die.h"
+static const char *separator = "\n";
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
- N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes-ref>] show [<object>]"),
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -96,11 +102,26 @@ static const char * const git_notes_get_ref_usage[] = {
static const char note_template[] =
N_("Write/edit the notes for the following object:");
+enum notes_stripspace {
+ UNSPECIFIED = -1,
+ NO_STRIPSPACE = 0,
+ STRIPSPACE = 1,
+};
+
+struct note_msg {
+ enum notes_stripspace stripspace;
+ struct strbuf buf;
+};
+
struct note_data {
int given;
int use_editor;
+ int stripspace;
char *edit_path;
struct strbuf buf;
+ struct note_msg **messages;
+ size_t msg_nr;
+ size_t msg_alloc;
};
static void free_note_data(struct note_data *d)
@@ -110,11 +131,18 @@ static void free_note_data(struct note_data *d)
free(d->edit_path);
}
strbuf_release(&d->buf);
+
+ while (d->msg_nr--) {
+ strbuf_release(&d->messages[d->msg_nr]->buf);
+ free(d->messages[d->msg_nr]);
+ }
+ free(d->messages);
}
static int list_each_note(const struct object_id *object_oid,
- const struct object_id *note_oid, char *note_path,
- void *cb_data)
+ const struct object_id *note_oid,
+ char *note_path UNUSED,
+ void *cb_data UNUSED)
{
printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid));
return 0;
@@ -124,7 +152,7 @@ static void copy_obj_to_fd(int fd, const struct object_id *oid)
{
unsigned long size;
enum object_type type;
- char *buf = read_object_file(oid, &type, &size);
+ char *buf = repo_read_object_file(the_repository, oid, &type, &size);
if (buf) {
if (size)
write_or_die(fd, buf, size);
@@ -151,7 +179,7 @@ static void write_commented_object(int fd, const struct object_id *object)
if (strbuf_read(&buf, show.out, 0) < 0)
die_errno(_("could not read 'show' output"));
- strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);
write_or_die(fd, cbuf.buf, cbuf.len);
strbuf_release(&cbuf);
@@ -179,9 +207,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
- strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));
- strbuf_addch(&buf, '\n');
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
+ comment_line_char);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
@@ -193,7 +222,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
if (launch_editor(d->edit_path, &d->buf, NULL)) {
die(_("please supply the note contents using either -m or -F option"));
}
- strbuf_stripspace(&d->buf, 1);
+ if (d->stripspace)
+ strbuf_stripspace(&d->buf, comment_line_char);
}
}
@@ -209,66 +239,102 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
}
}
+static void append_separator(struct strbuf *message)
+{
+ size_t sep_len = 0;
+
+ if (!separator)
+ return;
+ else if ((sep_len = strlen(separator)) && separator[sep_len - 1] == '\n')
+ strbuf_addstr(message, separator);
+ else
+ strbuf_addf(message, "%s%s", separator, "\n");
+}
+
+static void concat_messages(struct note_data *d)
+{
+ struct strbuf msg = STRBUF_INIT;
+ size_t i;
+
+ for (i = 0; i < d->msg_nr ; i++) {
+ if (d->buf.len)
+ append_separator(&d->buf);
+ strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
+ strbuf_addbuf(&d->buf, &msg);
+ if ((d->stripspace == UNSPECIFIED &&
+ d->messages[i]->stripspace == STRIPSPACE) ||
+ d->stripspace == STRIPSPACE)
+ strbuf_stripspace(&d->buf, 0);
+ strbuf_reset(&msg);
+ }
+ strbuf_release(&msg);
+}
+
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- strbuf_grow(&d->buf, strlen(arg) + 2);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
- strbuf_addstr(&d->buf, arg);
- strbuf_stripspace(&d->buf, 0);
-
- d->given = 1;
+ strbuf_init(&msg->buf, strlen(arg));
+ strbuf_addstr(&msg->buf, arg);
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
+ strbuf_init(&msg->buf , 0);
if (!strcmp(arg, "-")) {
- if (strbuf_read(&d->buf, 0, 1024) < 0)
+ if (strbuf_read(&msg->buf, 0, 1024) < 0)
die_errno(_("cannot read '%s'"), arg);
- } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
+ } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
die_errno(_("could not open or read '%s'"), arg);
- strbuf_stripspace(&d->buf, 0);
- d->given = 1;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
- char *buf;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
+ char *value;
struct object_id object;
enum object_type type;
unsigned long len;
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
-
- if (get_oid(arg, &object))
+ strbuf_init(&msg->buf, 0);
+ if (repo_get_oid(the_repository, arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_object_file(&object, &type, &len)))
+ if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
die(_("failed to read object '%s'."), arg);
if (type != OBJ_BLOB) {
- free(buf);
+ strbuf_release(&msg->buf);
+ free(value);
+ free(msg);
die(_("cannot read note data from non-blob object '%s'."), arg);
}
- strbuf_add(&d->buf, buf, len);
- free(buf);
- d->given = 1;
+ strbuf_add(&msg->buf, value, len);
+ free(value);
+
+ msg->buf.len = len;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = NO_STRIPSPACE;
return 0;
}
@@ -280,6 +346,16 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
return parse_reuse_arg(opt, arg, unset);
}
+static int parse_separator_arg(const struct option *opt, const char *arg,
+ int unset)
+{
+ if (unset)
+ *(const char **)opt->value = NULL;
+ else
+ *(const char **)opt->value = arg ? arg : "\n";
+ return 0;
+}
+
static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
{
struct strbuf buf = STRBUF_INIT;
@@ -307,9 +383,9 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
die(_("malformed input line: '%s'."), buf.buf);
strbuf_rtrim(split[0]);
strbuf_rtrim(split[1]);
- if (get_oid(split[0]->buf, &from_obj))
+ if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
- if (get_oid(split[1]->buf, &to_obj))
+ if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
if (rewrite_cmd)
@@ -377,7 +453,7 @@ static int list(int argc, const char **argv, const char *prefix)
t = init_notes_check("list", 0);
if (argc) {
- if (get_oid(argv[0], &object))
+ if (repo_get_oid(the_repository, argv[0], &object))
die(_("failed to resolve '%s' as a valid ref."), argv[0]);
note = get_note(t, &object);
if (note) {
@@ -402,7 +478,8 @@ static int add(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
struct object_id object, new_note;
const struct object_id *note;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -419,6 +496,12 @@ static int add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+ OPT_CALLBACK_F(0, "separator", &separator,
+ N_("<paragraph-break>"),
+ N_("insert <paragraph-break> between paragraphs"),
+ PARSE_OPT_OPTARG, parse_separator_arg),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
@@ -430,9 +513,13 @@ static int add(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_add_usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
object_ref = argc > 1 ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("add", NOTES_INIT_WRITABLE);
@@ -520,12 +607,12 @@ static int copy(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_copy_usage, options);
}
- if (get_oid(argv[0], &from_obj))
+ if (repo_get_oid(the_repository, argv[0], &from_obj))
die(_("failed to resolve '%s' as a valid ref."), argv[0]);
object_ref = 1 < argc ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("copy", NOTES_INIT_WRITABLE);
@@ -568,7 +655,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
const struct object_id *note;
char *logmsg;
const char * const *usage;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -584,6 +671,12 @@ static int append_edit(int argc, const char **argv, const char *prefix)
parse_reuse_arg),
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
+ OPT_CALLBACK_F(0, "separator", &separator,
+ N_("<paragraph-break>"),
+ N_("insert <paragraph-break> between paragraphs"),
+ PARSE_OPT_OPTARG, parse_separator_arg),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
int edit = !strcmp(argv[0], "edit");
@@ -597,6 +690,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
if (d.given && edit)
fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
"for the 'edit' subcommand.\n"
@@ -604,7 +701,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
object_ref = 1 < argc ? argv[1] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
@@ -616,14 +713,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
/* Append buf to previous note contents */
unsigned long size;
enum object_type type;
- char *prev_buf = read_object_file(note, &type, &size);
+ struct strbuf buf = STRBUF_INIT;
+ char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
- strbuf_grow(&d.buf, size + 1);
- if (d.buf.len && prev_buf && size)
- strbuf_insertstr(&d.buf, 0, "\n");
if (prev_buf && size)
- strbuf_insert(&d.buf, 0, prev_buf, size);
+ strbuf_add(&buf, prev_buf, size);
+ if (d.buf.len && prev_buf && size)
+ append_separator(&buf);
+ strbuf_insert(&d.buf, 0, buf.buf, buf.len);
+
free(prev_buf);
+ strbuf_release(&buf);
}
if (d.buf.len || allow_empty) {
@@ -666,7 +766,7 @@ static int show(int argc, const char **argv, const char *prefix)
object_ref = argc ? argv[0] : "HEAD";
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("failed to resolve '%s' as a valid ref."), object_ref);
t = init_notes_check("show", 0);
@@ -716,11 +816,11 @@ static int merge_commit(struct notes_merge_options *o)
* and target notes ref from .git/NOTES_MERGE_REF.
*/
- if (get_oid("NOTES_MERGE_PARTIAL", &oid))
+ if (repo_get_oid(the_repository, "NOTES_MERGE_PARTIAL", &oid))
die(_("failed to read ref NOTES_MERGE_PARTIAL"));
else if (!(partial = lookup_commit_reference(the_repository, &oid)))
die(_("could not find commit from NOTES_MERGE_PARTIAL."));
- else if (parse_commit(partial))
+ else if (repo_parse_commit(the_repository, partial))
die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
if (partial->parents)
@@ -741,7 +841,8 @@ static int merge_commit(struct notes_merge_options *o)
/* Reuse existing commit message in reflog message */
memset(&pretty_ctx, 0, sizeof(pretty_ctx));
- format_commit_message(partial, "%s", &msg, &pretty_ctx);
+ repo_format_commit_message(the_repository, partial, "%s", &msg,
+ &pretty_ctx);
strbuf_trim(&msg);
strbuf_insertstr(&msg, 0, "notes: ");
update_ref(msg.buf, o->local_ref, &oid,
@@ -895,7 +996,7 @@ static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag
{
int status;
struct object_id oid;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return error(_("Failed to resolve '%s' as a valid ref."), name);
status = remove_note(t, oid.hash);
if (status)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 3658c05caf..d8c2128a97 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1,13 +1,13 @@
#include "builtin.h"
-#include "cache.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "config.h"
#include "attr.h"
#include "object.h"
-#include "blob.h"
#include "commit.h"
#include "tag.h"
-#include "tree.h"
#include "delta.h"
#include "pack.h"
#include "pack-revindex.h"
@@ -16,7 +16,6 @@
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "pack-objects.h"
#include "progress.h"
@@ -30,13 +29,16 @@
#include "strvec.h"
#include "list.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "dir.h"
#include "midx.h"
#include "trace2.h"
#include "shallow.h"
#include "promisor-remote.h"
#include "pack-mtimes.h"
+#include "parse-options.h"
/*
* Objects we are going to pack are collected in the `to_pack` structure.
@@ -180,8 +182,8 @@ static inline void oe_set_delta_size(struct packing_data *pack,
#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
static const char *pack_usage[] = {
- N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
- N_("git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]"),
+ N_("git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"),
+ N_("git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"),
NULL
};
@@ -216,13 +218,19 @@ static int thin;
static int num_preferred_base;
static struct progress *progress_state;
-static struct packed_git *reuse_packfile;
+static struct bitmapped_pack *reuse_packfiles;
+static size_t reuse_packfiles_nr;
+static size_t reuse_packfiles_used_nr;
static uint32_t reuse_packfile_objects;
static struct bitmap *reuse_packfile_bitmap;
static int use_bitmap_index_default = 1;
static int use_bitmap_index = -1;
-static int allow_pack_reuse = 1;
+static enum {
+ NO_PACK_REUSE = 0,
+ SINGLE_PACK_REUSE,
+ MULTI_PACK_REUSE,
+} allow_pack_reuse = SINGLE_PACK_REUSE;
static enum {
WRITE_BITMAP_FALSE = 0,
WRITE_BITMAP_QUIET,
@@ -288,11 +296,13 @@ static void *get_delta(struct object_entry *entry)
void *buf, *base_buf, *delta_buf;
enum object_type type;
- buf = read_object_file(&entry->idx.oid, &type, &size);
+ buf = repo_read_object_file(the_repository, &entry->idx.oid, &type,
+ &size);
if (!buf)
die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
- base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
- &base_size);
+ base_buf = repo_read_object_file(the_repository,
+ &DELTA(entry)->idx.oid, &type,
+ &base_size);
if (!base_buf)
die("unable to read %s",
oid_to_hex(&DELTA(entry)->idx.oid));
@@ -454,7 +464,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
&size, NULL)) != NULL)
buf = NULL;
else {
- buf = read_object_file(&entry->idx.oid, &type, &size);
+ buf = repo_read_object_file(the_repository,
+ &entry->idx.oid, &type,
+ &size);
if (!buf)
die(_("unable to read %s"),
oid_to_hex(&entry->idx.oid));
@@ -929,8 +941,10 @@ static struct object_entry **compute_write_order(void)
*/
for_each_tag_ref(mark_tagged, NULL);
- if (use_delta_islands)
+ if (use_delta_islands) {
max_layers = compute_pack_layers(&to_pack);
+ free_island_marks();
+ }
ALLOC_ARRAY(wo, to_pack.nr_objects);
wo_end = 0;
@@ -1002,7 +1016,9 @@ static off_t find_reused_offset(off_t where)
return reused_chunks[lo-1].difference;
}
-static void write_reused_pack_one(size_t pos, struct hashfile *out,
+static void write_reused_pack_one(struct packed_git *reuse_packfile,
+ size_t pos, struct hashfile *out,
+ off_t pack_start,
struct pack_window **w_curs)
{
off_t offset, next, cur;
@@ -1012,7 +1028,8 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
offset = pack_pos_to_offset(reuse_packfile, pos);
next = pack_pos_to_offset(reuse_packfile, pos + 1);
- record_reused_object(offset, offset - hashfile_total(out));
+ record_reused_object(offset,
+ offset - (hashfile_total(out) - pack_start));
cur = offset;
type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
@@ -1080,41 +1097,93 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
}
-static size_t write_reused_pack_verbatim(struct hashfile *out,
+static size_t write_reused_pack_verbatim(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *out,
+ off_t pack_start,
struct pack_window **w_curs)
{
- size_t pos = 0;
+ size_t pos = reuse_packfile->bitmap_pos;
+ size_t end;
+
+ if (pos % BITS_IN_EWORD) {
+ size_t word_pos = (pos / BITS_IN_EWORD);
+ size_t offset = pos % BITS_IN_EWORD;
+ size_t last;
+ eword_t word = reuse_packfile_bitmap->words[word_pos];
+
+ if (offset + reuse_packfile->bitmap_nr < BITS_IN_EWORD)
+ last = offset + reuse_packfile->bitmap_nr;
+ else
+ last = BITS_IN_EWORD;
+
+ for (; offset < last; offset++) {
+ if (word >> offset == 0)
+ return word_pos;
+ if (!bitmap_get(reuse_packfile_bitmap,
+ word_pos * BITS_IN_EWORD + offset))
+ return word_pos;
+ }
+
+ pos += BITS_IN_EWORD - (pos % BITS_IN_EWORD);
+ }
+
+ /*
+ * Now we're going to copy as many whole eword_t's as possible.
+ * "end" is the index of the last whole eword_t we copy, but
+ * there may be additional bits to process. Those are handled
+ * individually by write_reused_pack().
+ *
+ * Begin by advancing to the first word boundary in range of the
+ * bit positions occupied by objects in "reuse_packfile". Then
+ * pick the last word boundary in the same range. If we have at
+ * least one word's worth of bits to process, continue on.
+ */
+ end = reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr;
+ if (end % BITS_IN_EWORD)
+ end -= end % BITS_IN_EWORD;
+ if (pos >= end)
+ return reuse_packfile->bitmap_pos / BITS_IN_EWORD;
- while (pos < reuse_packfile_bitmap->word_alloc &&
- reuse_packfile_bitmap->words[pos] == (eword_t)~0)
- pos++;
+ while (pos < end &&
+ reuse_packfile_bitmap->words[pos / BITS_IN_EWORD] == (eword_t)~0)
+ pos += BITS_IN_EWORD;
- if (pos) {
- off_t to_write;
+ if (pos > end)
+ pos = end;
- written = (pos * BITS_IN_EWORD);
- to_write = pack_pos_to_offset(reuse_packfile, written)
- - sizeof(struct pack_header);
+ if (reuse_packfile->bitmap_pos < pos) {
+ off_t pack_start_off = pack_pos_to_offset(reuse_packfile->p, 0);
+ off_t pack_end_off = pack_pos_to_offset(reuse_packfile->p,
+ pos - reuse_packfile->bitmap_pos);
+
+ written += pos - reuse_packfile->bitmap_pos;
/* We're recording one chunk, not one object. */
- record_reused_object(sizeof(struct pack_header), 0);
+ record_reused_object(pack_start_off,
+ pack_start_off - (hashfile_total(out) - pack_start));
hashflush(out);
- copy_pack_data(out, reuse_packfile, w_curs,
- sizeof(struct pack_header), to_write);
+ copy_pack_data(out, reuse_packfile->p, w_curs,
+ pack_start_off, pack_end_off - pack_start_off);
display_progress(progress_state, written);
}
- return pos;
+ if (pos % BITS_IN_EWORD)
+ BUG("attempted to jump past a word boundary to %"PRIuMAX,
+ (uintmax_t)pos);
+ return pos / BITS_IN_EWORD;
}
-static void write_reused_pack(struct hashfile *f)
+static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
+ struct hashfile *f)
{
- size_t i = 0;
+ size_t i = reuse_packfile->bitmap_pos / BITS_IN_EWORD;
uint32_t offset;
+ off_t pack_start = hashfile_total(f) - sizeof(struct pack_header);
struct pack_window *w_curs = NULL;
if (allow_ofs_delta)
- i = write_reused_pack_verbatim(f, &w_curs);
+ i = write_reused_pack_verbatim(reuse_packfile, f, pack_start,
+ &w_curs);
for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
eword_t word = reuse_packfile_bitmap->words[i];
@@ -1125,16 +1194,23 @@ static void write_reused_pack(struct hashfile *f)
break;
offset += ewah_bit_ctz64(word >> offset);
+ if (pos + offset < reuse_packfile->bitmap_pos)
+ continue;
+ if (pos + offset >= reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr)
+ goto done;
/*
* Can use bit positions directly, even for MIDX
* bitmaps. See comment in try_partial_reuse()
* for why.
*/
- write_reused_pack_one(pos + offset, f, &w_curs);
+ write_reused_pack_one(reuse_packfile->p,
+ pos + offset - reuse_packfile->bitmap_pos,
+ f, pack_start, &w_curs);
display_progress(progress_state, ++written);
}
}
+done:
unuse_pack(&w_curs);
}
@@ -1186,9 +1262,14 @@ static void write_pack_file(void)
offset = write_pack_header(f, nr_remaining);
- if (reuse_packfile) {
+ if (reuse_packfiles_nr) {
assert(pack_to_stdout);
- write_reused_pack(f);
+ for (j = 0; j < reuse_packfiles_nr; j++) {
+ reused_chunks_nr = 0;
+ write_reused_pack(&reuse_packfiles[j], f);
+ if (reused_chunks_nr)
+ reuse_packfiles_used_nr++;
+ }
offset = hashfile_total(f);
}
@@ -1588,7 +1669,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
static int add_object_entry_from_bitmap(const struct object_id *oid,
enum object_type type,
- int flags, uint32_t name_hash,
+ int flags UNUSED, uint32_t name_hash,
struct packed_git *pack, off_t offset)
{
display_progress(progress_state, ++nr_seen);
@@ -1663,7 +1744,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_object_file(oid, &type, &size);
+ data = repo_read_object_file(the_repository, oid, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
@@ -1708,17 +1789,14 @@ static void pbase_tree_put(struct pbase_tree_cache *cache)
free(cache);
}
-static int name_cmp_len(const char *name)
+static size_t name_cmp_len(const char *name)
{
- int i;
- for (i = 0; name[i] && name[i] != '\n' && name[i] != '/'; i++)
- ;
- return i;
+ return strcspn(name, "\n/");
}
static void add_pbase_object(struct tree_desc *tree,
const char *name,
- int cmplen,
+ size_t cmplen,
const char *fullname)
{
struct name_entry entry;
@@ -1743,7 +1821,7 @@ static void add_pbase_object(struct tree_desc *tree,
struct tree_desc sub;
struct pbase_tree_cache *tree;
const char *down = name+cmplen+1;
- int downlen = name_cmp_len(down);
+ size_t downlen = name_cmp_len(down);
tree = pbase_tree_get(&entry.oid);
if (!tree)
@@ -1795,7 +1873,7 @@ static int check_pbase_path(unsigned hash)
static void add_preferred_base_object(const char *name)
{
struct pbase_tree *it;
- int cmplen;
+ size_t cmplen;
unsigned hash = pack_name_hash(name);
if (!num_preferred_base || check_pbase_path(hash))
@@ -2075,7 +2153,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
- if (has_promisor_remote()) {
+ if (repo_has_promisor_remote(the_repository)) {
prefetch_to_pack(object_index);
if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
@@ -2526,7 +2604,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
packing_data_lock(&to_pack);
- trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
+ trg->data = repo_read_object_file(the_repository,
+ &trg_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!trg->data)
die(_("object %s cannot be read"),
@@ -2539,7 +2619,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
}
if (!src->data) {
packing_data_lock(&to_pack);
- src->data = read_object_file(&src_entry->idx.oid, &type, &sz);
+ src->data = repo_read_object_file(the_repository,
+ &src_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!src->data) {
if (src_entry->preferred_base) {
@@ -3121,26 +3203,27 @@ static void prepare_pack(int window, int depth)
free(delta_list);
}
-static int git_pack_config(const char *k, const char *v, void *cb)
+static int git_pack_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(k, "pack.window")) {
- window = git_config_int(k, v);
+ window = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "pack.windowmemory")) {
- window_memory_limit = git_config_ulong(k, v);
+ window_memory_limit = git_config_ulong(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "pack.depth")) {
- depth = git_config_int(k, v);
+ depth = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "pack.deltacachesize")) {
- max_delta_cache_size = git_config_int(k, v);
+ max_delta_cache_size = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "pack.deltacachelimit")) {
- cache_max_small_delta_size = git_config_int(k, v);
+ cache_max_small_delta_size = git_config_int(k, v, ctx->kvi);
return 0;
}
if (!strcmp(k, "pack.writebitmaphashcache")) {
@@ -3162,11 +3245,23 @@ static int git_pack_config(const char *k, const char *v, void *cb)
return 0;
}
if (!strcmp(k, "pack.allowpackreuse")) {
- allow_pack_reuse = git_config_bool(k, v);
+ int res = git_parse_maybe_bool_text(v);
+ if (res < 0) {
+ if (!strcasecmp(v, "single"))
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ else if (!strcasecmp(v, "multi"))
+ allow_pack_reuse = MULTI_PACK_REUSE;
+ else
+ die(_("invalid pack.allowPackReuse value: '%s'"), v);
+ } else if (res) {
+ allow_pack_reuse = SINGLE_PACK_REUSE;
+ } else {
+ allow_pack_reuse = NO_PACK_REUSE;
+ }
return 0;
}
if (!strcmp(k, "pack.threads")) {
- delta_search_threads = git_config_int(k, v);
+ delta_search_threads = git_config_int(k, v, ctx->kvi);
if (delta_search_threads < 0)
die(_("invalid number of threads specified (%d)"),
delta_search_threads);
@@ -3177,7 +3272,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
return 0;
}
if (!strcmp(k, "pack.indexversion")) {
- pack_idx_opts.version = git_config_int(k, v);
+ pack_idx_opts.version = git_config_int(k, v, ctx->kvi);
if (pack_idx_opts.version > 2)
die(_("bad pack.indexVersion=%"PRIu32),
pack_idx_opts.version);
@@ -3191,7 +3286,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
return 0;
}
if (!strcmp(k, "uploadpack.blobpackfileuri")) {
- struct configured_exclusion *ex = xmalloc(sizeof(*ex));
+ struct configured_exclusion *ex;
const char *oid_end, *pack_end;
/*
* Stores the pack hash. This is not a true object ID, but is
@@ -3199,6 +3294,10 @@ static int git_pack_config(const char *k, const char *v, void *cb)
*/
struct object_id pack_hash;
+ if (!v)
+ return config_error_nonbool(k);
+
+ ex = xmalloc(sizeof(*ex));
if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
*oid_end != ' ' ||
parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
@@ -3213,7 +3312,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
ex->uri = xstrdup(pack_end + 1);
oidmap_put(&configured_exclusions, ex);
}
- return git_default_config(k, v, cb);
+ return git_default_config(k, v, ctx, cb);
}
/* Counters for trace2 output when in --stdin-packs mode. */
@@ -3261,13 +3360,14 @@ static int add_object_entry_from_pack(const struct object_id *oid,
return 0;
}
-static void show_commit_pack_hint(struct commit *commit, void *_data)
+static void show_commit_pack_hint(struct commit *commit UNUSED,
+ void *data UNUSED)
{
/* nothing to do; commits don't have a namehash */
}
static void show_object_pack_hint(struct object *object, const char *name,
- void *_data)
+ void *data UNUSED)
{
struct object_entry *oe = packlist_find(&to_pack, &object->oid);
if (!oe)
@@ -3345,16 +3445,16 @@ static void read_packs_list_from_stdin(void)
}
string_list_sort(&include_packs);
+ string_list_remove_duplicates(&include_packs, 0);
string_list_sort(&exclude_packs);
+ string_list_remove_duplicates(&exclude_packs, 0);
for (p = get_all_packs(the_repository); p; p = p->next) {
const char *pack_name = pack_basename(p);
- item = string_list_lookup(&include_packs, pack_name);
- if (!item)
- item = string_list_lookup(&exclude_packs, pack_name);
-
- if (item)
+ if ((item = string_list_lookup(&include_packs, pack_name)))
+ item->util = p;
+ if ((item = string_list_lookup(&exclude_packs, pack_name)))
item->util = p;
}
@@ -3465,7 +3565,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
return;
}
-static void show_cruft_object(struct object *obj, const char *name, void *data)
+static void show_cruft_object(struct object *obj, const char *name, void *data UNUSED)
{
/*
* if we did not record it earlier, it's at least as old as our
@@ -3485,7 +3585,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
show_cruft_object((struct object*)commit, NULL, data);
}
-static int cruft_include_check_obj(struct object *obj, void *data)
+static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
{
return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS);
}
@@ -3589,7 +3689,6 @@ static void read_cruft_objects(void)
string_list_append(&discard_packs, buf.buf + 1);
else
string_list_append(&fresh_packs, buf.buf);
- strbuf_reset(&buf);
}
string_list_sort(&discard_packs);
@@ -3664,7 +3763,7 @@ static void read_object_list_from_stdin(void)
}
}
-static void show_commit(struct commit *commit, void *data)
+static void show_commit(struct commit *commit, void *data UNUSED)
{
add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
@@ -3675,7 +3774,8 @@ static void show_commit(struct commit *commit, void *data)
propagate_island_marks(commit);
}
-static void show_object(struct object *obj, const char *name, void *data)
+static void show_object(struct object *obj, const char *name,
+ void *data UNUSED)
{
add_preferred_base_object(name);
add_object_entry(&obj->oid, obj->type, name, 0);
@@ -3724,7 +3824,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
show_object(obj, name, data);
}
-static int option_parse_missing_action(const struct option *opt,
+static int option_parse_missing_action(const struct option *opt UNUSED,
const char *arg, int unset)
{
assert(arg);
@@ -3762,7 +3862,7 @@ static void show_edge(struct commit *commit)
static int add_object_in_unpacked_pack(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
- void *_data)
+ void *data UNUSED)
{
if (cruft) {
off_t offset;
@@ -3796,7 +3896,7 @@ static void add_objects_in_unpacked_packs(void)
}
static int add_loose_object(const struct object_id *oid, const char *path,
- void *data)
+ void *data UNUSED)
{
enum object_type type = oid_object_info(the_repository, oid, NULL);
@@ -3916,7 +4016,7 @@ static void loosen_unused_packed_objects(void)
*/
static int pack_options_allow_reuse(void)
{
- return allow_pack_reuse &&
+ return allow_pack_reuse != NO_PACK_REUSE &&
pack_to_stdout &&
!ignore_packed_keep_on_disk &&
!ignore_packed_keep_in_core &&
@@ -3929,13 +4029,18 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
return -1;
- if (pack_options_allow_reuse() &&
- !reuse_partial_packfile_from_bitmap(
- bitmap_git,
- &reuse_packfile,
- &reuse_packfile_objects,
- &reuse_packfile_bitmap)) {
- assert(reuse_packfile_objects);
+ if (pack_options_allow_reuse())
+ reuse_partial_packfile_from_bitmap(bitmap_git,
+ &reuse_packfiles,
+ &reuse_packfiles_nr,
+ &reuse_packfile_bitmap,
+ allow_pack_reuse == MULTI_PACK_REUSE);
+
+ if (reuse_packfiles) {
+ reuse_packfile_objects = bitmap_popcount(reuse_packfile_bitmap);
+ if (!reuse_packfile_objects)
+ BUG("expected non-empty reuse bitmap");
+
nr_result += reuse_packfile_objects;
nr_seen += reuse_packfile_objects;
display_progress(progress_state, nr_seen);
@@ -3947,13 +4052,13 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
}
static void record_recent_object(struct object *obj,
- const char *name,
- void *data)
+ const char *name UNUSED,
+ void *data UNUSED)
{
oid_array_append(&recent_objects, &obj->oid);
}
-static void record_recent_commit(struct commit *commit, void *data)
+static void record_recent_commit(struct commit *commit, void *data UNUSED)
{
oid_array_append(&recent_objects, &commit->object.oid);
}
@@ -4102,25 +4207,40 @@ static void add_extra_kept_packs(const struct string_list *names)
}
}
+static int option_parse_quiet(const struct option *opt, const char *arg,
+ int unset)
+{
+ int *val = opt->value;
+
+ BUG_ON_OPT_ARG(arg);
+
+ if (!unset)
+ *val = 0;
+ else if (!*val)
+ *val = 1;
+ return 0;
+}
+
static int option_parse_index_version(const struct option *opt,
const char *arg, int unset)
{
+ struct pack_idx_option *popts = opt->value;
char *c;
const char *val = arg;
BUG_ON_OPT_NEG(unset);
- pack_idx_opts.version = strtoul(val, &c, 10);
- if (pack_idx_opts.version > 2)
+ popts->version = strtoul(val, &c, 10);
+ if (popts->version > 2)
die(_("unsupported index version %s"), val);
if (*c == ',' && c[1])
- pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
- if (*c || pack_idx_opts.off32_limit & 0x80000000)
+ popts->off32_limit = strtoul(c+1, &c, 0);
+ if (*c || popts->off32_limit & 0x80000000)
die(_("bad index version '%s'"), val);
return 0;
}
-static int option_parse_unpack_unreachable(const struct option *opt,
+static int option_parse_unpack_unreachable(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4135,7 +4255,7 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
-static int option_parse_cruft_expiration(const struct option *opt,
+static int option_parse_cruft_expiration(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4149,21 +4269,6 @@ static int option_parse_cruft_expiration(const struct option *opt,
return 0;
}
-struct po_filter_data {
- unsigned have_revs:1;
- struct rev_info revs;
-};
-
-static struct list_objects_filter_options *po_filter_revs_init(void *value)
-{
- struct po_filter_data *data = value;
-
- repo_init_revisions(the_repository, &data->revs, NULL);
- data->have_revs = 1;
-
- return &data->revs.filter;
-}
-
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@@ -4174,11 +4279,13 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int rev_list_index = 0;
int stdin_packs = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- struct po_filter_data pfd = { .have_revs = 0 };
+ struct list_objects_filter_options filter_options =
+ LIST_OBJECTS_FILTER_INIT;
struct option pack_objects_options[] = {
- OPT_SET_INT('q', "quiet", &progress,
- N_("do not show progress meter"), 0),
+ OPT_CALLBACK_F('q', "quiet", &progress, NULL,
+ N_("do not show progress meter"),
+ PARSE_OPT_NOARG, option_parse_quiet),
OPT_SET_INT(0, "progress", &progress,
N_("show progress meter"), 1),
OPT_SET_INT(0, "all-progress", &progress,
@@ -4186,7 +4293,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
- OPT_CALLBACK_F(0, "index-version", NULL, N_("<version>[,<offset>]"),
+ OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
PARSE_OPT_NONEG, option_parse_index_version),
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -4254,8 +4361,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("ignore this pack")),
OPT_INTEGER(0, "compression", &pack_compression_level,
N_("pack compression level")),
- OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
- N_("do not hide commits by grafts"), 0),
+ OPT_BOOL(0, "keep-true-parents", &grafts_keep_true_parents,
+ N_("do not hide commits by grafts")),
OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
N_("use a bitmap index if available to speed up counting objects")),
OPT_SET_INT(0, "write-bitmap-index", &write_bitmap_index,
@@ -4265,7 +4372,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
&write_bitmap_index,
N_("write a bitmap index if possible"),
WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
- OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
N_("handling for missing objects"), PARSE_OPT_NONEG,
option_parse_missing_action),
@@ -4282,7 +4389,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
BUG("too many dfs states, increase OE_DFS_STATE_BITS");
- read_replace_refs = 0;
+ disable_replace_refs();
sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
if (the_repository->gitdir) {
@@ -4292,9 +4399,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
reset_pack_idx_option(&pack_idx_opts);
+ pack_idx_opts.flags |= WRITE_REV;
git_config(git_pack_config, NULL);
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- pack_idx_opts.flags |= WRITE_REV;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ pack_idx_opts.flags &= ~WRITE_REV;
progress = isatty(2);
argc = parse_options(argc, argv, prefix, pack_objects_options,
@@ -4368,7 +4476,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!HAVE_THREADS && delta_search_threads != 1)
warning(_("no threads support, ignoring --threads"));
- if (!pack_to_stdout && !pack_size_limit && !cruft)
+ if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
die(_("--max-pack-size cannot be used to build a pack for transfer"));
@@ -4385,12 +4493,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (pfd.have_revs && pfd.revs.filter.choice) {
- if (!pack_to_stdout)
- die(_("cannot use --filter without --stdout"));
- if (stdin_packs)
- die(_("cannot use --filter with --stdin-packs"));
- }
+ if (stdin_packs && filter_options.choice)
+ die(_("cannot use --filter with --stdin-packs"));
if (stdin_packs && use_internal_rev_list)
die(_("cannot use internal rev list with --stdin-packs"));
@@ -4400,8 +4504,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
die(_("cannot use internal rev list with --cruft"));
if (stdin_packs)
die(_("cannot use --stdin-packs with --cruft"));
- if (pack_size_limit)
- die(_("cannot use --max-pack-size with --cruft"));
}
/*
@@ -4472,13 +4574,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_cruft_objects();
} else if (!use_internal_rev_list) {
read_object_list_from_stdin();
- } else if (pfd.have_revs) {
- get_object_list(&pfd.revs, rp.nr, rp.v);
- release_revisions(&pfd.revs);
} else {
struct rev_info revs;
repo_init_revisions(the_repository, &revs, NULL);
+ list_objects_filter_copy(&revs.filter, &filter_options);
get_object_list(&revs, rp.nr, rp.v);
release_revisions(&revs);
}
@@ -4508,11 +4608,21 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
fprintf_ln(stderr,
_("Total %"PRIu32" (delta %"PRIu32"),"
" reused %"PRIu32" (delta %"PRIu32"),"
- " pack-reused %"PRIu32),
+ " pack-reused %"PRIu32" (from %"PRIuMAX")"),
written, written_delta, reused, reused_delta,
- reuse_packfile_objects);
+ reuse_packfile_objects,
+ (uintmax_t)reuse_packfiles_used_nr);
+
+ trace2_data_intmax("pack-objects", the_repository, "written", written);
+ trace2_data_intmax("pack-objects", the_repository, "written/delta", written_delta);
+ trace2_data_intmax("pack-objects", the_repository, "reused", reused);
+ trace2_data_intmax("pack-objects", the_repository, "reused/delta", reused_delta);
+ trace2_data_intmax("pack-objects", the_repository, "pack-reused", reuse_packfile_objects);
+ trace2_data_intmax("pack-objects", the_repository, "packs-reused", reuse_packfiles_used_nr);
cleanup:
+ clear_packing_data(&to_pack);
+ list_objects_filter_release(&filter_options);
strvec_clear(&rp);
return 0;
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index ed9b9013a5..4c735ba069 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -7,14 +7,16 @@
*/
#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#define BLKSIZE 512
static const char pack_redundant_usage[] =
-"git pack-redundant [--verbose] [--alt-odb] (--all | <filename.pack>...)";
+"git pack-redundant [--verbose] [--alt-odb] (--all | <pack-filename>...)";
static int load_all_packs, verbose, alt_odb;
@@ -557,7 +559,7 @@ static void load_all(void)
}
}
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
{
int i;
int i_still_use_this = 0;
@@ -603,6 +605,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
"option, '--i-still-use-this', on the command line\n"
"and let us know you still use it by sending an e-mail\n"
"to <git@vger.kernel.org>. Thanks.\n"), stderr);
+ die(_("refusing to run without --i-still-use-this"));
}
if (load_all_packs)
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index cfbd5c36c7..bcf383cac9 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,24 +1,48 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
#include "refs.h"
#include "repository.h"
+#include "revision.h"
static char const * const pack_refs_usage[] = {
- N_("git pack-refs [<options>]"),
+ N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
NULL
};
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{
unsigned int flags = PACK_REFS_PRUNE;
+ static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
+ static struct string_list included_refs = STRING_LIST_INIT_NODUP;
+ struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
+ .includes = &included_refs,
+ .flags = flags };
+ static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
+
struct option opts[] = {
- OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL),
- OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+ OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
+ OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+ OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
+ N_("references to include")),
+ OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
+ N_("references to exclude")),
OPT_END(),
};
git_config(git_default_config, NULL);
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
usage_with_options(pack_refs_usage, opts);
- return refs_pack_refs(get_main_ref_store(the_repository), flags);
+
+ for_each_string_list_item(item, &option_excluded_refs)
+ add_ref_exclusion(pack_refs_opts.exclusions, item->string);
+
+ if (pack_refs_opts.flags & PACK_REFS_ALL)
+ string_list_append(pack_refs_opts.includes, "*");
+
+ if (!pack_refs_opts.includes->nr)
+ string_list_append(pack_refs_opts.includes, "refs/tags/*");
+
+ return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
}
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 881fcf3273..3894d2b970 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,7 +1,10 @@
-#include "cache.h"
#include "builtin.h"
#include "config.h"
#include "diff.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "parse-options.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
{
@@ -57,10 +60,12 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
}
static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
- struct strbuf *line_buf, int stable)
+ struct strbuf *line_buf, int stable, int verbatim)
{
int patchlen = 0, found_next = 0;
int before = -1, after = -1;
+ int diff_is_binary = 0;
+ char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1];
git_hash_ctx ctx;
the_hash_algo->init_fn(&ctx);
@@ -71,11 +76,14 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
const char *p = line;
int len;
- if (!skip_prefix(line, "diff-tree ", &p) &&
- !skip_prefix(line, "commit ", &p) &&
+ /* Possibly skip over the prefix added by "log" or "format-patch" */
+ if (!skip_prefix(line, "commit ", &p) &&
!skip_prefix(line, "From ", &p) &&
- starts_with(line, "\\ ") && 12 < strlen(line))
+ starts_with(line, "\\ ") && 12 < strlen(line)) {
+ if (verbatim)
+ the_hash_algo->update_fn(&ctx, line, strlen(line));
continue;
+ }
if (!get_oid_hex(p, next_oid)) {
found_next = 1;
@@ -88,14 +96,44 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
/* Parsing diff header? */
if (before == -1) {
- if (starts_with(line, "index "))
+ if (starts_with(line, "GIT binary patch") ||
+ starts_with(line, "Binary files")) {
+ diff_is_binary = 1;
+ before = 0;
+ the_hash_algo->update_fn(&ctx, pre_oid_str,
+ strlen(pre_oid_str));
+ the_hash_algo->update_fn(&ctx, post_oid_str,
+ strlen(post_oid_str));
+ if (stable)
+ flush_one_hunk(result, &ctx);
+ continue;
+ } else if (skip_prefix(line, "index ", &p)) {
+ char *oid1_end = strstr(line, "..");
+ char *oid2_end = NULL;
+ if (oid1_end)
+ oid2_end = strstr(oid1_end, " ");
+ if (!oid2_end)
+ oid2_end = line + strlen(line) - 1;
+ if (oid1_end != NULL && oid2_end != NULL) {
+ *oid1_end = *oid2_end = '\0';
+ strlcpy(pre_oid_str, p, GIT_MAX_HEXSZ + 1);
+ strlcpy(post_oid_str, oid1_end + 2, GIT_MAX_HEXSZ + 1);
+ }
continue;
- else if (starts_with(line, "--- "))
+ } else if (starts_with(line, "--- "))
before = after = 1;
else if (!isalpha(line[0]))
break;
}
+ if (diff_is_binary) {
+ if (starts_with(line, "diff ")) {
+ diff_is_binary = 0;
+ before = -1;
+ }
+ continue;
+ }
+
/* Looking for a valid hunk header? */
if (before == 0 && after == 0) {
if (starts_with(line, "@@ -")) {
@@ -120,8 +158,8 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
if (line[0] == '+' || line[0] == ' ')
after--;
- /* Compute the sha without whitespace */
- len = remove_space(line);
+ /* Add line to hash algo (possibly removing whitespace) */
+ len = verbatim ? strlen(line) : remove_space(line);
patchlen += len;
the_hash_algo->update_fn(&ctx, line, len);
}
@@ -134,7 +172,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
return patchlen;
}
-static void generate_id_list(int stable)
+static void generate_id_list(int stable, int verbatim)
{
struct object_id oid, n, result;
int patchlen;
@@ -142,44 +180,64 @@ static void generate_id_list(int stable)
oidclr(&oid);
while (!feof(stdin)) {
- patchlen = get_one_patchid(&n, &result, &line_buf, stable);
+ patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim);
flush_current_id(patchlen, &oid, &result);
oidcpy(&oid, &n);
}
strbuf_release(&line_buf);
}
-static const char patch_id_usage[] = "git patch-id [--stable | --unstable]";
+static const char *const patch_id_usage[] = {
+ N_("git patch-id [--stable | --unstable | --verbatim]"), NULL
+};
+
+struct patch_id_opts {
+ int stable;
+ int verbatim;
+};
-static int git_patch_id_config(const char *var, const char *value, void *cb)
+static int git_patch_id_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int *stable = cb;
+ struct patch_id_opts *opts = cb;
if (!strcmp(var, "patchid.stable")) {
- *stable = git_config_bool(var, value);
+ opts->stable = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "patchid.verbatim")) {
+ opts->verbatim = git_config_bool(var, value);
return 0;
}
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
int cmd_patch_id(int argc, const char **argv, const char *prefix)
{
- int stable = -1;
-
- git_config(git_patch_id_config, &stable);
-
- /* If nothing is set, default to unstable. */
- if (stable < 0)
- stable = 0;
-
- if (argc == 2 && !strcmp(argv[1], "--stable"))
- stable = 1;
- else if (argc == 2 && !strcmp(argv[1], "--unstable"))
- stable = 0;
- else if (argc != 1)
- usage(patch_id_usage);
-
- generate_id_list(stable);
+ /* if nothing is set, default to unstable */
+ struct patch_id_opts config = {0, 0};
+ int opts = 0;
+ struct option builtin_patch_id_options[] = {
+ OPT_CMDMODE(0, "unstable", &opts,
+ N_("use the unstable patch-id algorithm"), 1),
+ OPT_CMDMODE(0, "stable", &opts,
+ N_("use the stable patch-id algorithm"), 2),
+ OPT_CMDMODE(0, "verbatim", &opts,
+ N_("don't strip whitespace from the patch"), 3),
+ OPT_END()
+ };
+
+ git_config(git_patch_id_config, &config);
+
+ /* verbatim implies stable */
+ if (config.verbatim)
+ config.stable = 1;
+
+ argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
+ patch_id_usage, 0);
+
+ generate_id_list(opts ? opts > 1 : config.stable,
+ opts ? opts == 3 : config.verbatim);
return 0;
}
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index da3273a268..ca3578e158 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "gettext.h"
#include "parse-options.h"
#include "prune-packed.h"
diff --git a/builtin/prune.c b/builtin/prune.c
index df376b2ed1..57fe31467f 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -1,13 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "diff.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
-#include "builtin.h"
#include "reachable.h"
#include "parse-options.h"
+#include "path.h"
#include "progress.h"
#include "prune-packed.h"
-#include "object-store.h"
+#include "replace-object.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "shallow.h"
static const char * const prune_usage[] = {
@@ -98,7 +105,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
return 0;
}
-static int prune_cruft(const char *basename, const char *path, void *data)
+static int prune_cruft(const char *basename, const char *path,
+ void *data UNUSED)
{
if (starts_with(basename, "tmp_obj_"))
prune_tmp_file(path);
@@ -107,7 +115,8 @@ static int prune_cruft(const char *basename, const char *path, void *data)
return 0;
}
-static int prune_subdir(unsigned int nr, const char *path, void *data)
+static int prune_subdir(unsigned int nr UNUSED, const char *path,
+ void *data UNUSED)
{
if (!show_only)
rmdir(path);
@@ -127,7 +136,9 @@ static void remove_temporary_files(const char *path)
dir = opendir(path);
if (!dir) {
- fprintf(stderr, "Unable to open directory %s\n", path);
+ if (errno != ENOENT)
+ fprintf(stderr, "Unable to open directory %s: %s\n",
+ path, strerror(errno));
return;
}
while ((de = readdir(dir)) != NULL)
@@ -154,7 +165,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
expire = TIME_MAX;
save_commit_buffer = 0;
- read_replace_refs = 0;
+ disable_replace_refs();
repo_init_revisions(the_repository, &revs, prefix);
argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
@@ -166,7 +177,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
struct object_id oid;
const char *name = *argv++;
- if (!get_oid(name, &oid)) {
+ if (!repo_get_oid(the_repository, name, &oid)) {
struct object *object = parse_object_or_die(&oid,
name);
add_pending_object(&revs, object, "");
diff --git a/builtin/pull.c b/builtin/pull.c
index 403a24d7ca..73a68b75b0 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -5,28 +5,29 @@
*
* Fetch one or more remote refs and merge it/them into the current HEAD.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
-#include "config.h"
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge.h"
+#include "object-name.h"
#include "parse-options.h"
-#include "exec-cmd.h"
#include "run-command.h"
#include "oid-array.h"
#include "remote.h"
#include "dir.h"
+#include "path.h"
+#include "read-cache-ll.h"
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "revision.h"
#include "submodule.h"
#include "submodule-config.h"
-#include "tempfile.h"
-#include "lockfile.h"
#include "wt-status.h"
#include "commit-reach.h"
#include "sequencer.h"
-#include "packfile.h"
/**
* Parses the value of --rebase. If value is a false value, returns
@@ -357,10 +358,9 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
/**
* Read config variables.
*/
-static int git_pull_config(const char *var, const char *value, void *cb)
+static int git_pull_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int status;
-
if (!strcmp(var, "rebase.autostash")) {
config_autostash = git_config_bool(var, value);
return 0;
@@ -372,11 +372,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
check_trust_level = 0;
}
- status = git_gpg_config(var, value, cb);
- if (status)
- return status;
-
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
/**
@@ -515,76 +511,75 @@ static void parse_repo_refspecs(int argc, const char **argv, const char **repo,
*/
static int run_fetch(const char *repo, const char **refspecs)
{
- struct strvec args = STRVEC_INIT;
- int ret;
+ struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_pushl(&args, "fetch", "--update-head-ok", NULL);
+ strvec_pushl(&cmd.args, "fetch", "--update-head-ok", NULL);
/* Shared options */
- argv_push_verbosity(&args);
+ argv_push_verbosity(&cmd.args);
if (opt_progress)
- strvec_push(&args, opt_progress);
+ strvec_push(&cmd.args, opt_progress);
/* Options passed to git-fetch */
if (opt_all)
- strvec_push(&args, opt_all);
+ strvec_push(&cmd.args, opt_all);
if (opt_append)
- strvec_push(&args, opt_append);
+ strvec_push(&cmd.args, opt_append);
if (opt_upload_pack)
- strvec_push(&args, opt_upload_pack);
- argv_push_force(&args);
+ strvec_push(&cmd.args, opt_upload_pack);
+ argv_push_force(&cmd.args);
if (opt_tags)
- strvec_push(&args, opt_tags);
+ strvec_push(&cmd.args, opt_tags);
if (opt_prune)
- strvec_push(&args, opt_prune);
+ strvec_push(&cmd.args, opt_prune);
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
switch (recurse_submodules_cli) {
case RECURSE_SUBMODULES_ON:
- strvec_push(&args, "--recurse-submodules=on");
+ strvec_push(&cmd.args, "--recurse-submodules=on");
break;
case RECURSE_SUBMODULES_OFF:
- strvec_push(&args, "--recurse-submodules=no");
+ strvec_push(&cmd.args, "--recurse-submodules=no");
break;
case RECURSE_SUBMODULES_ON_DEMAND:
- strvec_push(&args, "--recurse-submodules=on-demand");
+ strvec_push(&cmd.args, "--recurse-submodules=on-demand");
break;
default:
BUG("submodule recursion option not understood");
}
if (max_children)
- strvec_push(&args, max_children);
+ strvec_push(&cmd.args, max_children);
if (opt_dry_run)
- strvec_push(&args, "--dry-run");
+ strvec_push(&cmd.args, "--dry-run");
if (opt_keep)
- strvec_push(&args, opt_keep);
+ strvec_push(&cmd.args, opt_keep);
if (opt_depth)
- strvec_push(&args, opt_depth);
+ strvec_push(&cmd.args, opt_depth);
if (opt_unshallow)
- strvec_push(&args, opt_unshallow);
+ strvec_push(&cmd.args, opt_unshallow);
if (opt_update_shallow)
- strvec_push(&args, opt_update_shallow);
+ strvec_push(&cmd.args, opt_update_shallow);
if (opt_refmap)
- strvec_push(&args, opt_refmap);
+ strvec_push(&cmd.args, opt_refmap);
if (opt_ipv4)
- strvec_push(&args, opt_ipv4);
+ strvec_push(&cmd.args, opt_ipv4);
if (opt_ipv6)
- strvec_push(&args, opt_ipv6);
+ strvec_push(&cmd.args, opt_ipv6);
if (opt_show_forced_updates > 0)
- strvec_push(&args, "--show-forced-updates");
+ strvec_push(&cmd.args, "--show-forced-updates");
else if (opt_show_forced_updates == 0)
- strvec_push(&args, "--no-show-forced-updates");
+ strvec_push(&cmd.args, "--no-show-forced-updates");
if (set_upstream)
- strvec_push(&args, set_upstream);
- strvec_pushv(&args, opt_fetch.v);
+ strvec_push(&cmd.args, set_upstream);
+ strvec_pushv(&cmd.args, opt_fetch.v);
if (repo) {
- strvec_push(&args, repo);
- strvec_pushv(&args, refspecs);
+ strvec_push(&cmd.args, repo);
+ strvec_pushv(&cmd.args, refspecs);
} else if (*refspecs)
BUG("refspecs without repo?");
- ret = run_command_v_opt(args.v, RUN_GIT_CMD | RUN_CLOSE_OBJECT_STORE);
- strvec_clear(&args);
- return ret;
+ cmd.git_cmd = 1;
+ cmd.close_object_store = 1;
+ return run_command(&cmd);
}
/**
@@ -653,52 +648,50 @@ static int update_submodules(void)
*/
static int run_merge(void)
{
- int ret;
- struct strvec args = STRVEC_INIT;
+ struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_pushl(&args, "merge", NULL);
+ strvec_pushl(&cmd.args, "merge", NULL);
/* Shared options */
- argv_push_verbosity(&args);
+ argv_push_verbosity(&cmd.args);
if (opt_progress)
- strvec_push(&args, opt_progress);
+ strvec_push(&cmd.args, opt_progress);
/* Options passed to git-merge */
if (opt_diffstat)
- strvec_push(&args, opt_diffstat);
+ strvec_push(&cmd.args, opt_diffstat);
if (opt_log)
- strvec_push(&args, opt_log);
+ strvec_push(&cmd.args, opt_log);
if (opt_signoff)
- strvec_push(&args, opt_signoff);
+ strvec_push(&cmd.args, opt_signoff);
if (opt_squash)
- strvec_push(&args, opt_squash);
+ strvec_push(&cmd.args, opt_squash);
if (opt_commit)
- strvec_push(&args, opt_commit);
+ strvec_push(&cmd.args, opt_commit);
if (opt_edit)
- strvec_push(&args, opt_edit);
+ strvec_push(&cmd.args, opt_edit);
if (cleanup_arg)
- strvec_pushf(&args, "--cleanup=%s", cleanup_arg);
+ strvec_pushf(&cmd.args, "--cleanup=%s", cleanup_arg);
if (opt_ff)
- strvec_push(&args, opt_ff);
+ strvec_push(&cmd.args, opt_ff);
if (opt_verify)
- strvec_push(&args, opt_verify);
+ strvec_push(&cmd.args, opt_verify);
if (opt_verify_signatures)
- strvec_push(&args, opt_verify_signatures);
- strvec_pushv(&args, opt_strategies.v);
- strvec_pushv(&args, opt_strategy_opts.v);
+ strvec_push(&cmd.args, opt_verify_signatures);
+ strvec_pushv(&cmd.args, opt_strategies.v);
+ strvec_pushv(&cmd.args, opt_strategy_opts.v);
if (opt_gpg_sign)
- strvec_push(&args, opt_gpg_sign);
+ strvec_push(&cmd.args, opt_gpg_sign);
if (opt_autostash == 0)
- strvec_push(&args, "--no-autostash");
+ strvec_push(&cmd.args, "--no-autostash");
else if (opt_autostash == 1)
- strvec_push(&args, "--autostash");
+ strvec_push(&cmd.args, "--autostash");
if (opt_allow_unrelated_histories > 0)
- strvec_push(&args, "--allow-unrelated-histories");
+ strvec_push(&cmd.args, "--allow-unrelated-histories");
- strvec_push(&args, "FETCH_HEAD");
- ret = run_command_v_opt(args.v, RUN_GIT_CMD);
- strvec_clear(&args);
- return ret;
+ strvec_push(&cmd.args, "FETCH_HEAD");
+ cmd.git_cmd = 1;
+ return run_command(&cmd);
}
/**
@@ -879,43 +872,41 @@ static int get_rebase_newbase_and_upstream(struct object_id *newbase,
static int run_rebase(const struct object_id *newbase,
const struct object_id *upstream)
{
- int ret;
- struct strvec args = STRVEC_INIT;
+ struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_push(&args, "rebase");
+ strvec_push(&cmd.args, "rebase");
/* Shared options */
- argv_push_verbosity(&args);
+ argv_push_verbosity(&cmd.args);
/* Options passed to git-rebase */
if (opt_rebase == REBASE_MERGES)
- strvec_push(&args, "--rebase-merges");
+ strvec_push(&cmd.args, "--rebase-merges");
else if (opt_rebase == REBASE_INTERACTIVE)
- strvec_push(&args, "--interactive");
+ strvec_push(&cmd.args, "--interactive");
if (opt_diffstat)
- strvec_push(&args, opt_diffstat);
- strvec_pushv(&args, opt_strategies.v);
- strvec_pushv(&args, opt_strategy_opts.v);
+ strvec_push(&cmd.args, opt_diffstat);
+ strvec_pushv(&cmd.args, opt_strategies.v);
+ strvec_pushv(&cmd.args, opt_strategy_opts.v);
if (opt_gpg_sign)
- strvec_push(&args, opt_gpg_sign);
+ strvec_push(&cmd.args, opt_gpg_sign);
if (opt_signoff)
- strvec_push(&args, opt_signoff);
+ strvec_push(&cmd.args, opt_signoff);
if (opt_autostash == 0)
- strvec_push(&args, "--no-autostash");
+ strvec_push(&cmd.args, "--no-autostash");
else if (opt_autostash == 1)
- strvec_push(&args, "--autostash");
+ strvec_push(&cmd.args, "--autostash");
if (opt_verify_signatures &&
!strcmp(opt_verify_signatures, "--verify-signatures"))
warning(_("ignoring --verify-signatures for rebase"));
- strvec_push(&args, "--onto");
- strvec_push(&args, oid_to_hex(newbase));
+ strvec_push(&cmd.args, "--onto");
+ strvec_push(&cmd.args, oid_to_hex(newbase));
- strvec_push(&args, oid_to_hex(upstream));
+ strvec_push(&cmd.args, oid_to_hex(upstream));
- ret = run_command_v_opt(args.v, RUN_GIT_CMD);
- strvec_clear(&args);
- return ret;
+ cmd.git_cmd = 1;
+ return run_command(&cmd);
}
static int get_can_ff(struct object_id *orig_head,
@@ -1035,26 +1026,26 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_rebase < 0)
opt_rebase = config_get_rebase(&rebase_unspecified);
- if (read_cache_unmerged())
+ if (repo_read_index_unmerged(the_repository))
die_resolve_conflict("pull");
if (file_exists(git_path_merge_head(the_repository)))
die_conclude_merge();
- if (get_oid("HEAD", &orig_head))
+ if (repo_get_oid(the_repository, "HEAD", &orig_head))
oidclr(&orig_head);
if (opt_rebase) {
if (opt_autostash == -1)
opt_autostash = config_autostash;
- if (is_null_oid(&orig_head) && !is_cache_unborn())
+ if (is_null_oid(&orig_head) && !is_index_unborn(&the_index))
die(_("Updating an unborn branch with changes added to the index."));
if (!opt_autostash)
require_clean_work_tree(the_repository,
N_("pull with rebase"),
- _("please commit or stash them."), 1, 0);
+ _("Please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
oidclr(&rebase_fork_point);
@@ -1066,7 +1057,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_dry_run)
return 0;
- if (get_oid("HEAD", &curr_head))
+ if (repo_get_oid(the_repository, "HEAD", &curr_head))
oidclr(&curr_head);
if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
diff --git a/builtin/push.c b/builtin/push.c
index df0d68e599..2fbb31c3ad 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -1,19 +1,23 @@
/*
* "git push"
*/
-#include "cache.h"
+#include "builtin.h"
+#include "advice.h"
#include "branch.h"
#include "config.h"
-#include "refs.h"
+#include "environment.h"
+#include "gettext.h"
#include "refspec.h"
#include "run-command.h"
-#include "builtin.h"
#include "remote.h"
#include "transport.h"
#include "parse-options.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "submodule.h"
#include "submodule-config.h"
#include "send-pack.h"
+#include "trace2.h"
#include "color.h"
static const char * const push_usage[] = {
@@ -63,16 +67,9 @@ static struct refspec rs = REFSPEC_INIT_PUSH;
static struct string_list push_options_config = STRING_LIST_INIT_DUP;
static void refspec_append_mapped(struct refspec *refspec, const char *ref,
- struct remote *remote, struct ref *local_refs)
+ struct remote *remote, struct ref *matched)
{
const char *branch_name;
- struct ref *matched = NULL;
-
- /* Does "ref" uniquely name our ref? */
- if (count_refspec_match(ref, local_refs, &matched) != 1) {
- refspec_append(refspec, ref);
- return;
- }
if (remote->push.nr) {
struct refspec_item query;
@@ -120,15 +117,28 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
die(_("--delete only accepts plain target ref names"));
refspec_appendf(&rs, ":%s", ref);
} else if (!strchr(ref, ':')) {
- if (!remote) {
- /* lazily grab remote and local_refs */
- remote = remote_get(repo);
+ struct ref *matched = NULL;
+
+ /* lazily grab local_refs */
+ if (!local_refs)
local_refs = get_local_heads();
+
+ /* Does "ref" uniquely name our ref? */
+ if (count_refspec_match(ref, local_refs, &matched) != 1) {
+ refspec_append(&rs, ref);
+ } else {
+ /* lazily grab remote */
+ if (!remote)
+ remote = remote_get(repo);
+ if (!remote)
+ BUG("must get a remote for repo '%s'", repo);
+
+ refspec_append_mapped(&rs, ref, remote, matched);
}
- refspec_append_mapped(&rs, ref, remote, local_refs);
} else
refspec_append(&rs, ref);
}
+ free_refs(local_refs);
}
static int push_url_of_remote(struct remote *remote, const char ***url_p)
@@ -169,8 +179,8 @@ static NORETURN void die_push_simple(struct branch *branch,
if (git_branch_track != BRANCH_TRACK_SIMPLE)
advice_automergesimple_maybe = _("\n"
"To avoid automatically configuring "
- "upstream branches when their name\n"
- "doesn't match the local branch, see option "
+ "an upstream branch when its name\n"
+ "won't match the local branch, see option "
"'simple' of branch.autoSetupMerge\n"
"in 'git help config'.\n");
die(_("The upstream branch of your current branch does not match\n"
@@ -290,21 +300,21 @@ static void setup_default_push_refspecs(int *flags, struct remote *remote)
static const char message_advice_pull_before_push[] =
N_("Updates were rejected because the tip of your current branch is behind\n"
- "its remote counterpart. Integrate the remote changes (e.g.\n"
- "'git pull ...') before pushing again.\n"
+ "its remote counterpart. If you want to integrate the remote changes,\n"
+ "use 'git pull' before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_checkout_pull_push[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
- "counterpart. Check out this branch and integrate the remote changes\n"
- "(e.g. 'git pull ...') before pushing again.\n"
+ "counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+ "before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_ref_fetch_first[] =
- N_("Updates were rejected because the remote contains work that you do\n"
- "not have locally. This is usually caused by another repository pushing\n"
- "to the same ref. You may want to first integrate the remote changes\n"
- "(e.g., 'git pull ...') before pushing again.\n"
+ N_("Updates were rejected because the remote contains work that you do not\n"
+ "have locally. This is usually caused by another repository pushing to\n"
+ "the same ref. If you want to integrate the remote changes, use\n"
+ "'git pull' before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
static const char message_advice_ref_already_exists[] =
@@ -316,10 +326,10 @@ static const char message_advice_ref_needs_force[] =
"without using the '--force' option.\n");
static const char message_advice_ref_needs_update[] =
- N_("Updates were rejected because the tip of the remote-tracking\n"
- "branch has been updated since the last checkout. You may want\n"
- "to integrate those changes locally (e.g., 'git pull ...')\n"
- "before forcing an update.\n");
+ N_("Updates were rejected because the tip of the remote-tracking branch has\n"
+ "been updated since the last checkout. If you want to integrate the\n"
+ "remote changes, use 'git pull' before pushing again.\n"
+ "See the 'Note about fast-forwards' in 'git push --help' for details.");
static void advise_pull_before_push(void)
{
@@ -381,7 +391,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
if (!is_empty_cas(&cas)) {
if (!transport->smart_options)
die("underlying transport does not support --%s option",
- CAS_OPT_NAME);
+ "force-with-lease");
transport->smart_options->cas = &cas;
}
@@ -466,8 +476,16 @@ static int option_parse_recurse_submodules(const struct option *opt,
if (unset)
*recurse_submodules = RECURSE_SUBMODULES_OFF;
- else
- *recurse_submodules = parse_push_recurse_submodules_arg(opt->long_name, arg);
+ else {
+ if (!strcmp(arg, "only-is-on-demand")) {
+ if (*recurse_submodules == RECURSE_SUBMODULES_ONLY) {
+ warning(_("recursing into submodule with push.recurseSubmodules=only; using on-demand instead"));
+ *recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
+ }
+ } else {
+ *recurse_submodules = parse_push_recurse_submodules_arg(opt->long_name, arg);
+ }
+ }
return 0;
}
@@ -490,15 +508,11 @@ static void set_push_cert_flags(int *flags, int v)
}
-static int git_push_config(const char *k, const char *v, void *cb)
+static int git_push_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
const char *slot_name;
int *flags = cb;
- int status;
-
- status = git_gpg_config(k, v, NULL);
- if (status)
- return status;
if (!strcmp(k, "push.followtags")) {
if (git_config_bool(k, v))
@@ -511,26 +525,21 @@ static int git_push_config(const char *k, const char *v, void *cb)
*flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
return 0;
} else if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
- break;
- case 1:
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
+ break;
+ case 1:
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
+ else
+ return error(_("invalid value for '%s'"), k);
}
} else if (!strcmp(k, "push.recursesubmodules")) {
- const char *value;
- if (!git_config_get_value("push.recursesubmodules", &value))
- recurse_submodules = parse_push_recurse_submodules_arg(k, value);
+ recurse_submodules = parse_push_recurse_submodules_arg(k, v);
} else if (!strcmp(k, "submodule.recurse")) {
int val = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
@@ -562,7 +571,7 @@ static int git_push_config(const char *k, const char *v, void *cb)
return 0;
}
- return git_default_config(k, v, NULL);
+ return git_default_config(k, v, ctx, NULL);
}
int cmd_push(int argc, const char **argv, const char *prefix)
@@ -580,15 +589,16 @@ int cmd_push(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT__VERBOSITY(&verbosity),
OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
- OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+ OPT_BIT( 0 , "all", &flags, N_("push all branches"), TRANSPORT_PUSH_ALL),
+ OPT_ALIAS( 0 , "branches", "all"),
OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")),
- OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --branches or --mirror)")),
OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
@@ -611,10 +621,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, option_parse_push_signed),
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
- OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
- TRANSPORT_FAMILY_IPV4),
- OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
- TRANSPORT_FAMILY_IPV6),
+ OPT_IPVERSION(&family),
OPT_END()
};
@@ -626,8 +633,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
: &push_options_config);
set_push_cert_flags(&flags, push_cert);
- if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
- die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--mirror/--tags");
+ die_for_incompatible_opt4(deleterefs, "--delete",
+ tags, "--tags",
+ flags & TRANSPORT_PUSH_ALL, "--all/--branches",
+ flags & TRANSPORT_PUSH_MIRROR, "--mirror");
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
@@ -664,19 +673,13 @@ int cmd_push(int argc, const char **argv, const char *prefix)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (flags & TRANSPORT_PUSH_ALL) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--tags");
if (argc >= 2)
die(_("--all can't be combined with refspecs"));
}
if (flags & TRANSPORT_PUSH_MIRROR) {
- if (tags)
- die(_("options '%s' and '%s' cannot be used together"), "--mirror", "--tags");
if (argc >= 2)
die(_("--mirror can't be combined with refspecs"));
}
- if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
- die(_("options '%s' and '%s' cannot be used together"), "--all", "--mirror");
if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
cas.use_force_if_includes = 1;
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e2a74efb42..f02cbac087 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -1,9 +1,10 @@
-#include "cache.h"
#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
#include "parse-options.h"
#include "range-diff.h"
#include "config.h"
-#include "revision.h"
+#include "repository.h"
static const char * const builtin_range_diff_usage[] = {
N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
@@ -47,7 +48,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
repo_diff_setup(the_repository, &diffopt);
- options = parse_options_concat(range_diff_options, diffopt.parseopts);
+ options = add_diff_options(range_diff_options, &diffopt);
argc = parse_options(argc, argv, prefix, options,
builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
@@ -65,20 +66,20 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
if (dash_dash == 3 ||
(dash_dash < 0 && argc > 2 &&
- !get_oid_committish(argv[0], &oid) &&
- !get_oid_committish(argv[1], &oid) &&
- !get_oid_committish(argv[2], &oid))) {
+ !repo_get_oid_committish(the_repository, argv[0], &oid) &&
+ !repo_get_oid_committish(the_repository, argv[1], &oid) &&
+ !repo_get_oid_committish(the_repository, argv[2], &oid))) {
if (dash_dash < 0)
; /* already validated arguments */
- else if (get_oid_committish(argv[0], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[0], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[0]);
- else if (get_oid_committish(argv[1], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[1], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[1]);
- else if (get_oid_committish(argv[2], &oid))
+ else if (repo_get_oid_committish(the_repository, argv[2], &oid))
usage_msg_optf(_("not a revision: '%s'"),
builtin_range_diff_usage, options,
argv[2]);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 9f1f33e954..20e7db1973 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -4,21 +4,24 @@
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "object.h"
+#include "object-name.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
#include "unpack-trees.h"
-#include "dir.h"
-#include "builtin.h"
#include "parse-options.h"
+#include "repository.h"
#include "resolve-undo.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
static int nr_trees;
static int read_empty;
@@ -38,11 +41,13 @@ static int list_tree(struct object_id *oid)
}
static const char * const read_tree_usage[] = {
- N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
+ N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)\n"
+ " [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
+ " (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
NULL
};
-static int index_output_cb(const struct option *opt, const char *arg,
+static int index_output_cb(const struct option *opt UNUSED, const char *arg,
int unset)
{
BUG_ON_OPT_NEG(unset);
@@ -85,9 +90,9 @@ static int debug_merge(const struct cache_entry * const *stages,
{
int i;
- printf("* %d-way merge\n", o->merge_size);
+ printf("* %d-way merge\n", o->internal.merge_size);
debug_stage("index", stages[0], o);
- for (i = 1; i <= o->merge_size; i++) {
+ for (i = 1; i <= o->internal.merge_size; i++) {
char buf[24];
xsnprintf(buf, sizeof(buf), "ent#%d", i);
debug_stage(buf, stages[i], o);
@@ -95,12 +100,13 @@ static int debug_merge(const struct cache_entry * const *stages,
return 0;
}
-static int git_read_tree_config(const char *var, const char *value, void *cb)
+static int git_read_tree_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "submodule.recurse"))
return git_default_submodule_config(var, value, cb);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
@@ -112,6 +118,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
int prefix_set = 0;
struct lock_file lock_file = LOCK_INIT;
const struct option read_tree_options[] = {
+ OPT__SUPER_PREFIX(&opts.super_prefix),
OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
N_("write resulting index to <file>"),
PARSE_OPT_NONEG, index_output_cb),
@@ -141,7 +148,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
OPT_BOOL(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
N_("skip applying sparse checkout filter")),
- OPT_BOOL(0, "debug-unpack", &opts.debug_unpack,
+ OPT_BOOL(0, "debug-unpack", &opts.internal.debug_unpack,
N_("debug unpack-trees")),
OPT_CALLBACK_F(0, "recurse-submodules", NULL,
"checkout", "control recursive updating of submodules",
@@ -174,7 +181,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
/*
* NEEDSWORK
@@ -186,16 +193,16 @@ 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))
+ if (repo_read_index_unmerged(the_repository) && (opts.prefix || opts.merge))
die(_("You need to resolve your current index first"));
stage = opts.merge = 1;
}
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die("Not a valid object name %s", arg);
if (list_tree(&oid) < 0)
die("failed to unpack tree object %s", arg);
@@ -230,7 +237,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
break;
case 2:
opts.fn = twoway_merge;
- opts.initial_checkout = is_cache_unborn();
+ opts.initial_checkout = is_index_unborn(&the_index);
break;
case 3:
default:
@@ -244,10 +251,14 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
opts.head_idx = 1;
}
- if (opts.debug_unpack)
+ if (opts.internal.debug_unpack)
opts.fn = debug_merge;
- cache_tree_free(&active_cache_tree);
+ /* If we're going to prime_cache_tree later, skip cache tree update */
+ if (nr_trees == 1 && !opts.prefix)
+ opts.skip_cache_tree_update = 1;
+
+ cache_tree_free(&the_index.cache_tree);
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
parse_tree(tree);
@@ -256,7 +267,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (unpack_trees(nr_trees, t, &opts))
return 128;
- if (opts.debug_unpack || opts.dry_run)
+ if (opts.internal.debug_unpack || opts.dry_run)
return 0; /* do not write the index out */
/*
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 56e4214b44..995818c28d 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -4,20 +4,23 @@
* Copyright (c) 2018 Pratik Karki
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "run-command.h"
-#include "exec-cmd.h"
#include "strvec.h"
#include "dir.h"
-#include "packfile.h"
#include "refs.h"
-#include "quote.h"
#include "config.h"
-#include "cache-tree.h"
#include "unpack-trees.h"
#include "lockfile.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "commit.h"
#include "diff.h"
#include "wt-status.h"
@@ -28,10 +31,9 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "trace2.h"
#include "hook.h"
-#define DEFAULT_REFLOG_ACTION "rebase"
-
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] "
"[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
@@ -59,6 +61,26 @@ enum empty_type {
EMPTY_ASK
};
+enum action {
+ ACTION_NONE = 0,
+ ACTION_CONTINUE,
+ ACTION_SKIP,
+ ACTION_ABORT,
+ ACTION_QUIT,
+ ACTION_EDIT_TODO,
+ ACTION_SHOW_CURRENT_PATCH
+};
+
+static const char *action_names[] = {
+ "undefined",
+ "continue",
+ "skip",
+ "abort",
+ "quit",
+ "edit_todo",
+ "show_current_patch"
+};
+
struct rebase_options {
enum rebase_type type;
enum empty_type empty;
@@ -68,7 +90,7 @@ struct rebase_options {
const char *upstream_name;
const char *upstream_arg;
char *head_name;
- struct object_id orig_head;
+ struct commit *orig_head;
struct commit *onto;
const char *onto_name;
const char *revisions;
@@ -85,7 +107,8 @@ struct rebase_options {
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
} flags;
struct strvec git_am_opts;
- const char *action;
+ enum action action;
+ char *reflog_action;
int signoff;
int allow_rerere_autoupdate;
int keep_empty;
@@ -94,15 +117,19 @@ struct rebase_options {
int autostash;
int committer_date_is_author_date;
int ignore_date;
- char *cmd;
+ struct string_list exec;
int allow_empty_message;
int rebase_merges, rebase_cousins;
- char *strategy, *strategy_opts;
+ char *strategy;
+ struct string_list strategy_opts;
struct strbuf git_format_patch_opt;
int reschedule_failed_exec;
int reapply_cherry_picks;
int fork_point;
int update_refs;
+ int config_autosquash;
+ int config_rebase_merges;
+ int config_update_refs;
};
#define REBASE_OPTIONS_INIT { \
@@ -112,8 +139,17 @@ struct rebase_options {
.default_backend = "merge", \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
+ .exec = STRING_LIST_INIT_NODUP, \
.git_format_patch_opt = STRBUF_INIT, \
.fork_point = -1, \
+ .reapply_cherry_picks = -1, \
+ .allow_empty_message = 1, \
+ .autosquash = -1, \
+ .rebase_merges = -1, \
+ .config_rebase_merges = -1, \
+ .update_refs = -1, \
+ .config_update_refs = -1, \
+ .strategy_opts = STRING_LIST_INIT_NODUP,\
}
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -139,6 +175,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
opts->committer_date_is_author_date;
replay.ignore_date = opts->ignore_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
+ replay.reflog_action = xstrdup(opts->reflog_action);
if (opts->strategy)
replay.strategy = xstrdup_or_null(opts->strategy);
else if (!replay.strategy && replay.default_strategy) {
@@ -146,8 +183,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.default_strategy = NULL;
}
- if (opts->strategy_opts)
- parse_strategy_opts(&replay, opts->strategy_opts);
+ for (size_t i = 0; i < opts->strategy_opts.nr; i++)
+ strvec_push(&replay.xopts, opts->strategy_opts.items[i].string);
if (opts->squash_onto) {
oidcpy(&replay.squash_onto, opts->squash_onto);
@@ -157,24 +194,6 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
return replay;
}
-enum action {
- ACTION_NONE = 0,
- ACTION_CONTINUE,
- ACTION_SKIP,
- ACTION_ABORT,
- ACTION_QUIT,
- ACTION_EDIT_TODO,
- ACTION_SHOW_CURRENT_PATCH
-};
-
-static const char *action_names[] = { "undefined",
- "continue",
- "skip",
- "abort",
- "quit",
- "edit_todo",
- "show_current_patch" };
-
static int edit_todo_file(unsigned flags)
{
const char *todo_file = rebase_path_todo();
@@ -185,7 +204,7 @@ static int edit_todo_file(unsigned flags)
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- strbuf_stripspace(&todo_list.buf, 1);
+ strbuf_stripspace(&todo_list.buf, comment_line_char);
res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
@@ -207,13 +226,15 @@ static int get_revision_ranges(struct commit *upstream, struct commit *onto,
*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
oid_to_hex(orig_head));
- shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
+ shorthead = repo_find_unique_abbrev(the_repository, orig_head,
+ DEFAULT_ABBREV);
if (upstream) {
const char *shortrev;
- shortrev = find_unique_abbrev(&base_rev->object.oid,
- DEFAULT_ABBREV);
+ shortrev = repo_find_unique_abbrev(the_repository,
+ &base_rev->object.oid,
+ DEFAULT_ABBREV);
*shortrevisions = xstrfmt("%s..%s", shortrev, shorthead);
} else
@@ -241,38 +262,22 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,
return write_basic_state(opts, head_name, onto, orig_head);
}
-static void split_exec_commands(const char *cmd, struct string_list *commands)
-{
- if (cmd && *cmd) {
- string_list_split(commands, cmd, '\n', -1);
-
- /* rebase.c adds a new line to cmd after every command,
- * so here the last command is always empty */
- string_list_remove_empty_items(commands, 0);
- }
-}
-
static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
{
- int ret;
+ int ret = -1;
char *revisions = NULL, *shortrevisions = NULL;
struct strvec make_script_args = STRVEC_INIT;
struct todo_list todo_list = TODO_LIST_INIT;
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,
+ if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
&revisions, &shortrevisions))
- return -1;
+ goto cleanup;
if (init_basic_state(&replay,
opts->head_name ? opts->head_name : "detached HEAD",
- opts->onto, &opts->orig_head)) {
- free(revisions);
- free(shortrevisions);
-
- return -1;
- }
+ opts->onto, &opts->orig_head->object.oid))
+ goto cleanup;
if (!opts->upstream && opts->squash_onto)
write_file(path_squash_onto(), "%s\n",
@@ -290,20 +295,19 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
if (ret)
error(_("could not generate todo list"));
else {
- discard_cache();
+ discard_index(&the_index);
if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,
&todo_list))
BUG("unusable todo list");
- split_exec_commands(opts->cmd, &commands);
ret = complete_action(the_repository, &replay, flags,
shortrevisions, opts->onto_name, opts->onto,
- &opts->orig_head, &commands, opts->autosquash,
- opts->update_refs,
- &todo_list);
+ &opts->orig_head->object.oid, &opts->exec,
+ opts->autosquash, opts->update_refs, &todo_list);
}
- string_list_clear(&commands, 0);
+cleanup:
+ replay_opts_release(&replay);
free(revisions);
free(shortrevisions);
todo_list_release(&todo_list);
@@ -312,8 +316,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
return ret;
}
-static int run_sequencer_rebase(struct rebase_options *opts,
- enum action command)
+static int run_sequencer_rebase(struct rebase_options *opts)
{
unsigned flags = 0;
int abbreviate_commands = 0, ret = 0;
@@ -328,7 +331,7 @@ static int run_sequencer_rebase(struct rebase_options *opts,
flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
flags |= opts->flags & REBASE_NO_QUIET ? TODO_LIST_WARN_SKIPPED_CHERRY_PICKS : 0;
- switch (command) {
+ switch (opts->action) {
case ACTION_NONE: {
if (!opts->onto && !opts->upstream)
die(_("a base commit must be provided with --upstream or --onto"));
@@ -346,6 +349,7 @@ static int run_sequencer_rebase(struct rebase_options *opts,
struct replay_opts replay_opts = get_replay_opts(opts);
ret = sequencer_continue(the_repository, &replay_opts);
+ replay_opts_release(&replay_opts);
break;
}
case ACTION_EDIT_TODO:
@@ -361,26 +365,12 @@ static int run_sequencer_rebase(struct rebase_options *opts,
break;
}
default:
- BUG("invalid command '%d'", command);
+ BUG("invalid command '%d'", opts->action);
}
return ret;
}
-static void imply_merge(struct rebase_options *opts, const char *option);
-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);
-
- imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
- opts->keep_empty = !unset;
- opts->type = REBASE_MERGE;
- return 0;
-}
-
static int is_merge(struct rebase_options *opts)
{
return opts->type == REBASE_MERGE;
@@ -431,9 +421,9 @@ static int read_basic_state(struct rebase_options *opts)
opts->head_name = starts_with(head_name.buf, "refs/") ?
xstrdup(head_name.buf) : NULL;
strbuf_release(&head_name);
- if (get_oid(buf.buf, &oid))
- return error(_("could not get 'onto': '%s'"), buf.buf);
- opts->onto = lookup_commit_or_die(&oid, buf.buf);
+ if (get_oid_hex(buf.buf, &oid) ||
+ !(opts->onto = lookup_commit_object(the_repository, &oid)))
+ return error(_("invalid onto: '%s'"), buf.buf);
/*
* We always write to orig-head, but interactive rebase used to write to
@@ -448,7 +438,8 @@ static int read_basic_state(struct rebase_options *opts)
} else if (!read_oneliner(&buf, state_dir_path("head", opts),
READ_ONELINER_WARN_MISSING))
return -1;
- if (get_oid(buf.buf, &opts->orig_head))
+ if (get_oid_hex(buf.buf, &oid) ||
+ !(opts->orig_head = lookup_commit_object(the_repository, &oid)))
return error(_("invalid orig-head: '%s'"), buf.buf);
if (file_exists(state_dir_path("quiet", opts)))
@@ -487,24 +478,6 @@ static int read_basic_state(struct rebase_options *opts)
opts->gpg_sign_opt = xstrdup(buf.buf);
}
- if (file_exists(state_dir_path("strategy", opts))) {
- strbuf_reset(&buf);
- if (!read_oneliner(&buf, state_dir_path("strategy", opts),
- READ_ONELINER_WARN_MISSING))
- return -1;
- free(opts->strategy);
- opts->strategy = xstrdup(buf.buf);
- }
-
- if (file_exists(state_dir_path("strategy_opts", opts))) {
- strbuf_reset(&buf);
- if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts),
- READ_ONELINER_WARN_MISSING))
- return -1;
- free(opts->strategy_opts);
- opts->strategy_opts = xstrdup(buf.buf);
- }
-
strbuf_release(&buf);
return 0;
@@ -517,17 +490,11 @@ static int rebase_write_basic_state(struct rebase_options *opts)
write_file(state_dir_path("onto", opts), "%s",
opts->onto ? oid_to_hex(&opts->onto->object.oid) : "");
write_file(state_dir_path("orig-head", opts), "%s",
- oid_to_hex(&opts->orig_head));
+ oid_to_hex(&opts->orig_head->object.oid));
if (!(opts->flags & REBASE_NO_QUIET))
write_file(state_dir_path("quiet", opts), "%s", "");
if (opts->flags & REBASE_VERBOSE)
write_file(state_dir_path("verbose", opts), "%s", "");
- if (opts->strategy)
- write_file(state_dir_path("strategy", opts), "%s",
- opts->strategy);
- if (opts->strategy_opts)
- write_file(state_dir_path("strategy_opts", opts), "%s",
- opts->strategy_opts);
if (opts->allow_rerere_autoupdate > 0)
write_file(state_dir_path("allow_rerere_autoupdate", opts),
"-%s-rerere-autoupdate",
@@ -560,6 +527,7 @@ static int finish_rebase(struct rebase_options *opts)
replay.action = REPLAY_INTERACTIVE_REBASE;
ret = sequencer_remove_state(&replay);
+ replay_opts_release(&replay);
} else {
strbuf_addstr(&dir, opts->state_dir);
if (remove_dir_recursively(&dir, 0))
@@ -583,10 +551,11 @@ static int move_to_original_branch(struct rebase_options *opts)
if (!opts->onto)
BUG("move_to_original_branch without onto");
- strbuf_addf(&branch_reflog, "rebase finished: %s onto %s",
+ strbuf_addf(&branch_reflog, "%s (finish): %s onto %s",
+ opts->reflog_action,
opts->head_name, oid_to_hex(&opts->onto->object.oid));
- strbuf_addf(&head_reflog, "rebase finished: returning to %s",
- opts->head_name);
+ strbuf_addf(&head_reflog, "%s (finish): returning to %s",
+ opts->reflog_action, opts->head_name);
ropts.branch = opts->head_name;
ropts.flags = RESET_HEAD_REFS_ONLY;
ropts.branch_msg = branch_reflog.buf;
@@ -609,14 +578,14 @@ static int run_am(struct rebase_options *opts)
{
struct child_process am = CHILD_PROCESS_INIT;
struct child_process format_patch = CHILD_PROCESS_INIT;
- struct strbuf revisions = STRBUF_INIT;
int status;
char *rebased_patches;
am.git_cmd = 1;
strvec_push(&am.args, "am");
-
- if (opts->action && !strcmp("continue", opts->action)) {
+ strvec_pushf(&am.env, GIT_REFLOG_ACTION_ENVIRONMENT "=%s (pick)",
+ opts->reflog_action);
+ if (opts->action == ACTION_CONTINUE) {
strvec_push(&am.args, "--resolved");
strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
if (opts->gpg_sign_opt)
@@ -627,7 +596,7 @@ static int run_am(struct rebase_options *opts)
return move_to_original_branch(opts);
}
- if (opts->action && !strcmp("skip", opts->action)) {
+ if (opts->action == ACTION_SKIP) {
strvec_push(&am.args, "--skip");
strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
status = run_command(&am);
@@ -636,18 +605,11 @@ static int run_am(struct rebase_options *opts)
return move_to_original_branch(opts);
}
- if (opts->action && !strcmp("show-current-patch", opts->action)) {
+ if (opts->action == ACTION_SHOW_CURRENT_PATCH) {
strvec_push(&am.args, "--show-current-patch");
return run_command(&am);
}
- strbuf_addf(&revisions, "%s...%s",
- oid_to_hex(opts->root ?
- /* this is now equivalent to !opts->upstream */
- &opts->onto->object.oid :
- &opts->upstream->object.oid),
- oid_to_hex(&opts->orig_head));
-
rebased_patches = xstrdup(git_path("rebased-patches"));
format_patch.out = open(rebased_patches,
O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -662,13 +624,18 @@ static int run_am(struct rebase_options *opts)
format_patch.git_cmd = 1;
strvec_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
"--full-index", "--cherry-pick", "--right-only",
- "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
+ "--default-prefix", "--no-renames",
"--no-cover-letter", "--pretty=mboxrd", "--topo-order",
"--no-base", NULL);
if (opts->git_format_patch_opt.len)
strvec_split(&format_patch.args,
opts->git_format_patch_opt.buf);
- strvec_push(&format_patch.args, revisions.buf);
+ strvec_pushf(&format_patch.args, "%s...%s",
+ oid_to_hex(opts->root ?
+ /* this is now equivalent to !opts->upstream */
+ &opts->onto->object.oid :
+ &opts->upstream->object.oid),
+ oid_to_hex(&opts->orig_head->object.oid));
if (opts->restrict_revision)
strvec_pushf(&format_patch.args, "^%s",
oid_to_hex(&opts->restrict_revision->object.oid));
@@ -680,9 +647,9 @@ static int run_am(struct rebase_options *opts)
free(rebased_patches);
strvec_clear(&am.args);
- ropts.oid = &opts->orig_head;
+ ropts.oid = &opts->orig_head->object.oid;
ropts.branch = opts->head_name;
- ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
+ ropts.default_reflog_action = opts->reflog_action;
reset_head(the_repository, &ropts);
error(_("\ngit encountered an error while preparing the "
"patches to replay\n"
@@ -691,10 +658,8 @@ static int run_am(struct rebase_options *opts)
"As a result, git cannot rebase them."),
opts->revisions);
- strbuf_release(&revisions);
return status;
}
- strbuf_release(&revisions);
am.in = open(rebased_patches, O_RDONLY);
if (am.in < 0) {
@@ -729,17 +694,15 @@ static int run_am(struct rebase_options *opts)
return status;
}
-static int run_specific_rebase(struct rebase_options *opts, enum action action)
+static int run_specific_rebase(struct rebase_options *opts)
{
int status;
if (opts->type == REBASE_MERGE) {
/* Run sequencer-based rebase */
setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1);
- if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
+ if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))
setenv("GIT_SEQUENCE_EDITOR", ":", 1);
- opts->autosquash = 0;
- }
if (opts->gpg_sign_opt) {
/* remove the leading "-S" */
char *tmp = xstrdup(opts->gpg_sign_opt + 2);
@@ -747,7 +710,7 @@ 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_sequencer_rebase(opts);
} else if (opts->type == REBASE_APPLY)
status = run_am(opts);
else
@@ -773,7 +736,18 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
return status ? -1 : 0;
}
-static int rebase_config(const char *var, const char *value, void *data)
+static void parse_rebase_merges_value(struct rebase_options *options, const char *value)
+{
+ if (!strcmp("no-rebase-cousins", value))
+ options->rebase_cousins = 0;
+ else if (!strcmp("rebase-cousins", value))
+ options->rebase_cousins = 1;
+ else
+ die(_("Unknown rebase-merges mode: %s"), value);
+}
+
+static int rebase_config(const char *var, const char *value,
+ const struct config_context *ctx, void *data)
{
struct rebase_options *opts = data;
@@ -786,7 +760,7 @@ static int rebase_config(const char *var, const char *value, void *data)
}
if (!strcmp(var, "rebase.autosquash")) {
- opts->autosquash = git_config_bool(var, value);
+ opts->config_autosquash = git_config_bool(var, value);
return 0;
}
@@ -802,8 +776,19 @@ static int rebase_config(const char *var, const char *value, void *data)
return 0;
}
+ if (!strcmp(var, "rebase.rebasemerges")) {
+ opts->config_rebase_merges = git_parse_maybe_bool(value);
+ if (opts->config_rebase_merges < 0) {
+ opts->config_rebase_merges = 1;
+ parse_rebase_merges_value(opts, value);
+ } else {
+ opts->rebase_cousins = 0;
+ }
+ return 0;
+ }
+
if (!strcmp(var, "rebase.updaterefs")) {
- opts->update_refs = git_config_bool(var, value);
+ opts->config_update_refs = git_config_bool(var, value);
return 0;
}
@@ -821,7 +806,7 @@ static int rebase_config(const char *var, const char *value, void *data)
return git_config_string(&opts->default_backend, var, value);
}
- return git_default_config(var, value, data);
+ return git_default_config(var, value, ctx, data);
}
static int checkout_up_to_date(struct rebase_options *options)
@@ -831,9 +816,8 @@ static int checkout_up_to_date(struct rebase_options *options)
int ret = 0;
strbuf_addf(&buf, "%s: checkout %s",
- getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
- options->switch_to);
- ropts.oid = &options->orig_head;
+ options->reflog_action, options->switch_to);
+ ropts.oid = &options->orig_head->object.oid;
ropts.branch = options->head_name;
ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
if (!ropts.branch)
@@ -854,7 +838,7 @@ static int checkout_up_to_date(struct rebase_options *options)
static int is_linear_history(struct commit *from, struct commit *to)
{
while (to && to != from) {
- parse_commit(to);
+ repo_parse_commit(the_repository, to);
if (!to->parents)
return 1;
if (to->parents->next)
@@ -866,33 +850,24 @@ static int is_linear_history(struct commit *from, struct commit *to)
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)
+ struct commit *head, struct object_id *branch_base)
{
- struct commit *head = lookup_commit(the_repository, head_oid);
struct commit_list *merge_bases = NULL;
int res = 0;
- if (!head)
- goto done;
+ if (is_null_oid(branch_base))
+ goto done; /* fill_branch_base() found multiple merge bases */
- merge_bases = get_merge_bases(onto, head);
- if (!merge_bases || merge_bases->next) {
- oidcpy(merge_base, null_oid());
+ if (!oideq(branch_base, &onto->object.oid))
goto done;
- }
- 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))
+ if (restrict_revision && !oideq(&restrict_revision->object.oid, branch_base))
goto done;
if (!upstream)
goto done;
- free_commit_list(merge_bases);
- merge_bases = get_merge_bases(upstream, head);
+ merge_bases = repo_get_merge_bases(the_repository, upstream, head);
if (!merge_bases || merge_bases->next)
goto done;
@@ -906,6 +881,21 @@ done:
return res && is_linear_history(onto, head);
}
+static void fill_branch_base(struct rebase_options *options,
+ struct object_id *branch_base)
+{
+ struct commit_list *merge_bases = NULL;
+
+ merge_bases = repo_get_merge_bases(the_repository, options->onto,
+ options->orig_head);
+ if (!merge_bases || merge_bases->next)
+ oidcpy(branch_base, null_oid());
+ else
+ oidcpy(branch_base, &merge_bases->item->object.oid);
+
+ free_commit_list(merge_bases);
+}
+
static int parse_opt_am(const struct option *opt, const char *arg, int unset)
{
struct rebase_options *opts = opt->value;
@@ -913,6 +903,9 @@ static int parse_opt_am(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_APPLY)
+ die(_("apply options and merge options cannot be used together"));
+
opts->type = REBASE_APPLY;
return 0;
@@ -926,8 +919,10 @@ 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))
- opts->type = REBASE_MERGE;
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+ die(_("apply options and merge options cannot be used together"));
+
+ opts->type = REBASE_MERGE;
return 0;
}
@@ -941,6 +936,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+ die(_("apply options and merge options cannot be used together"));
+
opts->type = REBASE_MERGE;
opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
@@ -959,6 +957,18 @@ static enum empty_type parse_empty_value(const char *value)
die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value);
}
+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);
+
+ imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
+ opts->keep_empty = !unset;
+ return 0;
+}
+
static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
{
struct rebase_options *options = opt->value;
@@ -970,6 +980,28 @@ static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int parse_opt_rebase_merges(const struct option *opt, const char *arg, int unset)
+{
+ struct rebase_options *options = opt->value;
+
+ options->rebase_merges = !unset;
+ options->rebase_cousins = 0;
+
+ if (arg) {
+ if (!*arg) {
+ warning(_("--rebase-merges with an empty string "
+ "argument is deprecated and will stop "
+ "working in a future version of Git. Use "
+ "--rebase-merges without an argument "
+ "instead, which does the same thing."));
+ return 0;
+ }
+ parse_rebase_merges_value(options, arg);
+ }
+
+ return 0;
+}
+
static void NORETURN error_on_missing_default_upstream(void)
{
struct branch *current_branch = branch_get(NULL);
@@ -1000,23 +1032,6 @@ static void NORETURN error_on_missing_default_upstream(void)
exit(1);
}
-static void set_reflog_action(struct rebase_options *options)
-{
- const char *env;
- struct strbuf buf = STRBUF_INIT;
-
- if (!is_merge(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);
- setenv(GIT_REFLOG_ACTION_ENVIRONMENT, buf.buf, 1);
- strbuf_release(&buf);
-}
-
static int check_exec_cmd(const char *cmd)
{
if (strchr(cmd, '\n'))
@@ -1039,15 +1054,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct strbuf msg = STRBUF_INIT;
struct strbuf revisions = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
- struct object_id merge_base;
+ struct object_id branch_base;
int ignore_whitespace = 0;
- enum action action = ACTION_NONE;
const char *gpg_sign = NULL;
- struct string_list exec = STRING_LIST_INIT_NODUP;
- const char *rebase_merges = NULL;
- struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
char *squash_onto_name = NULL;
+ char *keep_base_onto_name = NULL;
int reschedule_failed_exec = -1;
int allow_preemptive_ff = 1;
int preserve_merges_selected = 0;
@@ -1090,18 +1102,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "no-ff", &options.flags,
N_("cherry-pick all commits, even if unchanged"),
REBASE_FORCE),
- OPT_CMDMODE(0, "continue", &action, N_("continue"),
+ OPT_CMDMODE(0, "continue", &options.action, N_("continue"),
ACTION_CONTINUE),
- OPT_CMDMODE(0, "skip", &action,
+ OPT_CMDMODE(0, "skip", &options.action,
N_("skip current patch and continue"), ACTION_SKIP),
- OPT_CMDMODE(0, "abort", &action,
+ OPT_CMDMODE(0, "abort", &options.action,
N_("abort and check out the original branch"),
ACTION_ABORT),
- OPT_CMDMODE(0, "quit", &action,
+ OPT_CMDMODE(0, "quit", &options.action,
N_("abort but keep HEAD where it is"), ACTION_QUIT),
- OPT_CMDMODE(0, "edit-todo", &action, N_("edit the todo list "
+ OPT_CMDMODE(0, "edit-todo", &options.action, N_("edit the todo list "
"during an interactive rebase"), ACTION_EDIT_TODO),
- OPT_CMDMODE(0, "show-current-patch", &action,
+ OPT_CMDMODE(0, "show-current-patch", &options.action,
N_("show the patch file being applied or merged"),
ACTION_SHOW_CURRENT_PATCH),
OPT_CALLBACK_F(0, "apply", &options, NULL,
@@ -1121,7 +1133,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"instead of ignoring them"),
1, PARSE_OPT_HIDDEN),
OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
- OPT_CALLBACK_F(0, "empty", &options, "{drop,keep,ask}",
+ OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|ask)",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
@@ -1138,22 +1150,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_AUTOSTASH(&options.autostash),
- OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+ OPT_STRING_LIST('x', "exec", &options.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),
- {OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
- N_("mode"),
+ OPT_CALLBACK_F('r', "rebase-merges", &options, N_("mode"),
N_("try to rebase merges instead of skipping them"),
- PARSE_OPT_OPTARG, NULL, (intptr_t)""},
+ PARSE_OPT_OPTARG, parse_opt_rebase_merges),
OPT_BOOL(0, "fork-point", &options.fork_point,
N_("use 'merge-base --fork-point' to refine upstream")),
OPT_STRING('s', "strategy", &options.strategy,
N_("strategy"), N_("use the given merge strategy")),
- OPT_STRING_LIST('X', "strategy-option", &strategy_options,
+ OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
N_("option"),
N_("pass the argument through to the merge "
"strategy")),
@@ -1175,7 +1186,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- options.allow_empty_message = 1;
git_config(rebase_config, &options);
/* options.gpg_sign_opt will be either "-S" or NULL */
gpg_sign = options.gpg_sign_opt ? "" : NULL;
@@ -1192,7 +1202,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else if (is_directory(merge_dir())) {
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/rewritten", merge_dir());
- if (!(action == ACTION_ABORT) && is_directory(buf.buf)) {
+ if (!(options.action == ACTION_ABORT) && is_directory(buf.buf)) {
die(_("`rebase --preserve-merges` (-p) is no longer supported.\n"
"Use `git rebase --abort` to terminate current rebase.\n"
"Or downgrade to v2.33, or earlier, to complete the rebase."));
@@ -1219,7 +1229,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
"which is no longer supported; use 'merges' instead"));
- if (action != ACTION_NONE && total_argc != 2) {
+ if (options.action != ACTION_NONE && total_argc != 2) {
usage_with_options(builtin_rebase_usage,
builtin_rebase_options);
}
@@ -1233,42 +1243,47 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--onto");
if (options.root)
die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--root");
+ /*
+ * --keep-base defaults to --no-fork-point to keep the
+ * base the same.
+ */
+ if (options.fork_point < 0)
+ options.fork_point = 0;
}
-
if (options.root && options.fork_point > 0)
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
- if (action != ACTION_NONE && !in_progress)
+ if (options.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 (options.action == ACTION_EDIT_TODO && !is_merge(&options))
die(_("The --edit-todo action can only be used during "
"interactive rebase."));
if (trace2_is_enabled()) {
if (is_merge(&options))
trace2_cmd_mode("interactive");
- else if (exec.nr)
+ else if (options.exec.nr)
trace2_cmd_mode("interactive-exec");
else
- trace2_cmd_mode(action_names[action]);
+ trace2_cmd_mode(action_names[options.action]);
}
- switch (action) {
+ options.reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
+ options.reflog_action =
+ xstrdup(options.reflog_action ? options.reflog_action : "rebase");
+
+ switch (options.action) {
case ACTION_CONTINUE: {
struct object_id head;
struct lock_file lock_file = LOCK_INIT;
int fd;
- options.action = "continue";
- set_reflog_action(&options);
-
/* Sanity check */
- if (get_oid("HEAD", &head))
+ if (repo_get_oid(the_repository, "HEAD", &head))
die(_("Cannot read HEAD"));
- fd = hold_locked_index(&lock_file, 0);
+ fd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL,
@@ -1289,9 +1304,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
case ACTION_SKIP: {
struct string_list merge_rr = STRING_LIST_INIT_DUP;
- options.action = "skip";
- set_reflog_action(&options);
-
rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
ropts.flags = RESET_HEAD_HARD;
@@ -1304,21 +1316,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
case ACTION_ABORT: {
struct string_list merge_rr = STRING_LIST_INIT_DUP;
- options.action = "abort";
- set_reflog_action(&options);
+ struct strbuf head_msg = STRBUF_INIT;
rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
if (read_basic_state(&options))
exit(1);
- ropts.oid = &options.orig_head;
+
+ strbuf_addf(&head_msg, "%s (abort): returning to %s",
+ options.reflog_action,
+ options.head_name ? options.head_name
+ : oid_to_hex(&options.orig_head->object.oid));
+ ropts.oid = &options.orig_head->object.oid;
+ ropts.head_msg = head_msg.buf;
ropts.branch = options.head_name;
ropts.flags = RESET_HEAD_HARD;
- ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
if (reset_head(the_repository, &ropts) < 0)
die(_("could not move back to %s"),
- oid_to_hex(&options.orig_head));
+ oid_to_hex(&options.orig_head->object.oid));
+ strbuf_release(&head_msg);
remove_branch_state(the_repository, 0);
ret = finish_rebase(&options);
goto cleanup;
@@ -1330,6 +1347,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
replay.action = REPLAY_INTERACTIVE_REBASE;
ret = sequencer_remove_state(&replay);
+ replay_opts_release(&replay);
} else {
strbuf_reset(&buf);
strbuf_addstr(&buf, options.state_dir);
@@ -1341,17 +1359,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
goto cleanup;
}
case ACTION_EDIT_TODO:
- options.action = "edit-todo";
options.dont_finish_rebase = 1;
goto run_rebase;
case ACTION_SHOW_CURRENT_PATCH:
- options.action = "show-current-patch";
options.dont_finish_rebase = 1;
goto run_rebase;
case ACTION_NONE:
break;
default:
- BUG("action: %d", action);
+ BUG("action: %d", options.action);
}
/* Make sure no rebase is in progress */
@@ -1375,9 +1391,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
- (action != ACTION_NONE) ||
- (exec.nr > 0) ||
- options.autosquash) {
+ (options.action != ACTION_NONE) ||
+ (options.exec.nr > 0) ||
+ options.autosquash == 1) {
allow_preemptive_ff = 0;
}
if (options.committer_date_is_author_date || options.ignore_date)
@@ -1400,8 +1416,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
}
- for (i = 0; i < exec.nr; i++)
- if (check_exec_cmd(exec.items[i].string))
+ for (i = 0; i < options.exec.nr; i++)
+ if (check_exec_cmd(options.exec.items[i].string))
exit(1);
if (!(options.flags & REBASE_NO_QUIET))
@@ -1410,34 +1426,34 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty != EMPTY_UNSPECIFIED)
imply_merge(&options, "--empty");
- if (options.reapply_cherry_picks)
- imply_merge(&options, "--reapply-cherry-picks");
+ if (options.reapply_cherry_picks < 0)
+ /*
+ * We default to --no-reapply-cherry-picks unless
+ * --keep-base is given; when --keep-base is given, we want
+ * to default to --reapply-cherry-picks.
+ */
+ options.reapply_cherry_picks = keep_base;
+ else if (!keep_base)
+ /*
+ * The apply backend always searches for and drops cherry
+ * picks. This is often not wanted with --keep-base, so
+ * --keep-base allows --reapply-cherry-picks to be
+ * simulated by altering the upstream such that
+ * cherry-picks cannot be detected and thus all commits are
+ * reapplied. Thus, --[no-]reapply-cherry-picks is
+ * supported when --keep-base is specified, but not when
+ * --keep-base is left out.
+ */
+ imply_merge(&options, options.reapply_cherry_picks ?
+ "--reapply-cherry-picks" :
+ "--no-reapply-cherry-picks");
if (gpg_sign)
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
- if (exec.nr) {
- int i;
-
+ if (options.exec.nr)
imply_merge(&options, "--exec");
- strbuf_reset(&buf);
- for (i = 0; i < exec.nr; i++)
- strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
- options.cmd = xstrdup(buf.buf);
- }
-
- if (rebase_merges) {
- if (!*rebase_merges)
- ; /* default mode; do nothing */
- else if (!strcmp("rebase-cousins", rebase_merges))
- options.rebase_cousins = 1;
- else if (strcmp("no-rebase-cousins", rebase_merges))
- die(_("Unknown mode: %s"), rebase_merges);
- options.rebase_merges = 1;
- imply_merge(&options, "--rebase-merges");
- }
-
if (options.type == REBASE_APPLY) {
if (ignore_whitespace)
strvec_push(&options.git_am_opts,
@@ -1450,43 +1466,19 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else {
/* REBASE_MERGE */
if (ignore_whitespace) {
- string_list_append(&strategy_options,
+ string_list_append(&options.strategy_opts,
"ignore-space-change");
}
}
- if (strategy_options.nr) {
- int i;
-
- if (!options.strategy)
- options.strategy = "ort";
-
- strbuf_reset(&buf);
- for (i = 0; i < strategy_options.nr; i++)
- strbuf_addf(&buf, " --%s",
- strategy_options.items[i].string);
- options.strategy_opts = xstrdup(buf.buf);
- }
+ if (options.strategy_opts.nr && !options.strategy)
+ options.strategy = "ort";
if (options.strategy) {
options.strategy = xstrdup(options.strategy);
- switch (options.type) {
- case REBASE_APPLY:
- die(_("--strategy requires --merge or --interactive"));
- case REBASE_MERGE:
- /* compatible */
- break;
- case REBASE_UNSPECIFIED:
- options.type = REBASE_MERGE;
- break;
- default:
- BUG("unhandled rebase type (%d)", options.type);
- }
+ imply_merge(&options, "--strategy");
}
- if (options.type == REBASE_MERGE)
- imply_merge(&options, "--merge");
-
if (options.root && !options.onto_name)
imply_merge(&options, "--root without --onto");
@@ -1499,18 +1491,40 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (strcmp(options.git_am_opts.v[i], "-q"))
break;
- if (i >= 0) {
+ if (i >= 0 || options.type == REBASE_APPLY) {
if (is_merge(&options))
die(_("apply options and merge options "
"cannot be used together"));
+ else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
+ die(_("apply options are incompatible with rebase.rebaseMerges. Consider adding --no-rebase-merges"));
+ else if (options.update_refs == -1 && options.config_update_refs == 1)
+ die(_("apply options are incompatible with rebase.updateRefs. Consider adding --no-update-refs"));
else
options.type = REBASE_APPLY;
}
}
+ if (options.update_refs == 1)
+ imply_merge(&options, "--update-refs");
+ options.update_refs = (options.update_refs >= 0) ? options.update_refs :
+ ((options.config_update_refs >= 0) ? options.config_update_refs : 0);
+
+ if (options.rebase_merges == 1)
+ imply_merge(&options, "--rebase-merges");
+ options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
+ ((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
+
+ if (options.autosquash == 1) {
+ imply_merge(&options, "--autosquash");
+ } else if (options.autosquash == -1) {
+ options.autosquash =
+ options.config_autosquash &&
+ (options.flags & REBASE_INTERACTIVE_EXPLICIT);
+ }
+
if (options.type == REBASE_UNSPECIFIED) {
if (!strcmp(options.default_backend, "merge"))
- imply_merge(&options, "--merge");
+ options.type = REBASE_MERGE;
else if (!strcmp(options.default_backend, "apply"))
options.type = REBASE_APPLY;
else
@@ -1537,7 +1551,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
options.empty = EMPTY_ASK;
- else if (exec.nr > 0)
+ else if (options.exec.nr > 0)
options.empty = EMPTY_KEEP;
else
options.empty = EMPTY_DROP;
@@ -1604,25 +1618,27 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
*/
if (argc == 1) {
/* Is it "rebase other branchname" or "rebase other commit"? */
+ struct object_id branch_oid;
branch_name = argv[0];
options.switch_to = argv[0];
/* Is it a local branch? */
strbuf_reset(&buf);
strbuf_addf(&buf, "refs/heads/%s", branch_name);
- if (!read_ref(buf.buf, &options.orig_head)) {
+ if (!read_ref(buf.buf, &branch_oid)) {
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
+ options.orig_head =
+ lookup_commit_object(the_repository,
+ &branch_oid);
/* If not is it a valid ref (branch or commit)? */
} else {
- struct commit *commit =
+ options.orig_head =
lookup_commit_reference_by_name(branch_name);
- if (!commit)
- die(_("no such branch/commit '%s'"),
- branch_name);
- oidcpy(&options.orig_head, &commit->object.oid);
options.head_name = NULL;
}
+ if (!options.orig_head)
+ die(_("no such branch/commit '%s'"), branch_name);
} else if (argc == 0) {
/* Do not need to switch branches, we are already on it. */
options.head_name =
@@ -1639,8 +1655,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
FREE_AND_NULL(options.head_name);
branch_name = "HEAD";
}
- if (get_oid("HEAD", &options.orig_head))
- die(_("Could not resolve HEAD to a revision"));
+ options.orig_head = lookup_commit_reference_by_name("HEAD");
+ if (!options.orig_head)
+ die(_("Could not resolve HEAD to a commit"));
} else
BUG("unexpected number of arguments left to parse");
@@ -1650,11 +1667,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_addstr(&buf, options.upstream_name);
strbuf_addstr(&buf, "...");
strbuf_addstr(&buf, branch_name);
- options.onto_name = xstrdup(buf.buf);
+ options.onto_name = keep_base_onto_name = xstrdup(buf.buf);
} else 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 (repo_get_oid_mb(the_repository, options.onto_name, &branch_base) < 0) {
if (keep_base)
die(_("'%s': need exactly one merge base with branch"),
options.upstream_name);
@@ -1662,7 +1679,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("'%s': need exactly one merge base"),
options.onto_name);
}
- options.onto = lookup_commit_or_die(&merge_base,
+ options.onto = lookup_commit_or_die(&branch_base,
options.onto_name);
} else {
options.onto =
@@ -1670,15 +1687,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (!options.onto)
die(_("Does not point to a valid commit '%s'"),
options.onto_name);
+ fill_branch_base(&options, &branch_base);
}
- if (options.fork_point > 0) {
- struct commit *head =
- lookup_commit_reference(the_repository,
- &options.orig_head);
+ if (keep_base && options.reapply_cherry_picks)
+ options.upstream = options.onto;
+
+ if (options.fork_point > 0)
options.restrict_revision =
- get_fork_point(options.upstream_name, head);
- }
+ get_fork_point(options.upstream_name, options.orig_head);
if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
@@ -1703,13 +1720,10 @@ 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.
*/
- if (can_fast_forward(options.onto, options.upstream, options.restrict_revision,
- &options.orig_head, &merge_base) &&
- allow_preemptive_ff) {
+ if (allow_preemptive_ff &&
+ can_fast_forward(options.onto, options.upstream, options.restrict_revision,
+ options.orig_head, &branch_base)) {
int flag;
if (!(options.flags & REBASE_FORCE)) {
@@ -1750,25 +1764,24 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct diff_options opts;
if (options.flags & REBASE_VERBOSE) {
- if (is_null_oid(&merge_base))
+ if (is_null_oid(&branch_base))
printf(_("Changes to %s:\n"),
oid_to_hex(&options.onto->object.oid));
else
printf(_("Changes from %s to %s:\n"),
- oid_to_hex(&merge_base),
+ oid_to_hex(&branch_base),
oid_to_hex(&options.onto->object.oid));
}
/* We want color (if set), but no pager */
- diff_setup(&opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ repo_diff_setup(the_repository, &opts);
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
diff_setup_done(&opts);
- diff_tree_oid(is_null_oid(&merge_base) ?
- the_hash_algo->empty_tree : &merge_base,
+ diff_tree_oid(is_null_oid(&branch_base) ?
+ the_hash_algo->empty_tree : &branch_base,
&options.onto->object.oid, "", &opts);
diffcore_std(&opts);
diff_flush(&opts);
@@ -1782,14 +1795,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
printf(_("First, rewinding head to replay your work on top of "
"it...\n"));
- strbuf_addf(&msg, "%s: checkout %s",
- getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
+ strbuf_addf(&msg, "%s (start): checkout %s",
+ options.reflog_action, options.onto_name);
ropts.oid = &options.onto->object.oid;
- ropts.orig_head = &options.orig_head,
+ ropts.orig_head = &options.orig_head->object.oid,
ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
ropts.head_msg = msg.buf;
- ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
+ ropts.default_reflog_action = options.reflog_action;
if (reset_head(the_repository, &ropts))
die(_("Could not detach HEAD"));
strbuf_release(&msg);
@@ -1798,19 +1811,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
* If the onto is a proper descendant of the tip of the branch, then
* we just fast-forwarded.
*/
- strbuf_reset(&msg);
- if (oideq(&merge_base, &options.orig_head)) {
+ if (oideq(&branch_base, &options.orig_head->object.oid)) {
printf(_("Fast-forwarded %s to %s.\n"),
branch_name, options.onto_name);
- strbuf_addf(&msg, "rebase finished: %s onto %s",
- options.head_name ? options.head_name : "detached HEAD",
- oid_to_hex(&options.onto->object.oid));
- memset(&ropts, 0, sizeof(ropts));
- ropts.branch = options.head_name;
- ropts.flags = RESET_HEAD_REFS_ONLY;
- ropts.head_msg = msg.buf;
- reset_head(the_repository, &ropts);
- strbuf_release(&msg);
+ move_to_original_branch(&options);
ret = finish_rebase(&options);
goto cleanup;
}
@@ -1820,21 +1824,25 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
(options.restrict_revision ?
oid_to_hex(&options.restrict_revision->object.oid) :
oid_to_hex(&options.upstream->object.oid)),
- oid_to_hex(&options.orig_head));
+ oid_to_hex(&options.orig_head->object.oid));
options.revisions = revisions.buf;
run_rebase:
- ret = run_specific_rebase(&options, action);
+ ret = run_specific_rebase(&options);
cleanup:
strbuf_release(&buf);
strbuf_release(&revisions);
+ free(options.reflog_action);
free(options.head_name);
+ strvec_clear(&options.git_am_opts);
free(options.gpg_sign_opt);
- free(options.cmd);
+ string_list_clear(&options.exec, 0);
free(options.strategy);
+ string_list_clear(&options.strategy_opts, 0);
strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name);
+ free(keep_base_onto_name);
return !!ret;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 44bcea3a5b..e36b1d619f 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1,6 +1,10 @@
#include "builtin.h"
+#include "abspath.h"
#include "repository.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "lockfile.h"
#include "pack.h"
#include "refs.h"
@@ -18,18 +22,23 @@
#include "connected.h"
#include "strvec.h"
#include "version.h"
-#include "tag.h"
#include "gpg-interface.h"
#include "sigchain.h"
#include "fsck.h"
#include "tmp-objdir.h"
#include "oidset.h"
#include "packfile.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "protocol.h"
#include "commit-reach.h"
+#include "server-info.h"
+#include "trace.h"
+#include "trace2.h"
#include "worktree.h"
#include "shallow.h"
+#include "parse-options.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -80,6 +89,7 @@ static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
static const char *cert_nonce_seed;
+static struct strvec hidden_refs = STRVEC_INIT;
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
static const char *NONCE_BAD = "BAD";
@@ -128,17 +138,15 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
return DENY_IGNORE;
}
-static int receive_pack_config(const char *var, const char *value, void *cb)
+static int receive_pack_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int status = parse_hide_refs_config(var, value, "receive");
+ const char *msg_id;
+ int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
if (status)
return status;
- status = git_gpg_config(var, value, NULL);
- if (status)
- return status;
-
if (strcmp(var, "receive.denydeletes") == 0) {
deny_deletes = git_config_bool(var, value);
return 0;
@@ -150,12 +158,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
}
if (strcmp(var, "receive.unpacklimit") == 0) {
- receive_unpack_limit = git_config_int(var, value);
+ receive_unpack_limit = git_config_int(var, value, ctx->kvi);
return 0;
}
if (strcmp(var, "transfer.unpacklimit") == 0) {
- transfer_unpack_limit = git_config_int(var, value);
+ transfer_unpack_limit = git_config_int(var, value, ctx->kvi);
return 0;
}
@@ -170,12 +178,14 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
- if (skip_prefix(var, "receive.fsck.", &var)) {
- if (is_valid_msg_type(var, value))
+ if (skip_prefix(var, "receive.fsck.", &msg_id)) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (is_valid_msg_type(msg_id, value))
strbuf_addf(&fsck_msg_types, "%c%s=%s",
- fsck_msg_types.len ? ',' : '=', var, value);
+ fsck_msg_types.len ? ',' : '=', msg_id, value);
else
- warning("skipping unknown msg id '%s'", var);
+ warning("skipping unknown msg id '%s'", msg_id);
return 0;
}
@@ -223,7 +233,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return git_config_string(&cert_nonce_seed, var, value);
if (strcmp(var, "receive.certnonceslop") == 0) {
- nonce_stamp_slop_limit = git_config_ulong(var, value);
+ nonce_stamp_slop_limit = git_config_ulong(var, value, ctx->kvi);
return 0;
}
@@ -238,12 +248,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
}
if (strcmp(var, "receive.keepalive") == 0) {
- keepalive_in_sec = git_config_int(var, value);
+ keepalive_in_sec = git_config_int(var, value, ctx->kvi);
return 0;
}
if (strcmp(var, "receive.maxinputsize") == 0) {
- max_input_size = git_config_int64(var, value);
+ max_input_size = git_config_int64(var, value, ctx->kvi);
return 0;
}
@@ -259,7 +269,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static void show_ref(const char *path, const struct object_id *oid)
@@ -296,7 +306,7 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
struct oidset *seen = data;
const char *path = strip_namespace(path_full);
- if (ref_is_hidden(path, path_full))
+ if (ref_is_hidden(path, path_full, &hidden_refs))
return 0;
/*
@@ -330,7 +340,9 @@ static void write_head_info(void)
{
static struct oidset seen = OIDSET_INIT;
- for_each_ref(show_ref_cb, &seen);
+ refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
+ hidden_refs_to_excludes(&hidden_refs),
+ show_ref_cb, &seen);
for_each_alternate_ref(show_one_alternate_ref, &seen);
oidset_clear(&seen);
if (!sent_capabilities)
@@ -1346,7 +1358,7 @@ static int head_has_history(void)
{
struct object_id oid;
- return !get_oid("HEAD", &oid);
+ return !repo_get_oid(the_repository, "HEAD", &oid);
}
static const char *push_to_deploy(unsigned char *sha1,
@@ -1462,8 +1474,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
find_shared_symref(worktrees, "HEAD", name);
/* only refs/... are allowed */
- if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
- rp_error("refusing to create funny ref '%s' remotely", name);
+ if (!starts_with(name, "refs/") ||
+ check_refname_format(name + 5, is_null_oid(new_oid) ?
+ REFNAME_ALLOW_ONELEVEL : 0)) {
+ rp_error("refusing to update funny ref '%s' remotely", name);
ret = "funny refname";
goto out;
}
@@ -1493,7 +1507,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
}
- if (!is_null_oid(new_oid) && !has_object_file(new_oid)) {
+ if (!is_null_oid(new_oid) && !repo_has_object_file(the_repository, new_oid)) {
error("unpack should have generated %s, "
"but I can't find it!", oid_to_hex(new_oid));
ret = "bad pack";
@@ -1547,7 +1561,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
- if (!in_merge_bases(old_commit, new_commit)) {
+ if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
ret = "non-fast-forward";
@@ -1680,11 +1694,11 @@ static void check_aliased_update_internal(struct command *cmd,
rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
" its target '%s' (%s..%s)",
cmd->ref_name,
- find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV),
- find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &cmd->old_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &cmd->new_oid, DEFAULT_ABBREV),
dst_cmd->ref_name,
- find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
- find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &dst_cmd->old_oid, DEFAULT_ABBREV),
+ repo_find_unique_abbrev(the_repository, &dst_cmd->new_oid, DEFAULT_ABBREV));
cmd->error_string = dst_cmd->error_string =
"inconsistent aliased update";
@@ -1794,7 +1808,7 @@ static void reject_updates_to_hidden(struct command *commands)
strbuf_setlen(&refname_full, prefix_len);
strbuf_addstr(&refname_full, cmd->ref_name);
- if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
+ if (!ref_is_hidden(cmd->ref_name, refname_full.buf, &hidden_refs))
continue;
if (is_null_oid(&cmd->new_oid))
cmd->error_string = "deny deleting a hidden ref";
@@ -1928,6 +1942,8 @@ static void execute_commands(struct command *commands,
opt.err_fd = err_fd;
opt.progress = err_fd && !quiet;
opt.env = tmp_objdir_env(tmp_objdir);
+ opt.exclude_hidden_refs_section = "receive";
+
if (check_connected(iterate_receive_command_list, &data, &opt))
set_connectivity_errors(commands, si);
@@ -2029,6 +2045,16 @@ static struct command **queue_command(struct command **tail,
return &cmd->next;
}
+static void free_commands(struct command *commands)
+{
+ while (commands) {
+ struct command *next = commands->next;
+
+ free(commands);
+ commands = next;
+ }
+}
+
static void queue_commands_from_cert(struct command **tail,
struct strbuf *push_cert)
{
@@ -2076,7 +2102,7 @@ static struct command *read_head_info(struct packet_reader *reader,
const char *feature_list = reader->line + linelen + 1;
const char *hash = NULL;
const char *client_sid;
- int len = 0;
+ size_t len = 0;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
if (parse_feature_request(feature_list, "report-status-v2"))
@@ -2171,7 +2197,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
}
}
-static const char *pack_lockfile;
+static struct tempfile *pack_lockfile;
static void push_header_arg(struct strvec *args, struct pack_header *hdr)
{
@@ -2238,6 +2264,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
return "unpack-objects abnormal exit";
} else {
char hostname[HOST_NAME_MAX + 1];
+ char *lockfile;
strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
push_header_arg(&child.args, &hdr);
@@ -2267,8 +2294,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
status = start_command(&child);
if (status)
return "index-pack fork failed";
- pack_lockfile = index_pack_lockfile(child.out, NULL);
+
+ lockfile = index_pack_lockfile(child.out, NULL);
+ if (lockfile) {
+ pack_lockfile = register_tempfile(lockfile);
+ free(lockfile);
+ }
close(child.out);
+
status = finish_command(&child);
if (status)
return "index-pack abnormal exit";
@@ -2496,10 +2529,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (cert_nonce_seed)
push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
- if (0 <= transfer_unpack_limit)
- unpack_limit = transfer_unpack_limit;
- else if (0 <= receive_unpack_limit)
+ if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
+ else if (0 <= transfer_unpack_limit)
+ unpack_limit = transfer_unpack_limit;
switch (determine_protocol_version_server()) {
case protocol_v2:
@@ -2555,8 +2588,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
use_keepalive = KEEPALIVE_ALWAYS;
execute_commands(commands, unpack_status, &si,
&push_options);
- if (pack_lockfile)
- unlink_or_warn(pack_lockfile);
+ delete_tempfile(&pack_lockfile);
sigchain_push(SIGPIPE, SIG_IGN);
if (report_status_v2)
report_v2(commands, unpack_status);
@@ -2566,6 +2598,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
run_receive_hook(commands, "post-receive", 1,
&push_options);
run_update_post_hook(commands);
+ free_commands(commands);
string_list_clear(&push_options, 0);
if (auto_gc) {
struct child_process proc = CHILD_PROCESS_INIT;
@@ -2591,6 +2624,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
packet_flush(1);
oid_array_clear(&shallow);
oid_array_clear(&ref);
+ strvec_clear(&hidden_refs);
free((void *)push_cert_nonce);
return 0;
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 57c5c0d061..a5a4099f61 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,9 +1,13 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "repository.h"
#include "revision.h"
#include "reachable.h"
+#include "wildmatch.h"
#include "worktree.h"
#include "reflog.h"
+#include "parse-options.h"
#define BUILTIN_REFLOG_SHOW_USAGE \
N_("git reflog [show] [<log-options>] [<ref>]")
@@ -67,7 +71,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
* Avoid collecting the same shared ref multiple times because
* they are available via all worktrees.
*/
- if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL)
+ if (!worktree->is_current &&
+ parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
return 0;
strbuf_worktree_ref(worktree, &newref, ref);
@@ -105,7 +110,8 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
#define EXPIRE_TOTAL 01
#define EXPIRE_UNREACH 02
-static int reflog_expire_config(const char *var, const char *value, void *cb)
+static int reflog_expire_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
const char *pattern, *key;
size_t pattern_len;
@@ -114,7 +120,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
struct reflog_expire_cfg *ent;
if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
if (!strcmp(key, "reflogexpire")) {
slot = EXPIRE_TOTAL;
@@ -125,7 +131,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
if (git_config_expiry_date(&expire, var, value))
return -1;
} else
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
if (!pattern) {
switch (slot) {
@@ -237,12 +243,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
struct cmd_reflog_expire_cb cmd = { 0 };
timestamp_t now = time(NULL);
- int i, status, do_all, all_worktrees = 1;
+ int i, status, do_all, single_worktree = 0;
unsigned int flags = 0;
int verbose = 0;
reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
@@ -262,7 +268,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stale-fix", &cmd.stalefix,
N_("prune any reflog entries that point to broken commits")),
OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
- OPT_BOOL(1, "single-worktree", &all_worktrees,
+ OPT_BOOL(0, "single-worktree", &single_worktree,
N_("limits processing to reflogs from the current worktree only")),
OPT_END()
};
@@ -292,7 +298,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
struct rev_info revs;
repo_init_revisions(the_repository, &revs, prefix);
- revs.do_not_die_on_missing_tree = 1;
+ revs.do_not_die_on_missing_objects = 1;
revs.ignore_missing = 1;
revs.ignore_missing_links = 1;
if (verbose)
@@ -312,7 +318,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
- if (!all_worktrees && !(*p)->is_current)
+ if (single_worktree && !(*p)->is_current)
continue;
collected.worktree = *p;
refs_for_each_reflog(get_worktree_ref_store(*p),
@@ -362,7 +368,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
int verbose = 0;
const struct option options[] = {
- OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
OPT_BIT(0, "rewrite", &flags,
N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index fd3538d4f0..282782eccd 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -169,6 +169,8 @@ static int command_loop(const char *child)
while (1) {
size_t i;
+ const char *arg;
+
if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
if (ferror(stdin))
die("Command input error");
@@ -182,10 +184,10 @@ static int command_loop(const char *child)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (skip_prefix(buffer, "connect ", &arg)) {
printf("\n");
fflush(stdout);
- return run_child(child, buffer + 8);
+ return run_child(child, arg);
} else {
fprintf(stderr, "Bad command");
return 1;
@@ -195,6 +197,8 @@ static int command_loop(const char *child)
int cmd_remote_ext(int argc, const char **argv, const char *prefix)
{
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 3)
usage(usage_msg);
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 91dfe07e06..9020fab9c5 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -40,7 +40,7 @@ static void command_loop(int input_fd, int output_fd)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (starts_with(buffer, "connect ")) {
printf("\n");
fflush(stdout);
if (bidirectional_transfer_loop(input_fd,
@@ -59,6 +59,8 @@ int cmd_remote_fd(int argc, const char **argv, const char *prefix)
int output_fd = -1;
char *end;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc != 3)
usage(usage_msg);
diff --git a/builtin/remote.c b/builtin/remote.c
index 910f7b9316..d91bbe728d 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
#include "transport.h"
#include "remote.h"
#include "string-list.h"
@@ -9,7 +11,7 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "strvec.h"
#include "commit-reach.h"
#include "progress.h"
@@ -92,13 +94,15 @@ static int verbose;
static int fetch_remote(const char *name)
{
- const char *argv[] = { "fetch", name, NULL, NULL };
- if (verbose) {
- argv[1] = "-v";
- argv[2] = name;
- }
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_push(&cmd.args, "fetch");
+ if (verbose)
+ strvec_push(&cmd.args, "-v");
+ strvec_push(&cmd.args, name);
+ cmd.git_cmd = 1;
printf_ln(_("Updating %s"), name);
- if (run_command_v_opt(argv, RUN_GIT_CMD))
+ if (run_command(&cmd))
return error(_("Could not fetch %s"), name);
return 0;
}
@@ -164,10 +168,9 @@ static int add(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
OPT_SET_INT(0, "tags", &fetch_tags,
- N_("import all tags and associated objects when fetching"),
+ N_("import all tags and associated objects when fetching\n"
+ "or do not fetch any tag at all (--no-tags)"),
TAGS_SET),
- OPT_SET_INT(0, NULL, &fetch_tags,
- N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET),
OPT_STRING_LIST('t', "track", &track, N_("branch"),
N_("branch(es) to track")),
OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
@@ -265,6 +268,7 @@ static const char *abbrev_ref(const char *name, const char *prefix)
#define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
static int config_read_branches(const char *key, const char *value,
+ const struct config_context *ctx UNUSED,
void *data UNUSED)
{
const char *orig_key = key;
@@ -441,7 +445,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
info->status = PUSH_STATUS_UPTODATE;
else if (is_null_oid(&ref->old_oid))
info->status = PUSH_STATUS_CREATE;
- else if (has_object_file(&ref->old_oid) &&
+ else if (repo_has_object_file(the_repository, &ref->old_oid) &&
ref_newer(&ref->new_oid, &ref->old_oid))
info->status = PUSH_STATUS_FASTFORWARD;
else
@@ -642,17 +646,19 @@ struct push_default_info
};
static int config_read_push_default(const char *key, const char *value,
- void *cb)
+ const struct config_context *ctx, void *cb)
{
+ const struct key_value_info *kvi = ctx->kvi;
+
struct push_default_info* info = cb;
if (strcmp(key, "remote.pushdefault") ||
!value || strcmp(value, info->old_name))
return 0;
- info->scope = current_config_scope();
+ info->scope = kvi->scope;
strbuf_reset(&info->origin);
- strbuf_addstr(&info->origin, current_config_name());
- info->linenr = current_config_line();
+ strbuf_addstr(&info->origin, config_origin_type_name(kvi->origin_type));
+ info->linenr = kvi->linenr;
return 0;
}
@@ -942,7 +948,7 @@ static int rm(int argc, const char **argv, const char *prefix)
return result;
}
-static void clear_push_info(void *util, const char *string)
+static void clear_push_info(void *util, const char *string UNUSED)
{
struct push_info *info = util;
free(info->dest);
@@ -1491,7 +1497,9 @@ static int prune(int argc, const char **argv, const char *prefix)
return result;
}
-static int get_remote_default(const char *key, const char *value UNUSED, void *priv)
+static int get_remote_default(const char *key, const char *value UNUSED,
+ const struct config_context *ctx UNUSED,
+ void *priv)
{
if (strcmp(key, "remotes.default") == 0) {
int *found = priv;
@@ -1508,37 +1516,35 @@ static int update(int argc, const char **argv, const char *prefix)
N_("prune remotes after fetching")),
OPT_END()
};
- struct strvec fetch_argv = STRVEC_INIT;
+ struct child_process cmd = CHILD_PROCESS_INIT;
int default_defined = 0;
- int retval;
argc = parse_options(argc, argv, prefix, options,
builtin_remote_update_usage,
PARSE_OPT_KEEP_ARGV0);
- strvec_push(&fetch_argv, "fetch");
+ strvec_push(&cmd.args, "fetch");
if (prune != -1)
- strvec_push(&fetch_argv, prune ? "--prune" : "--no-prune");
+ strvec_push(&cmd.args, prune ? "--prune" : "--no-prune");
if (verbose)
- strvec_push(&fetch_argv, "-v");
- strvec_push(&fetch_argv, "--multiple");
+ strvec_push(&cmd.args, "-v");
+ strvec_push(&cmd.args, "--multiple");
if (argc < 2)
- strvec_push(&fetch_argv, "default");
+ strvec_push(&cmd.args, "default");
for (i = 1; i < argc; i++)
- strvec_push(&fetch_argv, argv[i]);
+ strvec_push(&cmd.args, argv[i]);
- if (strcmp(fetch_argv.v[fetch_argv.nr-1], "default") == 0) {
+ if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) {
git_config(get_remote_default, &default_defined);
if (!default_defined) {
- strvec_pop(&fetch_argv);
- strvec_push(&fetch_argv, "--all");
+ strvec_pop(&cmd.args);
+ strvec_push(&cmd.args, "--all");
}
}
- retval = run_command_v_opt(fetch_argv.v, RUN_GIT_CMD);
- strvec_clear(&fetch_argv);
- return retval;
+ cmd.git_cmd = 1;
+ return run_command(&cmd);
}
static int remove_all_fetch_refspecs(const char *key)
diff --git a/builtin/repack.c b/builtin/repack.c
index a5bacc7797..ede36328a3 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,29 +1,33 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
-#include "sigchain.h"
+#include "server-info.h"
#include "strbuf.h"
#include "string-list.h"
#include "strvec.h"
#include "midx.h"
#include "packfile.h"
#include "prune-packed.h"
-#include "object-store.h"
+#include "object-store-ll.h"
#include "promisor-remote.h"
#include "shallow.h"
#include "pack.h"
#include "pack-bitmap.h"
#include "refs.h"
+#include "list-objects-filter-options.h"
#define ALL_INTO_ONE 1
#define LOOSEN_UNREACHABLE 2
#define PACK_CRUFT 4
#define DELETE_PACK 1
-#define CRUFT_PACK 2
+#define RETAIN_PACK 2
static int pack_everything;
static int delta_base_offset = 1;
@@ -32,7 +36,6 @@ static int write_bitmaps = -1;
static int use_delta_islands;
static int run_update_server_info = 1;
static char *packdir, *packtmp_name, *packtmp;
-static char *cruft_expiration;
static const char *const git_repack_usage[] = {
N_("git repack [<options>]"),
@@ -49,14 +52,16 @@ struct pack_objects_args {
const char *window_memory;
const char *depth;
const char *threads;
- const char *max_pack_size;
+ unsigned long max_pack_size;
int no_reuse_delta;
int no_reuse_object;
int quiet;
int local;
+ struct list_objects_filter_options filter_options;
};
-static int repack_config(const char *var, const char *value, void *cb)
+static int repack_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
struct pack_objects_args *cruft_po_args = cb;
if (!strcmp(var, "repack.usedeltabaseoffset")) {
@@ -88,107 +93,185 @@ static int repack_config(const char *var, const char *value, void *cb)
return git_config_string(&cruft_po_args->depth, var, value);
if (!strcmp(var, "repack.cruftthreads"))
return git_config_string(&cruft_po_args->threads, var, value);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
-/*
- * Remove temporary $GIT_OBJECT_DIRECTORY/pack/.tmp-$$-pack-* files.
- */
-static void remove_temporary_files(void)
+struct existing_packs {
+ struct string_list kept_packs;
+ struct string_list non_kept_packs;
+ struct string_list cruft_packs;
+};
+
+#define EXISTING_PACKS_INIT { \
+ .kept_packs = STRING_LIST_INIT_DUP, \
+ .non_kept_packs = STRING_LIST_INIT_DUP, \
+ .cruft_packs = STRING_LIST_INIT_DUP, \
+}
+
+static int has_existing_non_kept_packs(const struct existing_packs *existing)
{
- struct strbuf buf = STRBUF_INIT;
- size_t dirlen, prefixlen;
- DIR *dir;
- struct dirent *e;
+ return existing->non_kept_packs.nr || existing->cruft_packs.nr;
+}
- dir = opendir(packdir);
- if (!dir)
- return;
+static void pack_mark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
+}
+
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
+
+static int pack_is_marked_for_deletion(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & DELETE_PACK;
+}
- /* Point at the slash at the end of ".../objects/pack/" */
- dirlen = strlen(packdir) + 1;
- strbuf_addstr(&buf, packtmp);
- /* Hold the length of ".tmp-%d-pack-" */
- prefixlen = buf.len - dirlen;
+static void pack_mark_retained(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
- while ((e = readdir(dir))) {
- if (strncmp(e->d_name, buf.buf + dirlen, prefixlen))
+static int pack_is_retained(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & RETAIN_PACK;
+}
+
+static void mark_packs_for_deletion_1(struct string_list *names,
+ struct string_list *list)
+{
+ struct string_list_item *item;
+ const int hexsz = the_hash_algo->hexsz;
+
+ for_each_string_list_item(item, list) {
+ char *sha1;
+ size_t len = strlen(item->string);
+ if (len < hexsz)
continue;
- strbuf_setlen(&buf, dirlen);
- strbuf_addstr(&buf, e->d_name);
- unlink(buf.buf);
+ sha1 = item->string + len - hexsz;
+
+ if (pack_is_retained(item)) {
+ pack_unmark_for_deletion(item);
+ } else if (!string_list_has_string(names, sha1)) {
+ /*
+ * Mark this pack for deletion, which ensures
+ * that this pack won't be included in a MIDX
+ * (if `--write-midx` was given) and that we
+ * will actually delete this pack (if `-d` was
+ * given).
+ */
+ pack_mark_for_deletion(item);
+ }
}
- closedir(dir);
+}
+
+static void retain_cruft_pack(struct existing_packs *existing,
+ struct packed_git *cruft)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ strbuf_addstr(&buf, pack_basename(cruft));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ item = string_list_lookup(&existing->cruft_packs, buf.buf);
+ if (!item)
+ BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+ pack_mark_retained(item);
strbuf_release(&buf);
}
-static void remove_pack_on_signal(int signo)
+static void mark_packs_for_deletion(struct existing_packs *existing,
+ struct string_list *names)
+
{
- remove_temporary_files();
- sigchain_pop(signo);
- raise(signo);
+ mark_packs_for_deletion_1(names, &existing->non_kept_packs);
+ mark_packs_for_deletion_1(names, &existing->cruft_packs);
+}
+
+static void remove_redundant_pack(const char *dir_name, const char *base_name)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ strbuf_addf(&buf, "%s.pack", base_name);
+ if (m && midx_contains_pack(m, buf.buf))
+ clear_midx_file(the_repository);
+ strbuf_insertf(&buf, 0, "%s/", dir_name);
+ unlink_pack_path(buf.buf, 1);
+ strbuf_release(&buf);
+}
+
+static void remove_redundant_packs_1(struct string_list *packs)
+{
+ struct string_list_item *item;
+ for_each_string_list_item(item, packs) {
+ if (!pack_is_marked_for_deletion(item))
+ continue;
+ remove_redundant_pack(packdir, item->string);
+ }
+}
+
+static void remove_redundant_existing_packs(struct existing_packs *existing)
+{
+ remove_redundant_packs_1(&existing->non_kept_packs);
+ remove_redundant_packs_1(&existing->cruft_packs);
+}
+
+static void existing_packs_release(struct existing_packs *existing)
+{
+ string_list_clear(&existing->kept_packs, 0);
+ string_list_clear(&existing->non_kept_packs, 0);
+ string_list_clear(&existing->cruft_packs, 0);
}
/*
- * Adds all packs hex strings to either fname_nonkept_list or
- * fname_kept_list based on whether each pack has a corresponding
+ * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
+ * or packs->kept based on whether each pack has a corresponding
* .keep file or not. Packs without a .keep file are not to be kept
* if we are going to pack everything into one file.
*/
-static void collect_pack_filenames(struct string_list *fname_nonkept_list,
- struct string_list *fname_kept_list,
+static void collect_pack_filenames(struct existing_packs *existing,
const struct string_list *extra_keep)
{
- DIR *dir;
- struct dirent *e;
- char *fname;
-
- if (!(dir = opendir(packdir)))
- return;
+ struct packed_git *p;
+ struct strbuf buf = STRBUF_INIT;
- while ((e = readdir(dir)) != NULL) {
- size_t len;
+ for (p = get_all_packs(the_repository); p; p = p->next) {
int i;
+ const char *base;
- if (!strip_suffix(e->d_name, ".pack", &len))
+ if (!p->pack_local)
continue;
+ base = pack_basename(p);
+
for (i = 0; i < extra_keep->nr; i++)
- if (!fspathcmp(e->d_name, extra_keep->items[i].string))
+ if (!fspathcmp(base, extra_keep->items[i].string))
break;
- fname = xmemdupz(e->d_name, len);
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, base);
+ strbuf_strip_suffix(&buf, ".pack");
- if ((extra_keep->nr > 0 && i < extra_keep->nr) ||
- (file_exists(mkpath("%s/%s.keep", packdir, fname)))) {
- string_list_append_nodup(fname_kept_list, fname);
- } else {
- struct string_list_item *item;
- item = string_list_append_nodup(fname_nonkept_list,
- fname);
- if (file_exists(mkpath("%s/%s.mtimes", packdir, fname)))
- item->util = (void*)(uintptr_t)CRUFT_PACK;
- }
+ if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
+ string_list_append(&existing->kept_packs, buf.buf);
+ else if (p->is_cruft)
+ string_list_append(&existing->cruft_packs, buf.buf);
+ else
+ string_list_append(&existing->non_kept_packs, buf.buf);
}
- closedir(dir);
-
- string_list_sort(fname_kept_list);
-}
-static void remove_redundant_pack(const char *dir_name, const char *base_name)
-{
- struct strbuf buf = STRBUF_INIT;
- struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
- strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
- clear_midx_file(the_repository);
- strbuf_insertf(&buf, 0, "%s/", dir_name);
- unlink_pack_path(buf.buf, 1);
+ string_list_sort(&existing->kept_packs);
+ string_list_sort(&existing->non_kept_packs);
+ string_list_sort(&existing->cruft_packs);
strbuf_release(&buf);
}
static void prepare_pack_objects(struct child_process *cmd,
- const struct pack_objects_args *args)
+ const struct pack_objects_args *args,
+ const char *out)
{
strvec_push(&cmd->args, "pack-objects");
if (args->window)
@@ -200,7 +283,7 @@ static void prepare_pack_objects(struct child_process *cmd,
if (args->threads)
strvec_pushf(&cmd->args, "--threads=%s", args->threads);
if (args->max_pack_size)
- strvec_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+ strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
if (args->no_reuse_delta)
strvec_pushf(&cmd->args, "--no-reuse-delta");
if (args->no_reuse_object)
@@ -211,7 +294,7 @@ static void prepare_pack_objects(struct child_process *cmd,
strvec_push(&cmd->args, "--quiet");
if (delta_base_offset)
strvec_push(&cmd->args, "--delta-base-offset");
- strvec_push(&cmd->args, packtmp);
+ strvec_push(&cmd->args, out);
cmd->git_cmd = 1;
cmd->out = -1;
}
@@ -220,8 +303,9 @@ static void prepare_pack_objects(struct child_process *cmd,
* Write oid to the given struct child_process's stdin, starting it first if
* necessary.
*/
-static int write_oid(const struct object_id *oid, struct packed_git *pack,
- uint32_t pos, void *data)
+static int write_oid(const struct object_id *oid,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED, void *data)
{
struct child_process *cmd = data;
@@ -247,11 +331,15 @@ static struct {
{".idx"},
};
-static unsigned populate_pack_exts(char *name)
+struct generated_pack_data {
+ struct tempfile *tempfiles[ARRAY_SIZE(exts)];
+};
+
+static struct generated_pack_data *populate_pack_exts(const char *name)
{
struct stat statbuf;
struct strbuf path = STRBUF_INIT;
- unsigned ret = 0;
+ struct generated_pack_data *data = xcalloc(1, sizeof(*data));
int i;
for (i = 0; i < ARRAY_SIZE(exts); i++) {
@@ -261,11 +349,23 @@ static unsigned populate_pack_exts(char *name)
if (stat(path.buf, &statbuf))
continue;
- ret |= (1 << i);
+ data->tempfiles[i] = register_tempfile(path.buf);
}
strbuf_release(&path);
- return ret;
+ return data;
+}
+
+static int has_pack_ext(const struct generated_pack_data *data,
+ const char *ext)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ if (strcmp(exts[i].name, ext))
+ continue;
+ return !!data->tempfiles[i];
+ }
+ BUG("unknown pack extension: '%s'", ext);
}
static void repack_promisor_objects(const struct pack_objects_args *args,
@@ -275,7 +375,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
FILE *out;
struct strbuf line = STRBUF_INIT;
- prepare_pack_objects(&cmd, args);
+ prepare_pack_objects(&cmd, args, packtmp);
cmd.in = -1;
/*
@@ -320,7 +420,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
line.buf);
write_promisor_file(promisor_name, NULL, 0);
- item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
+ item->util = populate_pack_exts(item->string);
free(promisor_name);
}
@@ -333,6 +433,8 @@ struct pack_geometry {
struct packed_git **pack;
uint32_t pack_nr, pack_alloc;
uint32_t split;
+
+ int split_factor;
};
static uint32_t geometry_pack_weight(struct packed_git *p)
@@ -354,36 +456,42 @@ static int geometry_cmp(const void *va, const void *vb)
return 0;
}
-static void init_pack_geometry(struct pack_geometry **geometry_p,
- struct string_list *existing_kept_packs)
+static void init_pack_geometry(struct pack_geometry *geometry,
+ struct existing_packs *existing,
+ const struct pack_objects_args *args)
{
struct packed_git *p;
- struct pack_geometry *geometry;
struct strbuf buf = STRBUF_INIT;
- *geometry_p = xcalloc(1, sizeof(struct pack_geometry));
- geometry = *geometry_p;
-
for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (args->local && !p->pack_local)
+ /*
+ * When asked to only repack local packfiles we skip
+ * over any packfiles that are borrowed from alternate
+ * object directories.
+ */
+ continue;
+
if (!pack_kept_objects) {
/*
- * Any pack that has its pack_keep bit set will appear
- * in existing_kept_packs below, but this saves us from
- * doing a more expensive check.
+ * Any pack that has its pack_keep bit set will
+ * appear in existing->kept_packs below, but
+ * this saves us from doing a more expensive
+ * check.
*/
if (p->pack_keep)
continue;
/*
- * The pack may be kept via the --keep-pack option;
- * check 'existing_kept_packs' to determine whether to
- * ignore it.
+ * The pack may be kept via the --keep-pack
+ * option; check 'existing->kept_packs' to
+ * determine whether to ignore it.
*/
strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
- if (string_list_has_string(existing_kept_packs, buf.buf))
+ if (string_list_has_string(&existing->kept_packs, buf.buf))
continue;
}
if (p->is_cruft)
@@ -401,7 +509,7 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
strbuf_release(&buf);
}
-static void split_pack_geometry(struct pack_geometry *geometry, int factor)
+static void split_pack_geometry(struct pack_geometry *geometry)
{
uint32_t i;
uint32_t split;
@@ -420,12 +528,14 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
struct packed_git *ours = geometry->pack[i];
struct packed_git *prev = geometry->pack[i - 1];
- if (unsigned_mult_overflows(factor, geometry_pack_weight(prev)))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ geometry_pack_weight(prev)))
die(_("pack %s too large to consider in geometric "
"progression"),
prev->pack_name);
- if (geometry_pack_weight(ours) < factor * geometry_pack_weight(prev))
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * geometry_pack_weight(prev))
break;
}
@@ -460,10 +570,12 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
for (i = split; i < geometry->pack_nr; i++) {
struct packed_git *ours = geometry->pack[i];
- if (unsigned_mult_overflows(factor, total_size))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ total_size))
die(_("pack %s too large to roll up"), ours->pack_name);
- if (geometry_pack_weight(ours) < factor * total_size) {
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * total_size) {
if (unsigned_add_overflows(total_size,
geometry_pack_weight(ours)))
die(_("pack %s too large to roll up"),
@@ -478,8 +590,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
geometry->split = split;
}
-static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry)
+static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
{
+ uint32_t i;
+
if (!geometry) {
/*
* No geometry means either an all-into-one repack (in which
@@ -494,18 +608,55 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry
}
if (geometry->split == geometry->pack_nr)
return NULL;
- return geometry->pack[geometry->pack_nr - 1];
+
+ /*
+ * The preferred pack is the largest pack above the split line. In
+ * other words, it is the largest pack that does not get rolled up in
+ * the geometric repack.
+ */
+ for (i = geometry->pack_nr; i > geometry->split; i--)
+ /*
+ * A pack that is not local would never be included in a
+ * multi-pack index. We thus skip over any non-local packs.
+ */
+ if (geometry->pack[i - 1]->pack_local)
+ return geometry->pack[i - 1];
+
+ return NULL;
+}
+
+static void geometry_remove_redundant_packs(struct pack_geometry *geometry,
+ struct string_list *names,
+ struct existing_packs *existing)
+{
+ struct strbuf buf = STRBUF_INIT;
+ uint32_t i;
+
+ for (i = 0; i < geometry->split; i++) {
+ struct packed_git *p = geometry->pack[i];
+ if (string_list_has_string(names, hash_to_hex(p->hash)))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if ((p->pack_keep) ||
+ (string_list_has_string(&existing->kept_packs, buf.buf)))
+ continue;
+
+ remove_redundant_pack(packdir, buf.buf);
+ }
+
+ strbuf_release(&buf);
}
-static void clear_pack_geometry(struct pack_geometry *geometry)
+static void free_pack_geometry(struct pack_geometry *geometry)
{
if (!geometry)
return;
free(geometry->pack);
- geometry->pack_nr = 0;
- geometry->pack_alloc = 0;
- geometry->split = 0;
}
struct midx_snapshot_ref_data {
@@ -571,57 +722,76 @@ static void midx_snapshot_refs(struct tempfile *f)
}
static void midx_included_packs(struct string_list *include,
- struct string_list *existing_nonkept_packs,
- struct string_list *existing_kept_packs,
+ struct existing_packs *existing,
struct string_list *names,
struct pack_geometry *geometry)
{
struct string_list_item *item;
- for_each_string_list_item(item, existing_kept_packs)
+ for_each_string_list_item(item, &existing->kept_packs)
string_list_insert(include, xstrfmt("%s.idx", item->string));
for_each_string_list_item(item, names)
string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
- if (geometry) {
+ if (geometry->split_factor) {
struct strbuf buf = STRBUF_INIT;
uint32_t i;
for (i = geometry->split; i < geometry->pack_nr; i++) {
struct packed_git *p = geometry->pack[i];
+ /*
+ * The multi-pack index never refers to packfiles part
+ * of an alternate object database, so we skip these.
+ * While git-multi-pack-index(1) would silently ignore
+ * them anyway, this allows us to skip executing the
+ * command completely when we have only non-local
+ * packfiles.
+ */
+ if (!p->pack_local)
+ continue;
+
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
strbuf_addstr(&buf, ".idx");
string_list_insert(include, strbuf_detach(&buf, NULL));
}
-
- for_each_string_list_item(item, existing_nonkept_packs) {
- if (!((uintptr_t)item->util & CRUFT_PACK)) {
- /*
- * no need to check DELETE_PACK, since we're not
- * doing an ALL_INTO_ONE repack
- */
- continue;
- }
- string_list_insert(include, xstrfmt("%s.idx", item->string));
- }
} else {
- for_each_string_list_item(item, existing_nonkept_packs) {
- if ((uintptr_t)item->util & DELETE_PACK)
+ for_each_string_list_item(item, &existing->non_kept_packs) {
+ if (pack_is_marked_for_deletion(item))
continue;
string_list_insert(include, xstrfmt("%s.idx", item->string));
}
}
+
+ for_each_string_list_item(item, &existing->cruft_packs) {
+ /*
+ * When doing a --geometric repack, there is no need to check
+ * for deleted packs, since we're by definition not doing an
+ * ALL_INTO_ONE repack (hence no packs will be deleted).
+ * Otherwise we must check for and exclude any packs which are
+ * enqueued for deletion.
+ *
+ * So we could omit the conditional below in the --geometric
+ * case, but doing so is unnecessary since no packs are marked
+ * as pending deletion (since we only call
+ * `mark_packs_for_deletion()` when doing an all-into-one
+ * repack).
+ */
+ if (pack_is_marked_for_deletion(item))
+ continue;
+ string_list_insert(include, xstrfmt("%s.idx", item->string));
+ }
}
static int write_midx_included_packs(struct string_list *include,
struct pack_geometry *geometry,
+ struct string_list *names,
const char *refs_snapshot,
int show_progress, int write_bitmaps)
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
- struct packed_git *largest = get_largest_active_pack(geometry);
+ struct packed_git *preferred = get_preferred_pack(geometry);
FILE *in;
int ret;
@@ -642,9 +812,41 @@ static int write_midx_included_packs(struct string_list *include,
if (write_bitmaps)
strvec_push(&cmd.args, "--bitmap");
- if (largest)
+ if (preferred)
strvec_pushf(&cmd.args, "--preferred-pack=%s",
- pack_basename(largest));
+ pack_basename(preferred));
+ else if (names->nr) {
+ /* The largest pack was repacked, meaning that either
+ * one or two packs exist depending on whether the
+ * repository has a cruft pack or not.
+ *
+ * Select the non-cruft one as preferred to encourage
+ * pack-reuse among packs containing reachable objects
+ * over unreachable ones.
+ *
+ * (Note we could write multiple packs here if
+ * `--max-pack-size` was given, but any one of them
+ * will suffice, so pick the first one.)
+ */
+ for_each_string_list_item(item, names) {
+ struct generated_pack_data *data = item->util;
+ if (has_pack_ext(data, ".mtimes"))
+ continue;
+
+ strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
+ item->string);
+ break;
+ }
+ } else {
+ /*
+ * No packs were kept, and no packs were written. The
+ * only thing remaining are .keep packs (unless
+ * --pack-kept-objects was given).
+ *
+ * Set the `--preferred-pack` arbitrarily here.
+ */
+ ;
+ }
if (refs_snapshot)
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -661,19 +863,197 @@ static int write_midx_included_packs(struct string_list *include,
return finish_command(&cmd);
}
+static void remove_redundant_bitmaps(struct string_list *include,
+ const char *packdir)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct string_list_item *item;
+ size_t packdir_len;
+
+ strbuf_addstr(&path, packdir);
+ strbuf_addch(&path, '/');
+ packdir_len = path.len;
+
+ /*
+ * Remove any pack bitmaps corresponding to packs which are now
+ * included in the MIDX.
+ */
+ for_each_string_list_item(item, include) {
+ strbuf_addstr(&path, item->string);
+ strbuf_strip_suffix(&path, ".idx");
+ strbuf_addstr(&path, ".bitmap");
+
+ if (unlink(path.buf) && errno != ENOENT)
+ warning_errno(_("could not remove stale bitmap: %s"),
+ path.buf);
+
+ strbuf_setlen(&path, packdir_len);
+ }
+ strbuf_release(&path);
+}
+
+static int finish_pack_objects_cmd(struct child_process *cmd,
+ struct string_list *names,
+ int local)
+{
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+
+ out = xfdopen(cmd->out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+
+ if (line.len != the_hash_algo->hexsz)
+ die(_("repack: Expecting full hex object ID lines only "
+ "from pack-objects."));
+ /*
+ * Avoid putting packs written outside of the repository in the
+ * list of names.
+ */
+ if (local) {
+ item = string_list_append(names, line.buf);
+ item->util = populate_pack_exts(line.buf);
+ }
+ }
+ fclose(out);
+
+ strbuf_release(&line);
+
+ return finish_command(cmd);
+}
+
+static int write_filtered_pack(const struct pack_objects_args *args,
+ const char *destination,
+ const char *pack_prefix,
+ struct existing_packs *existing,
+ struct string_list *names)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct string_list_item *item;
+ FILE *in;
+ int ret;
+ const char *caret;
+ const char *scratch;
+ int local = skip_prefix(destination, packdir, &scratch);
+
+ prepare_pack_objects(&cmd, args, destination);
+
+ strvec_push(&cmd.args, "--stdin-packs");
+
+ if (!pack_kept_objects)
+ strvec_push(&cmd.args, "--honor-pack-keep");
+ for_each_string_list_item(item, &existing->kept_packs)
+ strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
+
+ cmd.in = -1;
+
+ ret = start_command(&cmd);
+ if (ret)
+ return ret;
+
+ /*
+ * Here 'names' contains only the pack(s) that were just
+ * written, which is exactly the packs we want to keep. Also
+ * 'existing_kept_packs' already contains the packs in
+ * 'keep_pack_list'.
+ */
+ in = xfdopen(cmd.in, "w");
+ for_each_string_list_item(item, names)
+ fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ caret = pack_kept_objects ? "" : "^";
+ for_each_string_list_item(item, &existing->kept_packs)
+ fprintf(in, "%s%s.pack\n", caret, item->string);
+ fclose(in);
+
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+ struct packed_git *a = *(struct packed_git **)va;
+ struct packed_git *b = *(struct packed_git **)vb;
+
+ if (a->pack_size < b->pack_size)
+ return -1;
+ if (a->pack_size > b->pack_size)
+ return 1;
+ return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+ struct existing_packs *existing)
+{
+ struct packed_git **existing_cruft, *p;
+ struct strbuf buf = STRBUF_INIT;
+ size_t total_size = 0;
+ size_t existing_cruft_nr = 0;
+ size_t i;
+
+ ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (!(p->is_cruft && p->pack_local))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+ continue;
+
+ if (existing_cruft_nr >= existing->cruft_packs.nr)
+ BUG("too many cruft packs (found %"PRIuMAX", but knew "
+ "of %"PRIuMAX")",
+ (uintmax_t)existing_cruft_nr + 1,
+ (uintmax_t)existing->cruft_packs.nr);
+ existing_cruft[existing_cruft_nr++] = p;
+ }
+
+ QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+ for (i = 0; i < existing_cruft_nr; i++) {
+ size_t proposed;
+
+ p = existing_cruft[i];
+ proposed = st_add(total_size, p->pack_size);
+
+ if (proposed <= max_size) {
+ total_size = proposed;
+ fprintf(in, "-%s\n", pack_basename(p));
+ } else {
+ retain_cruft_pack(existing, p);
+ fprintf(in, "%s\n", pack_basename(p));
+ }
+ }
+
+ for (i = 0; i < existing->non_kept_packs.nr; i++)
+ fprintf(in, "-%s.pack\n",
+ existing->non_kept_packs.items[i].string);
+
+ strbuf_release(&buf);
+ free(existing_cruft);
+}
+
static int write_cruft_pack(const struct pack_objects_args *args,
+ const char *destination,
const char *pack_prefix,
+ const char *cruft_expiration,
struct string_list *names,
- struct string_list *existing_packs,
- struct string_list *existing_kept_packs)
+ struct existing_packs *existing)
{
struct child_process cmd = CHILD_PROCESS_INIT;
- struct strbuf line = STRBUF_INIT;
struct string_list_item *item;
- FILE *in, *out;
+ FILE *in;
int ret;
+ const char *scratch;
+ int local = skip_prefix(destination, packdir, &scratch);
- prepare_pack_objects(&cmd, args);
+ prepare_pack_objects(&cmd, args, destination);
strvec_push(&cmd.args, "--cruft");
if (cruft_expiration)
@@ -682,7 +1062,6 @@ static int write_cruft_pack(const struct pack_objects_args *args,
strvec_push(&cmd.args, "--honor-pack-keep");
strvec_push(&cmd.args, "--non-empty");
- strvec_push(&cmd.args, "--max-pack-size=0");
cmd.in = -1;
@@ -698,28 +1077,38 @@ static int write_cruft_pack(const struct pack_objects_args *args,
* By the time it is read here, it contains only the pack(s)
* that were just written, which is exactly the set of packs we
* want to consider kept.
+ *
+ * If `--expire-to` is given, the double-use served by `names`
+ * ensures that the pack written to `--expire-to` excludes any
+ * objects contained in the cruft pack.
*/
in = xfdopen(cmd.in, "w");
for_each_string_list_item(item, names)
fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
- for_each_string_list_item(item, existing_packs)
- fprintf(in, "-%s.pack\n", item->string);
- for_each_string_list_item(item, existing_kept_packs)
+ if (args->max_pack_size && !cruft_expiration) {
+ collapse_small_cruft_packs(in, args->max_pack_size, existing);
+ } else {
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ }
+ for_each_string_list_item(item, &existing->kept_packs)
fprintf(in, "%s.pack\n", item->string);
fclose(in);
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only "
- "from pack-objects."));
- string_list_append(names, line.buf);
- }
- fclose(out);
-
- strbuf_release(&line);
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
- return finish_command(&cmd);
+static const char *find_pack_prefix(const char *packdir, const char *packtmp)
+{
+ const char *pack_prefix;
+ if (!skip_prefix(packtmp, packdir, &pack_prefix))
+ die(_("pack prefix %s does not begin with objdir %s"),
+ packtmp, packdir);
+ if (*pack_prefix == '/')
+ pack_prefix++;
+ return pack_prefix;
}
int cmd_repack(int argc, const char **argv, const char *prefix)
@@ -727,13 +1116,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
struct string_list names = STRING_LIST_INIT_DUP;
- struct string_list existing_nonkept_packs = STRING_LIST_INIT_DUP;
- struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
- struct pack_geometry *geometry = NULL;
- struct strbuf line = STRBUF_INIT;
+ struct existing_packs existing = EXISTING_PACKS_INIT;
+ struct pack_geometry geometry = { 0 };
struct tempfile *refs_snapshot = NULL;
int i, ext, ret;
- FILE *out;
int show_progress;
/* variables to be filled by option parsing */
@@ -743,8 +1129,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
struct pack_objects_args po_args = {NULL};
struct pack_objects_args cruft_po_args = {NULL};
- int geometric_factor = 0;
int write_midx = 0;
+ const char *cruft_expiration = NULL;
+ const char *expire_to = NULL;
+ const char *filter_to = NULL;
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -756,7 +1144,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("same as -a, pack unreachable cruft objects separately"),
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
- N_("with -C, expire objects older than this")),
+ N_("with --cruft, expire objects older than this")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -784,19 +1174,26 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("limits the maximum delta depth")),
OPT_STRING(0, "threads", &po_args.threads, N_("n"),
N_("limits the maximum number of threads")),
- OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
+ OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
N_("maximum size of each packfile")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
N_("do not repack this pack")),
- OPT_INTEGER('g', "geometric", &geometric_factor,
+ OPT_INTEGER('g', "geometric", &geometry.split_factor,
N_("find a geometric progression with factor <N>")),
OPT_BOOL('m', "write-midx", &write_midx,
N_("write a multi-pack index of the resulting packs")),
+ OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
+ N_("pack prefix to store a pack containing pruned objects")),
+ OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
+ N_("pack prefix to store a pack containing filtered out objects")),
OPT_END()
};
+ list_objects_filter_init(&po_args.filter_options);
+
git_config(repack_config, &cruft_po_args);
argc = parse_options(argc, argv, prefix, builtin_repack_options,
@@ -805,19 +1202,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant && repository_format_precious_objects)
die(_("cannot delete packs in a precious-objects repo"));
- if (keep_unreachable &&
- (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
- die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "-A");
+ die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
+ keep_unreachable, "-k/--keep-unreachable",
+ pack_everything & PACK_CRUFT, "--cruft");
- if (pack_everything & PACK_CRUFT) {
+ if (pack_everything & PACK_CRUFT)
pack_everything |= ALL_INTO_ONE;
- if (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE))
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-A");
- if (keep_unreachable)
- die(_("options '%s' and '%s' cannot be used together"), "--cruft", "-k");
- }
-
if (write_bitmaps < 0) {
if (!write_midx &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
@@ -833,6 +1224,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
die(_(incremental_bitmap_conflict_error));
+ if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+ /*
+ * When asked to do a local repack, but we have
+ * packfiles that are inherited from an alternate, then
+ * we cannot guarantee that the multi-pack-index would
+ * have full coverage of all objects. We thus disable
+ * writing bitmaps in that case.
+ */
+ warning(_("disabling bitmap writing, as some objects are not being packed"));
+ write_bitmaps = 0;
+ }
+
if (write_midx && write_bitmaps) {
struct strbuf path = STRBUF_INIT;
@@ -849,19 +1252,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
- collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
- &keep_pack_list);
+ collect_pack_filenames(&existing, &keep_pack_list);
- if (geometric_factor) {
+ if (geometry.split_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry, &existing_kept_packs);
- split_pack_geometry(geometry, geometric_factor);
+ init_pack_geometry(&geometry, &existing, &po_args);
+ split_pack_geometry(&geometry);
}
- sigchain_push_common(remove_pack_on_signal);
-
- prepare_pack_objects(&cmd, &po_args);
+ prepare_pack_objects(&cmd, &po_args, packtmp);
show_progress = !po_args.quiet && isatty(2);
@@ -872,7 +1272,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_pushf(&cmd.args, "--keep-pack=%s",
keep_pack_list.items[i].string);
strvec_push(&cmd.args, "--non-empty");
- if (!geometry) {
+ if (!geometry.split_factor) {
/*
* We need to grab all reachable objects, including those that
* are reachable from reflogs and the index.
@@ -887,7 +1287,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--reflog");
strvec_push(&cmd.args, "--indexed-objects");
}
- if (has_promisor_remote())
+ if (repo_has_promisor_remote(the_repository))
strvec_push(&cmd.args, "--exclude-promisor-objects");
if (!write_midx) {
if (write_bitmaps > 0)
@@ -901,7 +1301,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (pack_everything & ALL_INTO_ONE) {
repack_promisor_objects(&po_args, &names);
- if (existing_nonkept_packs.nr && delete_redundant &&
+ if (has_existing_non_kept_packs(&existing) &&
+ delete_redundant &&
!(pack_everything & PACK_CRUFT)) {
for_each_string_list_item(item, &names) {
strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
@@ -919,7 +1320,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--pack-loose-unreachable");
}
}
- } else if (geometry) {
+ } else if (geometry.split_factor) {
strvec_push(&cmd.args, "--stdin-packs");
strvec_push(&cmd.args, "--unpacked");
} else {
@@ -927,50 +1328,44 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--incremental");
}
- if (geometry)
+ if (po_args.filter_options.choice)
+ strvec_pushf(&cmd.args, "--filter=%s",
+ expand_list_objects_filter_spec(&po_args.filter_options));
+ else if (filter_to)
+ die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
+
+ if (geometry.split_factor)
cmd.in = -1;
else
cmd.no_stdin = 1;
ret = start_command(&cmd);
if (ret)
- return ret;
+ goto cleanup;
- if (geometry) {
+ if (geometry.split_factor) {
FILE *in = xfdopen(cmd.in, "w");
/*
* The resulting pack should contain all objects in packs that
* are going to be rolled up, but exclude objects in packs which
* are being left alone.
*/
- for (i = 0; i < geometry->split; i++)
- fprintf(in, "%s\n", pack_basename(geometry->pack[i]));
- for (i = geometry->split; i < geometry->pack_nr; i++)
- fprintf(in, "^%s\n", pack_basename(geometry->pack[i]));
+ for (i = 0; i < geometry.split; i++)
+ fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
+ for (i = geometry.split; i < geometry.pack_nr; i++)
+ fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
fclose(in);
}
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only from pack-objects."));
- string_list_append(&names, line.buf);
- }
- fclose(out);
- ret = finish_command(&cmd);
+ ret = finish_pack_objects_cmd(&cmd, &names, 1);
if (ret)
- return ret;
+ goto cleanup;
if (!names.nr && !po_args.quiet)
printf_ln(_("Nothing new to pack."));
if (pack_everything & PACK_CRUFT) {
- const char *pack_prefix;
- if (!skip_prefix(packtmp, packdir, &pack_prefix))
- die(_("pack prefix %s does not begin with objdir %s"),
- packtmp, packdir);
- if (*pack_prefix == '/')
- pack_prefix++;
+ const char *pack_prefix = find_pack_prefix(packdir, packtmp);
if (!cruft_po_args.window)
cruft_po_args.window = po_args.window;
@@ -980,119 +1375,131 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
cruft_po_args.depth = po_args.depth;
if (!cruft_po_args.threads)
cruft_po_args.threads = po_args.threads;
+ if (!cruft_po_args.max_pack_size)
+ cruft_po_args.max_pack_size = po_args.max_pack_size;
cruft_po_args.local = po_args.local;
cruft_po_args.quiet = po_args.quiet;
- ret = write_cruft_pack(&cruft_po_args, pack_prefix, &names,
- &existing_nonkept_packs,
- &existing_kept_packs);
+ ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
+ cruft_expiration, &names,
+ &existing);
if (ret)
- return ret;
+ goto cleanup;
+
+ if (delete_redundant && expire_to) {
+ /*
+ * If `--expire-to` is given with `-d`, it's possible
+ * that we're about to prune some objects. With cruft
+ * packs, pruning is implicit: any objects from existing
+ * packs that weren't picked up by new packs are removed
+ * when their packs are deleted.
+ *
+ * Generate an additional cruft pack, with one twist:
+ * `names` now includes the name of the cruft pack
+ * written in the previous step. So the contents of
+ * _this_ cruft pack exclude everything contained in the
+ * existing cruft pack (that is, all of the unreachable
+ * objects which are no older than
+ * `--cruft-expiration`).
+ *
+ * To make this work, cruft_expiration must become NULL
+ * so that this cruft pack doesn't actually prune any
+ * objects. If it were non-NULL, this call would always
+ * generate an empty pack (since every object not in the
+ * cruft pack generated above will have an mtime older
+ * than the expiration).
+ */
+ ret = write_cruft_pack(&cruft_po_args, expire_to,
+ pack_prefix,
+ NULL,
+ &names,
+ &existing);
+ if (ret)
+ goto cleanup;
+ }
}
- string_list_sort(&names);
+ if (po_args.filter_options.choice) {
+ if (!filter_to)
+ filter_to = packtmp;
- for_each_string_list_item(item, &names) {
- item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
+ ret = write_filtered_pack(&po_args,
+ filter_to,
+ find_pack_prefix(packdir, packtmp),
+ &existing,
+ &names);
+ if (ret)
+ goto cleanup;
}
+ string_list_sort(&names);
+
close_object_store(the_repository->objects);
/*
* Ok we have prepared all new packfiles.
*/
for_each_string_list_item(item, &names) {
+ struct generated_pack_data *data = item->util;
+
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
- char *fname, *fname_old;
+ char *fname;
fname = mkpathdup("%s/pack-%s%s",
packdir, item->string, exts[ext].name);
- fname_old = mkpathdup("%s-%s%s",
- packtmp, item->string, exts[ext].name);
- if (((uintptr_t)item->util) & ((uintptr_t)1 << ext)) {
+ if (data->tempfiles[ext]) {
+ const char *fname_old = get_tempfile_path(data->tempfiles[ext]);
struct stat statbuffer;
+
if (!stat(fname_old, &statbuffer)) {
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
chmod(fname_old, statbuffer.st_mode);
}
- if (rename(fname_old, fname))
- die_errno(_("renaming '%s' failed"), fname_old);
+ if (rename_tempfile(&data->tempfiles[ext], fname))
+ die_errno(_("renaming pack to '%s' failed"), fname);
} else if (!exts[ext].optional)
- die(_("missing required file: %s"), fname_old);
+ die(_("pack-objects did not write a '%s' file for pack %s-%s"),
+ exts[ext].name, packtmp, item->string);
else if (unlink(fname) < 0 && errno != ENOENT)
die_errno(_("could not unlink: %s"), fname);
free(fname);
- free(fname_old);
}
}
/* End of pack replacement. */
- if (delete_redundant && pack_everything & ALL_INTO_ONE) {
- const int hexsz = the_hash_algo->hexsz;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- char *sha1;
- size_t len = strlen(item->string);
- if (len < hexsz)
- continue;
- sha1 = item->string + len - hexsz;
- /*
- * Mark this pack for deletion, which ensures that this
- * pack won't be included in a MIDX (if `--write-midx`
- * was given) and that we will actually delete this pack
- * (if `-d` was given).
- */
- if (!string_list_has_string(&names, sha1))
- item->util = (void*)(uintptr_t)((size_t)item->util | DELETE_PACK);
- }
- }
+ if (delete_redundant && pack_everything & ALL_INTO_ONE)
+ mark_packs_for_deletion(&existing, &names);
if (write_midx) {
struct string_list include = STRING_LIST_INIT_NODUP;
- midx_included_packs(&include, &existing_nonkept_packs,
- &existing_kept_packs, &names, geometry);
+ midx_included_packs(&include, &existing, &names, &geometry);
- ret = write_midx_included_packs(&include, geometry,
+ ret = write_midx_included_packs(&include, &geometry, &names,
refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
show_progress, write_bitmaps > 0);
+ if (!ret && write_bitmaps)
+ remove_redundant_bitmaps(&include, packdir);
+
string_list_clear(&include, 0);
if (ret)
- return ret;
+ goto cleanup;
}
reprepare_packed_git(the_repository);
if (delete_redundant) {
int opts = 0;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- if (!((uintptr_t)item->util & DELETE_PACK))
- continue;
- remove_redundant_pack(packdir, item->string);
- }
-
- if (geometry) {
- struct strbuf buf = STRBUF_INIT;
-
- uint32_t i;
- for (i = 0; i < geometry->split; i++) {
- struct packed_git *p = geometry->pack[i];
- if (string_list_has_string(&names,
- hash_to_hex(p->hash)))
- continue;
+ remove_redundant_existing_packs(&existing);
- strbuf_reset(&buf);
- strbuf_addstr(&buf, pack_basename(p));
- strbuf_strip_suffix(&buf, ".pack");
-
- remove_redundant_pack(packdir, buf.buf);
- }
- strbuf_release(&buf);
- }
+ if (geometry.split_factor)
+ geometry_remove_redundant_packs(&geometry, &names,
+ &existing);
if (show_progress)
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
@@ -1106,7 +1513,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (run_update_server_info)
update_server_info(0);
- remove_temporary_files();
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
unsigned flags = 0;
@@ -1115,11 +1521,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
write_midx_file(get_object_directory(), NULL, NULL, flags);
}
- string_list_clear(&names, 0);
- string_list_clear(&existing_nonkept_packs, 0);
- string_list_clear(&existing_kept_packs, 0);
- clear_pack_geometry(geometry);
- strbuf_release(&line);
+cleanup:
+ string_list_clear(&names, 1);
+ existing_packs_release(&existing);
+ free_pack_geometry(&geometry);
+ list_objects_filter_release(&po_args.filter_options);
- return 0;
+ return ret;
}
diff --git a/builtin/replace.c b/builtin/replace.c
index a29e911d30..da59600ad2 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -8,15 +8,23 @@
* git-tag.sh and mktag.c by Linus Torvalds.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
#include "repository.h"
#include "tag.h"
+#include "wildmatch.h"
static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
@@ -41,7 +49,7 @@ struct show_data {
static int show_reference(struct repository *r, const char *refname,
const struct object_id *oid,
- int flag, void *cb_data)
+ int flag UNUSED, void *cb_data)
{
struct show_data *data = cb_data;
@@ -54,7 +62,7 @@ static int show_reference(struct repository *r, const char *refname,
struct object_id object;
enum object_type obj_type, repl_type;
- if (get_oid(refname, &object))
+ if (repo_get_oid(r, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
obj_type = oid_object_info(r, &object, NULL);
@@ -112,7 +120,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
base_len = ref.len;
for (p = argv; *p; p++) {
- if (get_oid(*p, &oid)) {
+ if (repo_get_oid(the_repository, *p, &oid)) {
error("failed to resolve '%s' as a valid ref", *p);
had_error = 1;
continue;
@@ -206,10 +214,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
{
struct object_id object, repl;
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
return error(_("failed to resolve '%s' as a valid ref"),
object_ref);
- if (get_oid(replace_ref, &repl))
+ if (repo_get_oid(the_repository, replace_ref, &repl))
return error(_("failed to resolve '%s' as a valid ref"),
replace_ref);
@@ -320,7 +328,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
struct object_id old_oid, new_oid, prev;
struct strbuf ref = STRBUF_INIT;
- if (get_oid(object_ref, &old_oid) < 0)
+ if (repo_get_oid(the_repository, object_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), object_ref);
type = oid_object_info(the_repository, &old_oid, NULL);
@@ -375,7 +383,7 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
struct object_id oid;
struct commit *commit;
- if (get_oid(argv[i], &oid) < 0) {
+ if (repo_get_oid(the_repository, argv[i], &oid) < 0) {
strbuf_release(&new_parents);
return error(_("not a valid object name: '%s'"),
argv[i]);
@@ -401,7 +409,7 @@ struct check_mergetag_data {
const char **argv;
};
-static int check_one_mergetag(struct commit *commit,
+static int check_one_mergetag(struct commit *commit UNUSED,
struct commit_extra_header *extra,
void *data)
{
@@ -422,7 +430,7 @@ static int check_one_mergetag(struct commit *commit,
/* iterate over new parents */
for (i = 1; i < mergetag_data->argc; i++) {
struct object_id oid;
- if (get_oid(mergetag_data->argv[i], &oid) < 0)
+ if (repo_get_oid(the_repository, 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))
@@ -452,15 +460,15 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
const char *buffer;
unsigned long size;
- if (get_oid(old_ref, &old_oid) < 0)
+ if (repo_get_oid(the_repository, old_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), old_ref);
commit = lookup_commit_reference(the_repository, &old_oid);
if (!commit)
return error(_("could not parse %s"), old_ref);
- buffer = get_commit_buffer(commit, &size);
+ buffer = repo_get_commit_buffer(the_repository, commit, &size);
strbuf_add(&buf, buffer, size);
- unuse_commit_buffer(commit, buffer);
+ repo_unuse_commit_buffer(the_repository, commit, buffer);
if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
strbuf_release(&buf);
@@ -559,7 +567,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
OPT_END()
};
- read_replace_refs = 0;
+ disable_replace_refs();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
diff --git a/builtin/replay.c b/builtin/replay.c
new file mode 100644
index 0000000000..6bc4b47f09
--- /dev/null
+++ b/builtin/replay.c
@@ -0,0 +1,446 @@
+/*
+ * "git replay" builtin command
+ */
+
+#define USE_THE_INDEX_VARIABLE
+#include "git-compat-util.h"
+
+#include "builtin.h"
+#include "environment.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "merge-ort.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "revision.h"
+#include "strmap.h"
+#include <oidset.h>
+#include <tree.h>
+
+static const char *short_commit_name(struct commit *commit)
+{
+ return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV);
+}
+
+static struct commit *peel_committish(const char *name)
+{
+ struct object *obj;
+ struct object_id oid;
+
+ if (repo_get_oid(the_repository, name, &oid))
+ return NULL;
+ obj = parse_object(the_repository, &oid);
+ return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+ OBJ_COMMIT);
+}
+
+static char *get_author(const char *message)
+{
+ size_t len;
+ const char *a;
+
+ a = find_commit_header(message, "author", &len);
+ if (a)
+ return xmemdupz(a, len);
+
+ return NULL;
+}
+
+static struct commit *create_commit(struct tree *tree,
+ struct commit *based_on,
+ struct commit *parent)
+{
+ struct object_id ret;
+ struct object *obj;
+ struct commit_list *parents = NULL;
+ char *author;
+ char *sign_commit = NULL; /* FIXME: cli users might want to sign again */
+ struct commit_extra_header *extra;
+ struct strbuf msg = STRBUF_INIT;
+ const char *out_enc = get_commit_output_encoding();
+ const char *message = repo_logmsg_reencode(the_repository, based_on,
+ NULL, out_enc);
+ const char *orig_message = NULL;
+ const char *exclude_gpgsig[] = { "gpgsig", NULL };
+
+ commit_list_insert(parent, &parents);
+ extra = read_commit_extra_headers(based_on, exclude_gpgsig);
+ find_commit_subject(message, &orig_message);
+ strbuf_addstr(&msg, orig_message);
+ author = get_author(message);
+ reset_ident_date();
+ if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
+ &ret, author, NULL, sign_commit, extra)) {
+ error(_("failed to write commit object"));
+ return NULL;
+ }
+ free(author);
+ strbuf_release(&msg);
+
+ obj = parse_object(the_repository, &ret);
+ return (struct commit *)obj;
+}
+
+struct ref_info {
+ struct commit *onto;
+ struct strset positive_refs;
+ struct strset negative_refs;
+ int positive_refexprs;
+ int negative_refexprs;
+};
+
+static void get_ref_information(struct rev_cmdline_info *cmd_info,
+ struct ref_info *ref_info)
+{
+ int i;
+
+ ref_info->onto = NULL;
+ strset_init(&ref_info->positive_refs);
+ strset_init(&ref_info->negative_refs);
+ ref_info->positive_refexprs = 0;
+ ref_info->negative_refexprs = 0;
+
+ /*
+ * When the user specifies e.g.
+ * git replay origin/main..mybranch
+ * git replay ^origin/next mybranch1 mybranch2
+ * we want to be able to determine where to replay the commits. In
+ * these examples, the branches are probably based on an old version
+ * of either origin/main or origin/next, so we want to replay on the
+ * newest version of that branch. In contrast we would want to error
+ * out if they ran
+ * git replay ^origin/master ^origin/next mybranch
+ * git replay mybranch~2..mybranch
+ * the first of those because there's no unique base to choose, and
+ * the second because they'd likely just be replaying commits on top
+ * of the same commit and not making any difference.
+ */
+ for (i = 0; i < cmd_info->nr; i++) {
+ struct rev_cmdline_entry *e = cmd_info->rev + i;
+ struct object_id oid;
+ const char *refexpr = e->name;
+ char *fullname = NULL;
+ int can_uniquely_dwim = 1;
+
+ if (*refexpr == '^')
+ refexpr++;
+ if (repo_dwim_ref(the_repository, refexpr, strlen(refexpr), &oid, &fullname, 0) != 1)
+ can_uniquely_dwim = 0;
+
+ if (e->flags & BOTTOM) {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->negative_refs, fullname);
+ if (!ref_info->negative_refexprs)
+ ref_info->onto = lookup_commit_reference_gently(the_repository,
+ &e->item->oid, 1);
+ ref_info->negative_refexprs++;
+ } else {
+ if (can_uniquely_dwim)
+ strset_add(&ref_info->positive_refs, fullname);
+ ref_info->positive_refexprs++;
+ }
+
+ free(fullname);
+ }
+}
+
+static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
+ const char *onto_name,
+ const char **advance_name,
+ struct commit **onto,
+ struct strset **update_refs)
+{
+ struct ref_info rinfo;
+
+ get_ref_information(cmd_info, &rinfo);
+ if (!rinfo.positive_refexprs)
+ die(_("need some commits to replay"));
+ if (onto_name && *advance_name)
+ die(_("--onto and --advance are incompatible"));
+ else if (onto_name) {
+ *onto = peel_committish(onto_name);
+ if (rinfo.positive_refexprs <
+ strset_get_size(&rinfo.positive_refs))
+ die(_("all positive revisions given must be references"));
+ } else if (*advance_name) {
+ struct object_id oid;
+ char *fullname = NULL;
+
+ *onto = peel_committish(*advance_name);
+ if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name),
+ &oid, &fullname, 0) == 1) {
+ *advance_name = fullname;
+ } else {
+ die(_("argument to --advance must be a reference"));
+ }
+ if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple sources because ordering would be ill-defined"));
+ } else {
+ int positive_refs_complete = (
+ rinfo.positive_refexprs ==
+ strset_get_size(&rinfo.positive_refs));
+ int negative_refs_complete = (
+ rinfo.negative_refexprs ==
+ strset_get_size(&rinfo.negative_refs));
+ /*
+ * We need either positive_refs_complete or
+ * negative_refs_complete, but not both.
+ */
+ if (rinfo.negative_refexprs > 0 &&
+ positive_refs_complete == negative_refs_complete)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ if (negative_refs_complete) {
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+
+ if (rinfo.negative_refexprs == 0)
+ die(_("all positive revisions given must be references"));
+ else if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+ else if (rinfo.positive_refexprs > 1)
+ die(_("cannot advance target with multiple source branches because ordering would be ill-defined"));
+
+ /* Only one entry, but we have to loop to get it */
+ strset_for_each_entry(&rinfo.negative_refs,
+ &iter, entry) {
+ *advance_name = entry->key;
+ }
+ } else { /* positive_refs_complete */
+ if (rinfo.negative_refexprs > 1)
+ die(_("cannot implicitly determine correct base for --onto"));
+ if (rinfo.negative_refexprs == 1)
+ *onto = rinfo.onto;
+ }
+ }
+ if (!*advance_name) {
+ *update_refs = xcalloc(1, sizeof(**update_refs));
+ **update_refs = rinfo.positive_refs;
+ memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
+ }
+ strset_clear(&rinfo.negative_refs);
+ strset_clear(&rinfo.positive_refs);
+}
+
+static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
+ struct commit *commit,
+ struct commit *fallback)
+{
+ khint_t pos = kh_get_oid_map(replayed_commits, commit->object.oid);
+ if (pos == kh_end(replayed_commits))
+ return fallback;
+ return kh_value(replayed_commits, pos);
+}
+
+static struct commit *pick_regular_commit(struct commit *pickme,
+ kh_oid_map_t *replayed_commits,
+ struct commit *onto,
+ struct merge_options *merge_opt,
+ struct merge_result *result)
+{
+ struct commit *base, *replayed_base;
+ struct tree *pickme_tree, *base_tree;
+
+ base = pickme->parents->item;
+ replayed_base = mapped_commit(replayed_commits, base, onto);
+
+ result->tree = repo_get_commit_tree(the_repository, replayed_base);
+ pickme_tree = repo_get_commit_tree(the_repository, pickme);
+ base_tree = repo_get_commit_tree(the_repository, base);
+
+ merge_opt->branch1 = short_commit_name(replayed_base);
+ merge_opt->branch2 = short_commit_name(pickme);
+ merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
+
+ merge_incore_nonrecursive(merge_opt,
+ base_tree,
+ result->tree,
+ pickme_tree,
+ result);
+
+ free((char*)merge_opt->ancestor);
+ merge_opt->ancestor = NULL;
+ if (!result->clean)
+ return NULL;
+ return create_commit(result->tree, pickme, replayed_base);
+}
+
+int cmd_replay(int argc, const char **argv, const char *prefix)
+{
+ const char *advance_name = NULL;
+ struct commit *onto = NULL;
+ const char *onto_name = NULL;
+ int contained = 0;
+
+ struct rev_info revs;
+ struct commit *last_commit = NULL;
+ struct commit *commit;
+ struct merge_options merge_opt;
+ struct merge_result result;
+ struct strset *update_refs = NULL;
+ kh_oid_map_t *replayed_commits;
+ int ret = 0;
+
+ const char * const replay_usage[] = {
+ N_("(EXPERIMENTAL!) git replay "
+ "([--contained] --onto <newbase> | --advance <branch>) "
+ "<revision-range>..."),
+ NULL
+ };
+ struct option replay_options[] = {
+ OPT_STRING(0, "advance", &advance_name,
+ N_("branch"),
+ N_("make replay advance given branch")),
+ OPT_STRING(0, "onto", &onto_name,
+ N_("revision"),
+ N_("replay onto given commit")),
+ OPT_BOOL(0, "contained", &contained,
+ N_("advance all branches contained in revision-range")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, replay_options, replay_usage,
+ PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+ if (!onto_name && !advance_name) {
+ error(_("option --onto or --advance is mandatory"));
+ usage_with_options(replay_usage, replay_options);
+ }
+
+ if (advance_name && contained)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--advance", "--contained");
+
+ repo_init_revisions(the_repository, &revs, prefix);
+
+ /*
+ * Set desired values for rev walking options here. If they
+ * are changed by some user specified option in setup_revisions()
+ * below, we will detect that below and then warn.
+ *
+ * TODO: In the future we might want to either die(), or allow
+ * some options changing these values if we think they could
+ * be useful.
+ */
+ revs.reverse = 1;
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ revs.topo_order = 1;
+ revs.simplify_history = 0;
+
+ argc = setup_revisions(argc, argv, &revs, NULL);
+ if (argc > 1) {
+ ret = error(_("unrecognized argument: %s"), argv[1]);
+ goto cleanup;
+ }
+
+ /*
+ * Detect and warn if we override some user specified rev
+ * walking options.
+ */
+ if (revs.reverse != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "reverse");
+ revs.reverse = 1;
+ }
+ if (revs.sort_order != REV_SORT_IN_GRAPH_ORDER) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "sort_order");
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ }
+ if (revs.topo_order != 1) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "topo_order");
+ revs.topo_order = 1;
+ }
+ if (revs.simplify_history != 0) {
+ warning(_("some rev walking options will be overridden as "
+ "'%s' bit in 'struct rev_info' will be forced"),
+ "simplify_history");
+ revs.simplify_history = 0;
+ }
+
+ determine_replay_mode(&revs.cmdline, onto_name, &advance_name,
+ &onto, &update_refs);
+
+ if (!onto) /* FIXME: Should handle replaying down to root commit */
+ die("Replaying down to root commit is not supported yet!");
+
+ if (prepare_revision_walk(&revs) < 0) {
+ ret = error(_("error preparing revisions"));
+ goto cleanup;
+ }
+
+ init_merge_options(&merge_opt, the_repository);
+ memset(&result, 0, sizeof(result));
+ merge_opt.show_rename_progress = 0;
+ last_commit = onto;
+ replayed_commits = kh_init_oid_map();
+ while ((commit = get_revision(&revs))) {
+ const struct name_decoration *decoration;
+ khint_t pos;
+ int hr;
+
+ if (!commit->parents)
+ die(_("replaying down to root commit is not supported yet!"));
+ if (commit->parents->next)
+ die(_("replaying merge commits is not supported yet!"));
+
+ last_commit = pick_regular_commit(commit, replayed_commits, onto,
+ &merge_opt, &result);
+ if (!last_commit)
+ break;
+
+ /* Record commit -> last_commit mapping */
+ pos = kh_put_oid_map(replayed_commits, commit->object.oid, &hr);
+ if (hr == 0)
+ BUG("Duplicate rewritten commit: %s\n",
+ oid_to_hex(&commit->object.oid));
+ kh_value(replayed_commits, pos) = last_commit;
+
+ /* Update any necessary branches */
+ if (advance_name)
+ continue;
+ decoration = get_name_decoration(&commit->object);
+ if (!decoration)
+ continue;
+ while (decoration) {
+ if (decoration->type == DECORATION_REF_LOCAL &&
+ (contained || strset_contains(update_refs,
+ decoration->name))) {
+ printf("update %s %s %s\n",
+ decoration->name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&commit->object.oid));
+ }
+ decoration = decoration->next;
+ }
+ }
+
+ /* In --advance mode, advance the target ref */
+ if (result.clean == 1 && advance_name) {
+ printf("update %s %s %s\n",
+ advance_name,
+ oid_to_hex(&last_commit->object.oid),
+ oid_to_hex(&onto->object.oid));
+ }
+
+ merge_finalize(&merge_opt, &result);
+ kh_destroy_oid_map(replayed_commits);
+ if (update_refs) {
+ strset_clear(update_refs);
+ free(update_refs);
+ }
+ ret = result.clean;
+
+cleanup:
+ release_revisions(&revs);
+
+ /* Return */
+ if (ret < 0)
+ exit(128);
+ return ret ? 0 : 1;
+}
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 83d7a778e3..b2efc6f640 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,8 +1,8 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
-#include "dir.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "string-list.h"
#include "rerere.h"
#include "xdiff/xdiff.h"
@@ -10,11 +10,11 @@
#include "pathspec.h"
static const char * const rerere_usage[] = {
- N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),
+ N_("git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"),
NULL,
};
-static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
+static int outf(void *dummy UNUSED, mmbuffer_t *ptr, int nbuf)
{
int i;
for (i = 0; i < nbuf; i++)
diff --git a/builtin/reset.c b/builtin/reset.c
index fdce6f8c85..8390bfe4c4 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,25 +7,34 @@
*
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
-#include "tag.h"
#include "object.h"
#include "pretty.h"
-#include "run-command.h"
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
#include "tree.h"
#include "branch.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "unpack-trees.h"
#include "cache-tree.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
+#include "trace.h"
+#include "trace2.h"
#include "dir.h"
+#include "add-interactive.h"
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
@@ -73,20 +82,22 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
case HARD:
opts.update = 1;
opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+ opts.skip_cache_tree_update = 1;
break;
case MIXED:
opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
+ opts.skip_cache_tree_update = 1;
/* but opts.update=0, so working tree not updated */
break;
default:
BUG("invalid reset_type passed to reset_index");
}
- read_cache_unmerged();
+ repo_read_index_unmerged(the_repository);
if (reset_type == KEEP) {
struct object_id head_oid;
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("You do not have a valid HEAD."));
if (!fill_tree_descriptor(the_repository, desc + nr, &head_oid))
return error(_("Failed to find tree of HEAD."));
@@ -121,7 +132,7 @@ static void print_new_head_line(struct commit *commit)
struct strbuf buf = STRBUF_INIT;
printf(_("HEAD is now at %s"),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
if (buf.len > 0)
@@ -131,7 +142,8 @@ static void print_new_head_line(struct commit *commit)
}
static void update_index_from_diff(struct diff_queue_struct *q,
- struct diff_options *opt, void *data)
+ struct diff_options *opt UNUSED,
+ void *data)
{
int i;
int intent_to_add = *(int *)data;
@@ -143,7 +155,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct cache_entry *ce;
if (!is_in_reset_tree && !intent_to_add) {
- remove_file_from_cache(one->path);
+ remove_file_from_index(&the_index, one->path);
continue;
}
@@ -158,8 +170,8 @@ static void update_index_from_diff(struct diff_queue_struct *q,
* if this entry is outside the sparse cone - this is necessary
* to properly construct the reset sparse directory.
*/
- pos = cache_name_pos(one->path, strlen(one->path));
- if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
+ pos = index_name_pos(&the_index, one->path, strlen(one->path));
+ if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
ce->ce_flags |= CE_SKIP_WORKTREE;
@@ -170,7 +182,8 @@ static void update_index_from_diff(struct diff_queue_struct *q,
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+ add_index_entry(&the_index, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
@@ -218,7 +231,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,
static void die_if_unmerged_cache(int reset_type)
{
- if (is_merge() || unmerged_cache())
+ if (is_merge() || unmerged_index(&the_index))
die(_("Cannot do a %s reset in the middle of a merge."),
_(reset_type_names[reset_type]));
@@ -255,8 +268,8 @@ static void parse_args(struct pathspec *pathspec,
* has to be unambiguous. If there is a single argument, it
* can not be a tree
*/
- else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
- (argv[1] && !get_oid_treeish(argv[0], &unused))) {
+ else if ((!argv[1] && !repo_get_oid_committish(the_repository, argv[0], &unused)) ||
+ (argv[1] && !repo_get_oid_treeish(the_repository, argv[0], &unused))) {
/*
* Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
@@ -283,9 +296,9 @@ static int reset_refs(const char *rev, const struct object_id *oid)
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
- if (!get_oid("ORIG_HEAD", &oid_old_orig))
+ if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
- if (!get_oid("HEAD", &oid_orig)) {
+ if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
@@ -299,12 +312,13 @@ static int reset_refs(const char *rev, const struct object_id *oid)
return update_ref_status;
}
-static int git_reset_config(const char *var, const char *value, void *cb)
+static int git_reset_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "submodule.recurse"))
return git_default_submodule_config(var, value, cb);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
int cmd_reset(int argc, const char **argv, const char *prefix)
@@ -312,7 +326,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int reset_type = NONE, update_ref_status = 0, quiet = 0;
int no_refresh = 0;
int patch_mode = 0, pathspec_file_nul = 0, unborn;
- const char *rev, *pathspec_from_file = NULL;
+ const char *rev;
+ char *pathspec_from_file = NULL;
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
@@ -320,18 +335,25 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_BOOL(0, "no-refresh", &no_refresh,
N_("skip refreshing the index after reset")),
- OPT_SET_INT(0, "mixed", &reset_type,
- N_("reset HEAD and index"), MIXED),
- OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
- OPT_SET_INT(0, "hard", &reset_type,
- N_("reset HEAD, index and working tree"), HARD),
- OPT_SET_INT(0, "merge", &reset_type,
- N_("reset HEAD, index and working tree"), MERGE),
- OPT_SET_INT(0, "keep", &reset_type,
- N_("reset HEAD but keep local changes"), KEEP),
+ OPT_SET_INT_F(0, "mixed", &reset_type,
+ N_("reset HEAD and index"),
+ MIXED, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "soft", &reset_type,
+ N_("reset only HEAD"),
+ SOFT, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "hard", &reset_type,
+ N_("reset HEAD, index and working tree"),
+ HARD, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "merge", &reset_type,
+ N_("reset HEAD, index and working tree"),
+ MERGE, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "keep", &reset_type,
+ N_("reset HEAD but keep local changes"),
+ KEEP, PARSE_OPT_NONEG),
OPT_CALLBACK_F(0, "recurse-submodules", NULL,
- "reset", "control recursive updating of submodules",
- PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+ "reset", "control recursive updating of submodules",
+ PARSE_OPT_OPTARG,
+ option_parse_recurse_submodules_worktree_updater),
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")),
@@ -360,13 +382,14 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
- unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
+ unborn = !strcmp(rev, "HEAD") && repo_get_oid(the_repository, "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) {
struct commit *commit;
- if (get_oid_committish(rev, &oid))
+ if (repo_get_oid_committish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
@@ -374,7 +397,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
oidcpy(&oid, &commit->object.oid);
} else {
struct tree *tree;
- if (get_oid_treeish(rev, &oid))
+ if (repo_get_oid_treeish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid tree."), rev);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -386,7 +409,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type != NONE)
die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
trace2_cmd_mode("patch-interactive");
- return run_add_interactive(rev, "--patch=reset", &pathspec);
+ update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
+ &pathspec);
+ goto cleanup;
}
/* git reset tree [--] paths... can be used to
@@ -420,7 +445,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
/* Soft reset does not touch the index file nor the working tree
@@ -431,11 +456,14 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type != SOFT) {
struct lock_file lock = LOCK_INIT;
- hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock,
+ LOCK_DIE_ON_ERROR);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- if (read_from_tree(&pathspec, &oid, intent_to_add))
- return 1;
+ if (read_from_tree(&pathspec, &oid, intent_to_add)) {
+ update_ref_status = 1;
+ goto cleanup;
+ }
the_index.updated_skipworktree = 1;
if (!no_refresh && get_git_work_tree()) {
uint64_t t_begin, t_delta_in_ms;
@@ -454,7 +482,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
char *ref = NULL;
int err;
- dwim_ref(rev, strlen(rev), &dummy, &ref, 0);
+ repo_dwim_ref(the_repository, rev, strlen(rev),
+ &dummy, &ref, 0);
if (ref && !starts_with(ref, "refs/"))
FREE_AND_NULL(ref);
@@ -481,5 +510,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
+ discard_index(&the_index);
+
+cleanup:
+ clear_pathspec(&pathspec);
+ free(pathspec_from_file);
return update_ref_status;
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index fba6f5d51f..b3f4783858 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -1,16 +1,18 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "revision.h"
#include "list-objects.h"
-#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
#include "object.h"
-#include "object-store.h"
-#include "pack.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "object-store-ll.h"
#include "pack-bitmap.h"
-#include "builtin.h"
#include "log-tree.h"
#include "graph.h"
#include "bisect.h"
@@ -20,7 +22,8 @@
#include "packfile.h"
static const char rev_list_usage[] =
-"git rev-list [<options>] <commit-id>... [-- <path>...]\n"
+"git rev-list [<options>] <commit>... [--] [<path>...]\n"
+"\n"
" limiting output:\n"
" --max-count=<n>\n"
" --max-age=<epoch>\n"
@@ -37,6 +40,7 @@ static const char rev_list_usage[] =
" --tags\n"
" --remotes\n"
" --stdin\n"
+" --exclude-hidden=[fetch|receive|uploadpack]\n"
" --quiet\n"
" ordering output:\n"
" --topo-order\n"
@@ -94,7 +98,48 @@ static off_t get_object_disk_usage(struct object *obj)
return size;
}
-static void finish_commit(struct commit *commit);
+static inline void finish_object__ma(struct object *obj)
+{
+ /*
+ * Whether or not we try to dynamically fetch missing objects
+ * from the server, we currently DO NOT have the object. We
+ * can either print, allow (ignore), or conditionally allow
+ * (ignore) them.
+ */
+ switch (arg_missing_action) {
+ case MA_ERROR:
+ die("missing %s object '%s'",
+ type_name(obj->type), oid_to_hex(&obj->oid));
+ return;
+
+ case MA_ALLOW_ANY:
+ return;
+
+ case MA_PRINT:
+ oidset_insert(&missing_objects, &obj->oid);
+ return;
+
+ case MA_ALLOW_PROMISOR:
+ if (is_promisor_object(&obj->oid))
+ return;
+ die("unexpected missing %s object '%s'",
+ type_name(obj->type), oid_to_hex(&obj->oid));
+ return;
+
+ default:
+ BUG("unhandled missing_action");
+ return;
+ }
+}
+
+static void finish_commit(struct commit *commit)
+{
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
+ free_commit_buffer(the_repository->parsed_objects,
+ commit);
+}
+
static void show_commit(struct commit *commit, void *data)
{
struct rev_list_info *info = data;
@@ -102,6 +147,12 @@ static void show_commit(struct commit *commit, void *data)
display_progress(progress, ++progress_counter);
+ if (revs->do_not_die_on_missing_objects &&
+ oidset_contains(&revs->missing_commits, &commit->object.oid)) {
+ finish_object__ma(&commit->object);
+ return;
+ }
+
if (show_disk_usage)
total_disk_usage += get_object_disk_usage(&commit->object);
@@ -132,7 +183,7 @@ static void show_commit(struct commit *commit, void *data)
if (!revs->graph)
fputs(get_revision_mark(revs, commit), stdout);
if (revs->abbrev_commit && revs->abbrev)
- fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
+ fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, revs->abbrev),
stdout);
else
fputs(oid_to_hex(&commit->object.oid), stdout);
@@ -213,49 +264,8 @@ static void show_commit(struct commit *commit, void *data)
finish_commit(commit);
}
-static void finish_commit(struct commit *commit)
-{
- free_commit_list(commit->parents);
- commit->parents = NULL;
- free_commit_buffer(the_repository->parsed_objects,
- commit);
-}
-
-static inline void finish_object__ma(struct object *obj)
-{
- /*
- * Whether or not we try to dynamically fetch missing objects
- * from the server, we currently DO NOT have the object. We
- * can either print, allow (ignore), or conditionally allow
- * (ignore) them.
- */
- switch (arg_missing_action) {
- case MA_ERROR:
- die("missing %s object '%s'",
- type_name(obj->type), oid_to_hex(&obj->oid));
- return;
-
- case MA_ALLOW_ANY:
- return;
-
- case MA_PRINT:
- oidset_insert(&missing_objects, &obj->oid);
- return;
-
- case MA_ALLOW_PROMISOR:
- if (is_promisor_object(&obj->oid))
- return;
- die("unexpected missing %s object '%s'",
- type_name(obj->type), oid_to_hex(&obj->oid));
- return;
-
- default:
- BUG("unhandled missing_action");
- return;
- }
-}
-
-static int finish_object(struct object *obj, const char *name, void *cb_data)
+static int finish_object(struct object *obj, const char *name UNUSED,
+ void *cb_data)
{
struct rev_list_info *info = cb_data;
if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
@@ -360,11 +370,11 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
static int show_object_fast(
const struct object_id *oid,
- enum object_type type,
- int exclude,
- uint32_t name_hash,
- struct packed_git *found_pack,
- off_t found_offset)
+ enum object_type type UNUSED,
+ int exclude UNUSED,
+ uint32_t name_hash UNUSED,
+ struct packed_git *found_pack UNUSED,
+ off_t found_offset UNUSED)
{
fprintf(stdout, "%s\n", oid_to_hex(oid));
return 1;
@@ -554,7 +564,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
}
if (arg_missing_action)
- revs.do_not_die_on_missing_tree = 1;
+ revs.do_not_die_on_missing_objects = 1;
argc = setup_revisions(argc, argv, &revs, &s_r_opt);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 8f61050bde..d08987646a 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -3,16 +3,24 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "refs.h"
#include "quote.h"
-#include "builtin.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "diff.h"
+#include "read-cache-ll.h"
#include "revision.h"
+#include "setup.h"
#include "split-index.h"
#include "submodule.h"
#include "commit-reach.h"
@@ -39,7 +47,7 @@ static int abbrev_ref_strict;
static int output_sq;
static int stuck_long;
-static struct string_list *ref_excludes;
+static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
/*
* Some arguments are relevant "revision" arguments,
@@ -136,7 +144,9 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), &discard, &full, 0)) {
+ switch (repo_dwim_ref(the_repository, name,
+ strlen(name), &discard, &full,
+ 0)) {
case 0:
/*
* Not found -- not a ref. We could
@@ -147,9 +157,12 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
*/
break;
case 1: /* happy */
- if (abbrev_ref)
+ if (abbrev_ref) {
+ char *old = full;
full = shorten_unambiguous_ref(full,
abbrev_ref_strict);
+ free(old);
+ }
show_with_type(type, full);
break;
default: /* ambiguous */
@@ -162,7 +175,8 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
}
}
else if (abbrev)
- show_with_type(type, find_unique_abbrev(oid, abbrev));
+ show_with_type(type,
+ repo_find_unique_abbrev(the_repository, oid, abbrev));
else
show_with_type(type, oid_to_hex(oid));
}
@@ -187,7 +201,7 @@ static int show_default(void)
struct object_id oid;
def = NULL;
- if (!get_oid(s, &oid)) {
+ if (!repo_get_oid(the_repository, s, &oid)) {
show_rev(NORMAL, &oid, s);
return 1;
}
@@ -198,7 +212,7 @@ static int show_default(void)
static int show_reference(const char *refname, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
- if (ref_excluded(ref_excludes, refname))
+ if (ref_excluded(&ref_excludes, refname))
return 0;
show_rev(NORMAL, oid, refname);
return 0;
@@ -211,7 +225,7 @@ static int anti_reference(const char *refname, const struct object_id *oid,
return 0;
}
-static int show_abbrev(const struct object_id *oid, void *cb_data)
+static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
{
show_rev(NORMAL, oid, NULL);
return 0;
@@ -279,7 +293,7 @@ static int try_difference(const char *arg)
return 0;
}
- if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
+ if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
show_rev(NORMAL, &end_oid, end);
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) {
@@ -291,7 +305,7 @@ static int try_difference(const char *arg)
*dotdot = '.';
return 0;
}
- exclude = get_merge_bases(a, b);
+ exclude = repo_get_merge_bases(the_repository, a, b);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
show_rev(REVERSED, &commit->object.oid, NULL);
@@ -337,7 +351,7 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
- if (get_oid_committish(arg, &oid) ||
+ if (repo_get_oid_committish(the_repository, arg, &oid) ||
!(commit = lookup_commit_reference(the_repository, &oid))) {
*dotdot = '^';
return 0;
@@ -530,6 +544,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
strbuf_addstr(&parsed, " --");
sq_quote_argv(&parsed, argv);
puts(parsed.buf);
+ strbuf_release(&parsed);
return 0;
}
@@ -585,7 +600,7 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
else
for_each_ref_in(prefix, show_reference, NULL);
- clear_ref_exclusion(&ref_excludes);
+ clear_ref_exclusions(&ref_excludes);
}
enum format_type {
@@ -863,11 +878,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--all")) {
for_each_ref(show_reference, NULL);
- clear_ref_exclusion(&ref_excludes);
+ clear_ref_exclusions(&ref_excludes);
continue;
}
if (skip_prefix(arg, "--disambiguate=", &arg)) {
- for_each_abbrev(arg, show_abbrev, NULL);
+ repo_for_each_abbrev(the_repository, arg,
+ show_abbrev, NULL);
continue;
}
if (!strcmp(arg, "--bisect")) {
@@ -876,10 +892,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (opt_with_value(arg, "--branches", &arg)) {
+ if (ref_excludes.hidden_refs_configured)
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--branches");
handle_ref_opt(arg, "refs/heads/");
continue;
}
if (opt_with_value(arg, "--tags", &arg)) {
+ if (ref_excludes.hidden_refs_configured)
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--tags");
handle_ref_opt(arg, "refs/tags/");
continue;
}
@@ -888,6 +910,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (opt_with_value(arg, "--remotes", &arg)) {
+ if (ref_excludes.hidden_refs_configured)
+ return error(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-hidden", "--remotes");
handle_ref_opt(arg, "refs/remotes/");
continue;
}
@@ -895,6 +920,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
add_ref_exclusion(&ref_excludes, arg);
continue;
}
+ if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
+ exclude_hidden_refs(&ref_excludes, arg);
+ continue;
+ }
if (!strcmp(arg, "--show-toplevel")) {
const char *work_tree = get_git_work_tree();
if (work_tree)
@@ -997,7 +1026,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--shared-index-path")) {
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("Could not read the index"));
if (the_index.split_index) {
const struct object_id *oid = &the_index.split_index->base_oid;
@@ -1033,6 +1062,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(the_hash_algo->name);
continue;
}
+ if (!strcmp(arg, "--show-ref-format")) {
+ puts(ref_storage_format_to_name(the_repository->ref_storage_format));
+ continue;
+ }
if (!strcmp(arg, "--end-of-options")) {
seen_end_of_options = 1;
if (filter & (DO_FLAGS | DO_REVS))
diff --git a/builtin/revert.c b/builtin/revert.c
index ee2a0807f0..89821bab95 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,11 +1,11 @@
-#include "cache.h"
-#include "config.h"
+#include "git-compat-util.h"
#include "builtin.h"
#include "parse-options.h"
#include "diff.h"
+#include "gettext.h"
+#include "repository.h"
#include "revision.h"
#include "rerere.h"
-#include "dir.h"
#include "sequencer.h"
#include "branch.h"
@@ -21,14 +21,15 @@
*/
static const char * const revert_usage[] = {
- N_("git revert [<options>] <commit-ish>..."),
- N_("git revert <subcommand>"),
+ N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>..."),
+ N_("git revert (--continue | --skip | --abort | --quit)"),
NULL
};
static const char * const cherry_pick_usage[] = {
- N_("git cherry-pick [<options>] <commit-ish>..."),
- N_("git cherry-pick <subcommand>"),
+ N_("git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+ " [-S[<keyid>]] <commit>..."),
+ N_("git cherry-pick (--continue | --skip | --abort | --quit)"),
NULL
};
@@ -42,20 +43,6 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
}
-static int option_parse_x(const struct option *opt,
- const char *arg, int unset)
-{
- struct replay_opts **opts_ptr = opt->value;
- struct replay_opts *opts = *opts_ptr;
-
- if (unset)
- return 0;
-
- ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
- opts->xopts[opts->xopts_nr++] = xstrdup(arg);
- return 0;
-}
-
static int option_parse_m(const struct option *opt,
const char *arg, int unset)
{
@@ -92,7 +79,8 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
}
-static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
+static int run_sequencer(int argc, const char **argv, const char *prefix,
+ struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
@@ -112,8 +100,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
- OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
- N_("option for merge strategy"), option_parse_x),
+ OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
+ N_("option for merge strategy")),
{ OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
@@ -139,7 +127,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
options = parse_options_concat(options, cp_extra);
}
- argc = parse_options(argc, argv, NULL, options, usage_str,
+ argc = parse_options(argc, argv, prefix, options, usage_str,
PARSE_OPT_KEEP_ARGV0 |
PARSE_OPT_KEEP_UNKNOWN_OPT);
@@ -174,7 +162,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
"--signoff", opts->signoff,
"--mainline", opts->mainline,
"--strategy", opts->strategy ? 1 : 0,
- "--strategy-option", opts->xopts ? 1 : 0,
+ "--strategy-option", opts->xopts.nr ? 1 : 0,
"-x", opts->record_origin,
"--ff", opts->allow_ff,
"--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
@@ -220,6 +208,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
opts->strategy = xstrdup_or_null(opts->strategy);
if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+ free(options);
if (cmd == 'q') {
int ret = sequencer_remove_state(opts);
@@ -243,12 +232,10 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
opts.action = REPLAY_REVERT;
sequencer_init_config(&opts);
- res = run_sequencer(argc, argv, &opts);
+ res = run_sequencer(argc, argv, prefix, &opts);
if (res < 0)
die(_("revert failed"));
- if (opts.revs)
- release_revisions(opts.revs);
- free(opts.revs);
+ replay_opts_release(&opts);
return res;
}
@@ -259,8 +246,9 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
opts.action = REPLAY_PICK;
sequencer_init_config(&opts);
- res = run_sequencer(argc, argv, &opts);
+ res = run_sequencer(argc, argv, prefix, &opts);
if (res < 0)
die(_("cherry-pick failed"));
+ replay_opts_release(&opts);
return res;
}
diff --git a/builtin/rm.c b/builtin/rm.c
index b6ba859fe4..fd130cea2d 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,21 +3,29 @@
*
* Copyright (C) Linus Torvalds 2006
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
#include "lockfile.h"
#include "dir.h"
-#include "cache-tree.h"
+#include "gettext.h"
+#include "hash.h"
#include "tree-walk.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "read-cache.h"
+#include "repository.h"
#include "string-list.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "pathspec.h"
static const char * const builtin_rm_usage[] = {
- N_("git rm [<options>] [--] <file>..."),
+ N_("git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
+ " [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+ " [--] [<pathspec>...]"),
NULL
};
@@ -33,8 +41,8 @@ static int get_ours_cache_pos(const char *path, int pos)
{
int i = -pos - 1;
- while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) {
- if (ce_stage(active_cache[i]) == 2)
+ while ((i < the_index.cache_nr) && !strcmp(the_index.cache[i]->name, path)) {
+ if (ce_stage(the_index.cache[i]) == 2)
return i;
i++;
}
@@ -70,13 +78,13 @@ static void submodules_absorb_gitdir_if_needed(void)
int pos;
const struct cache_entry *ce;
- pos = cache_name_pos(name, strlen(name));
+ pos = index_name_pos(&the_index, name, strlen(name));
if (pos < 0) {
pos = get_ours_cache_pos(name, pos);
if (pos < 0)
continue;
}
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (!S_ISGITLINK(ce->ce_mode) ||
!file_exists(ce->name) ||
@@ -84,8 +92,7 @@ static void submodules_absorb_gitdir_if_needed(void)
continue;
if (!submodule_uses_gitfile(name))
- absorb_git_dir_into_superproject(name,
- ABSORB_GITDIR_RECURSE_SUBMODULES);
+ absorb_git_dir_into_superproject(name, NULL);
}
}
@@ -115,7 +122,7 @@ static int check_local_mod(struct object_id *head, int index_only)
int local_changes = 0;
int staged_changes = 0;
- pos = cache_name_pos(name, strlen(name));
+ pos = index_name_pos(&the_index, name, strlen(name));
if (pos < 0) {
/*
* Skip unmerged entries except for populated submodules
@@ -125,11 +132,11 @@ static int check_local_mod(struct object_id *head, int index_only)
if (pos < 0)
continue;
- if (!S_ISGITLINK(active_cache[pos]->ce_mode) ||
+ if (!S_ISGITLINK(the_index.cache[pos]->ce_mode) ||
is_empty_dir(name))
continue;
}
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (lstat(ce->name, &st) < 0) {
if (!is_missing_file_error(errno))
@@ -166,7 +173,7 @@ static int check_local_mod(struct object_id *head, int index_only)
* Is the index different from the file in the work tree?
* If it's a submodule, is its work tree modified?
*/
- if (ce_match_stat(ce, &st, 0) ||
+ if (ie_match_stat(&the_index, ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
bad_to_remove_submodule(ce->name,
SUBMODULE_REMOVAL_DIE_ON_ERROR |
@@ -289,9 +296,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
@@ -301,8 +308,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (pathspec_needs_expanded_index(&the_index, &pathspec))
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ const struct cache_entry *ce = the_index.cache[i];
if (!include_sparse &&
(ce_skip_worktree(ce) ||
@@ -369,7 +376,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
*/
if (!force) {
struct object_id oid;
- if (get_oid("HEAD", &oid))
+ if (repo_get_oid(the_repository, "HEAD", &oid))
oidclr(&oid);
if (check_local_mod(&oid, index_only))
exit(1);
@@ -384,7 +391,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!quiet)
printf("rm '%s'\n", path);
- if (remove_file_from_cache(path))
+ if (remove_file_from_index(&the_index, path))
die(_("git rm: unable to remove %s"), path);
}
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 64962be016..b7183be970 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,25 +1,24 @@
#include "builtin.h"
#include "config.h"
-#include "commit.h"
-#include "refs.h"
+#include "hex.h"
#include "pkt-line.h"
-#include "sideband.h"
#include "run-command.h"
#include "remote.h"
#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
-#include "version.h"
#include "oid-array.h"
-#include "gpg-interface.h"
#include "gettext.h"
#include "protocol.h"
+#include "parse-options.h"
+#include "write-or-die.h"
static const char * const send_pack_usage[] = {
N_("git send-pack [--mirror] [--dry-run] [--force]\n"
" [--receive-pack=<git-receive-pack>]\n"
" [--verbose] [--thin] [--atomic]\n"
+ " [--[no-]signed | --signed=(true|false|if-asked)]\n"
" [<host>:]<directory> (--all | <ref>...)"),
NULL,
};
@@ -127,29 +126,25 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf);
}
-static int send_pack_config(const char *k, const char *v, void *cb)
+static int send_pack_config(const char *k, const char *v,
+ const struct config_context *ctx, void *cb)
{
- git_gpg_config(k, v, NULL);
-
if (!strcmp(k, "push.gpgsign")) {
- const char *value;
- if (!git_config_get_value("push.gpgsign", &value)) {
- switch (git_parse_maybe_bool(value)) {
- case 0:
- args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
- break;
- case 1:
- args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
- break;
- default:
- if (value && !strcasecmp(value, "if-asked"))
- args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
- else
- return error(_("invalid value for '%s'"), k);
- }
+ switch (git_parse_maybe_bool(v)) {
+ case 0:
+ args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
+ break;
+ case 1:
+ args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
+ break;
+ default:
+ if (!strcasecmp(v, "if-asked"))
+ args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
+ else
+ return error(_("invalid value for '%s'"), k);
}
}
- return git_default_config(k, v, cb);
+ return git_default_config(k, v, ctx, cb);
}
int cmd_send_pack(int argc, const char **argv, const char *prefix)
@@ -205,7 +200,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
- OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
+ OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option),
OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
@@ -274,7 +269,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
fd[0] = 0;
fd[1] = 1;
} else {
- conn = git_connect(fd, dest, receivepack,
+ conn = git_connect(fd, dest, "git-receive-pack", receivepack,
args.verbose ? CONNECT_VERBOSE : 0);
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 7a1e1fe7c0..1307ed2b88 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -1,12 +1,15 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "commit.h"
#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
#include "string-list.h"
+#include "repository.h"
#include "revision.h"
#include "utf8.h"
#include "mailmap.h"
+#include "setup.h"
#include "shortlog.h"
#include "parse-options.h"
#include "trailer.h"
@@ -132,7 +135,9 @@ static void read_from_stdin(struct shortlog *log)
match = committer_match;
break;
case SHORTLOG_GROUP_TRAILER:
- die(_("using --group=trailer with stdin is not supported"));
+ die(_("using %s with stdin is not supported"), "--group=trailer");
+ case SHORTLOG_GROUP_FORMAT:
+ die(_("using %s with stdin is not supported"), "--group=format");
default:
BUG("unhandled shortlog group");
}
@@ -170,11 +175,15 @@ static void insert_records_from_trailers(struct shortlog *log,
const char *commit_buffer, *body;
struct strbuf ident = STRBUF_INIT;
+ if (!log->trailers.nr)
+ return;
+
/*
- * Using format_commit_message("%B") would be simpler here, but
+ * Using repo_format_commit_message("%B") would be simpler here, but
* this saves us copying the message.
*/
- commit_buffer = logmsg_reencode(commit, NULL, ctx->output_encoding);
+ commit_buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+ ctx->output_encoding);
body = strstr(commit_buffer, "\n\n");
if (!body)
return;
@@ -197,12 +206,38 @@ static void insert_records_from_trailers(struct shortlog *log,
trailer_iterator_release(&iter);
strbuf_release(&ident);
- unuse_commit_buffer(commit, commit_buffer);
+ repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
+}
+
+static int shortlog_needs_dedup(const struct shortlog *log)
+{
+ return HAS_MULTI_BITS(log->groups) || log->format.nr > 1 || log->trailers.nr;
+}
+
+static void insert_records_from_format(struct shortlog *log,
+ struct strset *dups,
+ struct commit *commit,
+ struct pretty_print_context *ctx,
+ const char *oneline)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, &log->format) {
+ strbuf_reset(&buf);
+
+ repo_format_commit_message(the_repository, commit,
+ item->string, &buf, ctx);
+
+ if (!shortlog_needs_dedup(log) || strset_add(dups, buf.buf))
+ insert_one_record(log, buf.buf, oneline);
+ }
+
+ strbuf_release(&buf);
}
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
{
- struct strbuf ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
struct strset dups = STRSET_INIT;
struct pretty_print_context ctx = {0};
@@ -211,41 +246,22 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
ctx.print_email_subject = 1;
- ctx.date_mode.type = DATE_NORMAL;
+ ctx.date_mode = log->date_mode;
ctx.output_encoding = get_log_output_encoding();
if (!log->summary) {
if (log->user_format)
pretty_print_commit(&ctx, commit, &oneline);
else
- format_commit_message(commit, "%s", &oneline, &ctx);
+ repo_format_commit_message(the_repository, commit,
+ "%s", &oneline, &ctx);
}
oneline_str = oneline.len ? oneline.buf : "<none>";
- if (log->groups & SHORTLOG_GROUP_AUTHOR) {
- strbuf_reset(&ident);
- format_commit_message(commit,
- log->email ? "%aN <%aE>" : "%aN",
- &ident, &ctx);
- if (!HAS_MULTI_BITS(log->groups) ||
- strset_add(&dups, ident.buf))
- insert_one_record(log, ident.buf, oneline_str);
- }
- if (log->groups & SHORTLOG_GROUP_COMMITTER) {
- strbuf_reset(&ident);
- format_commit_message(commit,
- log->email ? "%cN <%cE>" : "%cN",
- &ident, &ctx);
- if (!HAS_MULTI_BITS(log->groups) ||
- strset_add(&dups, ident.buf))
- insert_one_record(log, ident.buf, oneline_str);
- }
- if (log->groups & SHORTLOG_GROUP_TRAILER) {
- insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
- }
+ insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
+ insert_records_from_format(log, &dups, commit, &ctx, oneline_str);
strset_clear(&dups);
- strbuf_release(&ident);
strbuf_release(&oneline);
}
@@ -314,6 +330,7 @@ static int parse_group_option(const struct option *opt, const char *arg, int uns
if (unset) {
log->groups = 0;
string_list_clear(&log->trailers, 0);
+ string_list_clear(&log->format, 0);
} else if (!strcasecmp(arg, "author"))
log->groups |= SHORTLOG_GROUP_AUTHOR;
else if (!strcasecmp(arg, "committer"))
@@ -321,8 +338,15 @@ static int parse_group_option(const struct option *opt, const char *arg, int uns
else if (skip_prefix(arg, "trailer:", &field)) {
log->groups |= SHORTLOG_GROUP_TRAILER;
string_list_append(&log->trailers, field);
- } else
+ } else if (skip_prefix(arg, "format:", &field)) {
+ log->groups |= SHORTLOG_GROUP_FORMAT;
+ string_list_append(&log->format, field);
+ } else if (strchr(arg, '%')) {
+ log->groups |= SHORTLOG_GROUP_FORMAT;
+ string_list_append(&log->format, arg);
+ } else {
return error(_("unknown group type: %s"), arg);
+ }
return 0;
}
@@ -340,6 +364,19 @@ void shortlog_init(struct shortlog *log)
log->in2 = DEFAULT_INDENT2;
log->trailers.strdup_strings = 1;
log->trailers.cmp = strcasecmp;
+ log->format.strdup_strings = 1;
+}
+
+void shortlog_finish_setup(struct shortlog *log)
+{
+ if (log->groups & SHORTLOG_GROUP_AUTHOR)
+ string_list_append(&log->format,
+ log->email ? "%aN <%aE>" : "%aN");
+ if (log->groups & SHORTLOG_GROUP_COMMITTER)
+ string_list_append(&log->format,
+ log->email ? "%cN <%cE>" : "%cN");
+
+ string_list_sort(&log->trailers);
}
int cmd_shortlog(int argc, const char **argv, const char *prefix)
@@ -407,10 +444,11 @@ parse_done:
log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
log.abbrev = rev.abbrev;
log.file = rev.diffopt.file;
+ log.date_mode = rev.date_mode;
if (!log.groups)
log.groups = SHORTLOG_GROUP_AUTHOR;
- string_list_sort(&log.trailers);
+ shortlog_finish_setup(&log);
/* assume HEAD if from a tty */
if (!nongit && !rev.pending.nr && isatty(0))
@@ -479,4 +517,5 @@ void shortlog_output(struct shortlog *log)
log->list.strdup_strings = 1;
string_list_clear(&log->list, 1);
clear_mailmap(&log->mailmap);
+ string_list_clear(&log->format, 0);
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index d3f5715e3e..b01ec761d2 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -1,20 +1,27 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "pretty.h"
#include "refs.h"
-#include "builtin.h"
#include "color.h"
#include "strvec.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "repository.h"
#include "dir.h"
#include "commit-slab.h"
#include "date.h"
+#include "wildmatch.h"
static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
" [--current] [--color[=<when>] | --no-color] [--sparse]\n"
" [--more=<n> | --list | --independent | --merge-base]\n"
- " [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ " [--no-name | --sha1-name] [--topics]\n"
+ " [(<rev> | <glob>)...]"),
N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
@@ -239,7 +246,7 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
- parse_commit(p);
+ repo_parse_commit(the_repository, p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
@@ -311,8 +318,8 @@ static void show_one_commit(struct commit *commit, int no_name)
}
else
printf("[%s] ",
- find_unique_abbrev(&commit->object.oid,
- DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid,
+ DEFAULT_ABBREV));
}
puts(pretty_str);
strbuf_release(&pretty);
@@ -413,7 +420,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+ if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -428,7 +435,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
- if (get_oid(refname + ofs, &tmp) || !oideq(&tmp, oid))
+ if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
ofs = 5;
return append_ref(refname + ofs, oid, 0);
}
@@ -532,7 +539,7 @@ static int show_independent(struct commit **rev,
static void append_one_rev(const char *av)
{
struct object_id revkey;
- if (!get_oid(av, &revkey)) {
+ if (!repo_get_oid(the_repository, av, &revkey)) {
append_ref(av, &revkey, 0);
return;
}
@@ -552,7 +559,8 @@ static void append_one_rev(const char *av)
die("bad sha1 reference %s", av);
}
-static int git_show_branch_config(const char *var, const char *value, void *cb)
+static int git_show_branch_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "showbranch.default")) {
if (!value)
@@ -572,7 +580,10 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_color_default_config(var, value, cb);
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -638,7 +649,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int with_current_branch = 0;
int head_at = -1;
int topics = 0;
- int dense = 1;
+ int sparse = 0;
const char *reflog_base = NULL;
struct option builtin_show_branch_options[] = {
OPT_BOOL('a', "all", &all_heads,
@@ -660,17 +671,17 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
N_("show possible merge bases")),
OPT_BOOL(0, "independent", &independent,
N_("show refs unreachable from any other ref")),
- OPT_SET_INT(0, "topo-order", &sort_order,
- N_("show commits in topological order"),
- REV_SORT_IN_GRAPH_ORDER),
+ OPT_SET_INT_F(0, "topo-order", &sort_order,
+ N_("show commits in topological order"),
+ REV_SORT_IN_GRAPH_ORDER, PARSE_OPT_NONEG),
OPT_BOOL(0, "topics", &topics,
N_("show only commits not on the first branch")),
- OPT_SET_INT(0, "sparse", &dense,
- N_("show merges reachable from only one tip"), 0),
- OPT_SET_INT(0, "date-order", &sort_order,
- N_("topologically sort, maintaining date order "
- "where possible"),
- REV_SORT_BY_COMMIT_DATE),
+ OPT_SET_INT(0, "sparse", &sparse,
+ N_("show merges reachable from only one tip"), 1),
+ OPT_SET_INT_F(0, "date-order", &sort_order,
+ N_("topologically sort, maintaining date order "
+ "where possible"),
+ REV_SORT_BY_COMMIT_DATE, PARSE_OPT_NONEG),
OPT_CALLBACK_F('g', "reflog", &reflog_base, N_("<n>[,<base>]"),
N_("show <n> most recent ref-log entries starting at "
"base"),
@@ -745,7 +756,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), &oid, &ref, 0))
+ if (!repo_dwim_ref(the_repository, *av, strlen(*av), &oid,
+ &ref, 0))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
@@ -835,13 +847,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("cannot handle more than %d rev.",
"cannot handle more than %d revs.",
MAX_REVS), MAX_REVS);
- if (get_oid(ref_name[num_rev], &revkey))
+ if (repo_get_oid(the_repository, ref_name[num_rev], &revkey))
die(_("'%s' is not a valid ref."), ref_name[num_rev]);
commit = lookup_commit_reference(the_repository, &revkey);
if (!commit)
die(_("cannot find commit %s (%s)"),
ref_name[num_rev], oid_to_hex(&revkey));
- parse_commit(commit);
+ repo_parse_commit(the_repository, commit);
mark_seen(commit, &seen);
/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
@@ -928,7 +940,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
!is_merge_point &&
(this_flag & (1u << REV_SHIFT)))
continue;
- if (dense && is_merge &&
+ if (!sparse && is_merge &&
omit_in_dense(commit, rev, num_rev))
continue;
for (i = 0; i < num_rev; i++) {
@@ -955,5 +967,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (shown_merge_point && --extra < 0)
break;
}
+ free(head);
return 0;
}
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 0e0b9fb95b..540dc3dad1 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,7 +1,10 @@
#include "builtin.h"
-#include "cache.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "pack.h"
#include "parse-options.h"
+#include "repository.h"
static const char *const show_index_usage[] = {
"git show-index [--object-format=<hash-algorithm>]",
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 4856906108..aaa2c39b2f 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,60 +1,79 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
-#include "refs.h"
-#include "object-store.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs/refs-internal.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "object.h"
-#include "tag.h"
#include "string-list.h"
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"),
+ N_("git show-ref [--head] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
+ " [--heads] [--] [<pattern>...]"),
+ N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+ " [--] [<ref>...]"),
N_("git show-ref --exclude-existing[=<pattern>]"),
+ N_("git show-ref --exists <ref>"),
NULL
};
-static int deref_tags, show_head, tags_only, heads_only, found_match, verify,
- quiet, hash_only, abbrev, exclude_arg;
-static const char **pattern;
-static const char *exclude_existing_arg;
+struct show_one_options {
+ int quiet;
+ int hash_only;
+ int abbrev;
+ int deref_tags;
+};
-static void show_one(const char *refname, const struct object_id *oid)
+static void show_one(const struct show_one_options *opts,
+ const char *refname, const struct object_id *oid)
{
const char *hex;
struct object_id peeled;
- if (!has_object_file(oid))
+ if (!repo_has_object_file(the_repository, oid))
die("git show-ref: bad ref %s (%s)", refname,
oid_to_hex(oid));
- if (quiet)
+ if (opts->quiet)
return;
- hex = find_unique_abbrev(oid, abbrev);
- if (hash_only)
+ hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
+ if (opts->hash_only)
printf("%s\n", hex);
else
printf("%s %s\n", hex, refname);
- if (!deref_tags)
+ if (!opts->deref_tags)
return;
if (!peel_iterated_oid(oid, &peeled)) {
- hex = find_unique_abbrev(&peeled, abbrev);
+ hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
printf("%s %s^{}\n", hex, refname);
}
}
+struct show_ref_data {
+ const struct show_one_options *show_one_opts;
+ const char **patterns;
+ int found_match;
+ int show_head;
+};
+
static int show_ref(const char *refname, const struct object_id *oid,
- int flag UNUSED, void *cbdata UNUSED)
+ int flag UNUSED, void *cbdata)
{
- if (show_head && !strcmp(refname, "HEAD"))
+ struct show_ref_data *data = cbdata;
+
+ if (data->show_head && !strcmp(refname, "HEAD"))
goto match;
- if (pattern) {
+ if (data->patterns) {
int reflen = strlen(refname);
- const char **p = pattern, *m;
+ const char **p = data->patterns, *m;
while ((m = *p++) != NULL) {
int len = strlen(m);
if (len > reflen)
@@ -70,9 +89,9 @@ static int show_ref(const char *refname, const struct object_id *oid,
}
match:
- found_match++;
+ data->found_match++;
- show_one(refname, oid);
+ show_one(data->show_one_opts, refname, oid);
return 0;
}
@@ -86,6 +105,15 @@ static int add_existing(const char *refname,
return 0;
}
+struct exclude_existing_options {
+ /*
+ * We need an explicit `enabled` field because it is perfectly valid
+ * for `pattern` to be `NULL` even if `--exclude-existing` was given.
+ */
+ int enabled;
+ const char *pattern;
+};
+
/*
* read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
* and
@@ -95,11 +123,11 @@ static int add_existing(const char *refname,
* (4) ignore if refname is a ref that exists in the local repository;
* (5) otherwise output the line.
*/
-static int exclude_existing(const char *match)
+static int cmd_show_ref__exclude_existing(const struct exclude_existing_options *opts)
{
- static struct string_list existing_refs = STRING_LIST_INIT_DUP;
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
char buf[1024];
- int matchlen = match ? strlen(match) : 0;
+ int patternlen = opts->pattern ? strlen(opts->pattern) : 0;
for_each_ref(add_existing, &existing_refs);
while (fgets(buf, sizeof(buf), stdin)) {
@@ -115,11 +143,11 @@ static int exclude_existing(const char *match)
for (ref = buf + len; buf < ref; ref--)
if (isspace(ref[-1]))
break;
- if (match) {
+ if (opts->pattern) {
int reflen = buf + len - ref;
- if (reflen < matchlen)
+ if (reflen < patternlen)
continue;
- if (strncmp(ref, match, matchlen))
+ if (strncmp(ref, opts->pattern, patternlen))
continue;
}
if (check_refname_format(ref, 0)) {
@@ -130,97 +158,172 @@ static int exclude_existing(const char *match)
printf("%s\n", buf);
}
}
+
+ string_list_clear(&existing_refs, 0);
+ return 0;
+}
+
+static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
+ const char **refs)
+{
+ if (!refs || !*refs)
+ die("--verify requires a reference");
+
+ while (*refs) {
+ struct object_id oid;
+
+ if ((starts_with(*refs, "refs/") || !strcmp(*refs, "HEAD")) &&
+ !read_ref(*refs, &oid)) {
+ show_one(show_one_opts, *refs, &oid);
+ }
+ else if (!show_one_opts->quiet)
+ die("'%s' - not a valid ref", *refs);
+ else
+ return 1;
+ refs++;
+ }
+
return 0;
}
+struct patterns_options {
+ int show_head;
+ int heads_only;
+ int tags_only;
+};
+
+static int cmd_show_ref__patterns(const struct patterns_options *opts,
+ const struct show_one_options *show_one_opts,
+ const char **patterns)
+{
+ struct show_ref_data show_ref_data = {
+ .show_one_opts = show_one_opts,
+ .show_head = opts->show_head,
+ };
+
+ if (patterns && *patterns)
+ show_ref_data.patterns = patterns;
+
+ if (opts->show_head)
+ head_ref(show_ref, &show_ref_data);
+ if (opts->heads_only || opts->tags_only) {
+ if (opts->heads_only)
+ for_each_fullref_in("refs/heads/", show_ref, &show_ref_data);
+ if (opts->tags_only)
+ for_each_fullref_in("refs/tags/", show_ref, &show_ref_data);
+ } else {
+ for_each_ref(show_ref, &show_ref_data);
+ }
+ if (!show_ref_data.found_match)
+ return 1;
+
+ return 0;
+}
+
+static int cmd_show_ref__exists(const char **refs)
+{
+ struct strbuf unused_referent = STRBUF_INIT;
+ struct object_id unused_oid;
+ unsigned int unused_type;
+ int failure_errno = 0;
+ const char *ref;
+ int ret = 0;
+
+ if (!refs || !*refs)
+ die("--exists requires a reference");
+ ref = *refs++;
+ if (*refs)
+ die("--exists requires exactly one reference");
+
+ if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
+ &unused_oid, &unused_referent, &unused_type,
+ &failure_errno)) {
+ if (failure_errno == ENOENT) {
+ error(_("reference does not exist"));
+ ret = 2;
+ } else {
+ errno = failure_errno;
+ error_errno(_("failed to look up reference"));
+ ret = 1;
+ }
+
+ goto out;
+ }
+
+out:
+ strbuf_release(&unused_referent);
+ return ret;
+}
+
static int hash_callback(const struct option *opt, const char *arg, int unset)
{
- hash_only = 1;
+ struct show_one_options *opts = opt->value;
+ struct option abbrev_opt = *opt;
+
+ opts->hash_only = 1;
/* Use full length SHA1 if no argument */
if (!arg)
return 0;
- return parse_opt_abbrev_cb(opt, arg, unset);
+
+ abbrev_opt.value = &opts->abbrev;
+ return parse_opt_abbrev_cb(&abbrev_opt, arg, unset);
}
static int exclude_existing_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct exclude_existing_options *opts = opt->value;
BUG_ON_OPT_NEG(unset);
- exclude_arg = 1;
- *(const char **)opt->value = arg;
+ opts->enabled = 1;
+ opts->pattern = arg;
return 0;
}
-static const struct option show_ref_options[] = {
- OPT_BOOL(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
- OPT_BOOL(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
- OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
- "requires exact ref path")),
- OPT_HIDDEN_BOOL('h', NULL, &show_head,
- N_("show the HEAD reference, even if it would be filtered out")),
- OPT_BOOL(0, "head", &show_head,
- N_("show the HEAD reference, even if it would be filtered out")),
- OPT_BOOL('d', "dereference", &deref_tags,
- N_("dereference tags into object IDs")),
- OPT_CALLBACK_F('s', "hash", &abbrev, N_("n"),
- N_("only show SHA1 hash using <n> digits"),
- PARSE_OPT_OPTARG, &hash_callback),
- OPT__ABBREV(&abbrev),
- OPT__QUIET(&quiet,
- N_("do not print results to stdout (useful with --verify)")),
- OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_arg,
- N_("pattern"), N_("show refs from stdin that aren't in local repository"),
- PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
- OPT_END()
-};
-
int cmd_show_ref(int argc, const char **argv, const char *prefix)
{
+ struct exclude_existing_options exclude_existing_opts = {0};
+ struct patterns_options patterns_opts = {0};
+ struct show_one_options show_one_opts = {0};
+ int verify = 0, exists = 0;
+ const struct option show_ref_options[] = {
+ OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with heads)")),
+ OPT_BOOL(0, "heads", &patterns_opts.heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
+ OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
+ "requires exact ref path")),
+ OPT_HIDDEN_BOOL('h', NULL, &patterns_opts.show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL(0, "head", &patterns_opts.show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL('d', "dereference", &show_one_opts.deref_tags,
+ N_("dereference tags into object IDs")),
+ OPT_CALLBACK_F('s', "hash", &show_one_opts, N_("n"),
+ N_("only show SHA1 hash using <n> digits"),
+ PARSE_OPT_OPTARG, &hash_callback),
+ OPT__ABBREV(&show_one_opts.abbrev),
+ OPT__QUIET(&show_one_opts.quiet,
+ N_("do not print results to stdout (useful with --verify)")),
+ OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_opts,
+ N_("pattern"), N_("show refs from stdin that aren't in local repository"),
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
+ OPT_END()
+ };
+
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, 0);
- if (exclude_arg)
- return exclude_existing(exclude_existing_arg);
-
- pattern = argv;
- if (!*pattern)
- pattern = NULL;
-
- if (verify) {
- if (!pattern)
- die("--verify requires a reference");
- while (*pattern) {
- struct object_id oid;
-
- if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
- !read_ref(*pattern, &oid)) {
- show_one(*pattern, &oid);
- }
- else if (!quiet)
- die("'%s' - not a valid ref", *pattern);
- else
- return 1;
- pattern++;
- }
- return 0;
- }
+ die_for_incompatible_opt3(exclude_existing_opts.enabled, "--exclude-existing",
+ verify, "--verify",
+ exists, "--exists");
- if (show_head)
- head_ref(show_ref, NULL);
- if (heads_only || tags_only) {
- if (heads_only)
- for_each_fullref_in("refs/heads/", show_ref, NULL);
- if (tags_only)
- for_each_fullref_in("refs/tags/", show_ref, NULL);
- } else {
- for_each_ref(show_ref, NULL);
- }
- if (!found_match) {
- if (verify && !quiet)
- die("No match");
- return 1;
- }
- return 0;
+ if (exclude_existing_opts.enabled)
+ return cmd_show_ref__exclude_existing(&exclude_existing_opts);
+ else if (verify)
+ return cmd_show_ref__verify(&show_one_opts, argv);
+ else if (exists)
+ return cmd_show_ref__exists(argv);
+ else
+ return cmd_show_ref__patterns(&patterns_opts, &show_one_opts, argv);
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 287716db68..0f52e25249 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,26 +1,26 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
#include "pathspec.h"
#include "repository.h"
-#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#include "cache-tree.h"
#include "lockfile.h"
-#include "resolve-undo.h"
#include "unpack-trees.h"
-#include "wt-status.h"
#include "quote.h"
+#include "setup.h"
#include "sparse-index.h"
#include "worktree.h"
static const char *empty_base = "";
static char const * const builtin_sparse_checkout_usage[] = {
- N_("git sparse-checkout (init|list|set|add|reapply|disable) <options>"),
+ N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]"),
NULL
};
@@ -57,6 +57,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
char *sparse_filename;
int res;
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("this worktree is not sparse"));
@@ -218,14 +219,13 @@ static int update_working_directory(struct pattern_list *pl)
o.src_index = r->index;
o.dst_index = r->index;
o.skip_sparse_checkout = 0;
- o.pl = pl;
setup_work_tree();
repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
setup_unpack_trees_porcelain(&o, "sparse-checkout");
- result = update_sparsity(&o);
+ result = update_sparsity(&o, pl);
clear_unpack_trees_porcelain(&o);
if (result == UPDATE_SPARSITY_WARNINGS)
@@ -382,13 +382,7 @@ static int set_config(enum sparse_checkout_mode mode)
return 0;
}
-static int update_modes(int *cone_mode, int *sparse_index)
-{
- int mode, record_mode;
-
- /* Determine if we need to record the mode; ensure sparse checkout on */
- record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
-
+static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
/* If not specified, use previous definition of cone mode */
if (*cone_mode == -1 && core_apply_sparse_checkout)
*cone_mode = core_sparse_checkout_cone;
@@ -396,12 +390,21 @@ static int update_modes(int *cone_mode, int *sparse_index)
/* Set cone/non-cone mode appropriately */
core_apply_sparse_checkout = 1;
if (*cone_mode == 1 || *cone_mode == -1) {
- mode = MODE_CONE_PATTERNS;
core_sparse_checkout_cone = 1;
- } else {
- mode = MODE_ALL_PATTERNS;
- core_sparse_checkout_cone = 0;
+ return MODE_CONE_PATTERNS;
}
+ core_sparse_checkout_cone = 0;
+ return MODE_ALL_PATTERNS;
+}
+
+static int update_modes(int *cone_mode, int *sparse_index)
+{
+ int mode, record_mode;
+
+ /* Determine if we need to record the mode; ensure sparse checkout on */
+ record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
+
+ mode = update_cone_mode(cone_mode);
if (record_mode && set_config(mode))
return 1;
@@ -447,6 +450,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
repo_read_index(the_repository);
init_opts.cone_mode = -1;
@@ -470,7 +474,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
return update_working_directory(NULL);
}
- if (get_oid("HEAD", &oid)) {
+ if (repo_get_oid(the_repository, "HEAD", &oid)) {
FILE *fp;
/* assume we are in a fresh repo, but update the sparse-checkout file */
@@ -544,7 +548,7 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
static void add_patterns_from_input(struct pattern_list *pl,
int argc, const char **argv,
- int use_stdin)
+ FILE *file)
{
int i;
if (core_sparse_checkout_cone) {
@@ -554,9 +558,9 @@ static void add_patterns_from_input(struct pattern_list *pl,
hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
pl->use_cone_patterns = 1;
- if (use_stdin) {
+ if (file) {
struct strbuf unquoted = STRBUF_INIT;
- while (!strbuf_getline(&line, stdin)) {
+ while (!strbuf_getline(&line, file)) {
if (line.buf[0] == '"') {
strbuf_reset(&unquoted);
if (unquote_c_style(&unquoted, line.buf, NULL))
@@ -578,10 +582,10 @@ static void add_patterns_from_input(struct pattern_list *pl,
}
}
} else {
- if (use_stdin) {
+ if (file) {
struct strbuf line = STRBUF_INIT;
- while (!strbuf_getline(&line, stdin)) {
+ while (!strbuf_getline(&line, file)) {
size_t len;
char *buf = strbuf_detach(&line, &len);
add_pattern(buf, empty_base, 0, pl, 0);
@@ -608,7 +612,8 @@ static void add_patterns_cone_mode(int argc, const char **argv,
struct pattern_list existing;
char *sparse_filename = get_sparse_checkout_filename();
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv,
+ use_stdin ? stdin : NULL);
memset(&existing, 0, sizeof(existing));
existing.use_cone_patterns = core_sparse_checkout_cone;
@@ -645,7 +650,7 @@ static void add_patterns_literal(int argc, const char **argv,
pl, NULL, 0))
die(_("unable to load existing sparse-checkout patterns"));
free(sparse_filename);
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
}
static int modify_pattern_list(int argc, const char **argv, int use_stdin,
@@ -664,7 +669,8 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
break;
case REPLACE:
- add_patterns_from_input(pl, argc, argv, use_stdin);
+ add_patterns_from_input(pl, argc, argv,
+ use_stdin ? stdin : NULL);
break;
}
@@ -759,6 +765,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("no sparse-checkout to add to"));
@@ -766,8 +773,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_add_options,
- builtin_sparse_checkout_add_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_add_usage, 0);
sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
@@ -805,6 +811,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_work_tree();
repo_read_index(the_repository);
set_opts.cone_mode = -1;
@@ -812,8 +819,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_set_options,
- builtin_sparse_checkout_set_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_set_usage, 0);
if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
return 1;
@@ -823,7 +829,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
* non-cone mode, if nothing is specified, manually select just the
* top-level directory (much as 'init' would do).
*/
- if (!core_sparse_checkout_cone && argc == 0) {
+ if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
argv = default_patterns;
argc = default_patterns_nr;
} else {
@@ -854,6 +860,7 @@ static int sparse_checkout_reapply(int argc, const char **argv,
OPT_END(),
};
+ setup_work_tree();
if (!core_apply_sparse_checkout)
die(_("must be in a sparse-checkout to reapply sparsity patterns"));
@@ -897,6 +904,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
* forcibly return to a dense checkout regardless of initial state.
*/
+ setup_work_tree();
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_disable_options,
builtin_sparse_checkout_disable_usage, 0);
@@ -922,6 +930,90 @@ static int sparse_checkout_disable(int argc, const char **argv,
return set_config(MODE_NO_PATTERNS);
}
+static char const * const builtin_sparse_checkout_check_rules_usage[] = {
+ N_("git sparse-checkout check-rules [-z] [--skip-checks]"
+ "[--[no-]cone] [--rules-file <file>]"),
+ NULL
+};
+
+static struct sparse_checkout_check_rules_opts {
+ int cone_mode;
+ int null_termination;
+ char *rules_file;
+} check_rules_opts;
+
+static int check_rules(struct pattern_list *pl, int null_terminated) {
+ struct strbuf line = STRBUF_INIT;
+ struct strbuf unquoted = STRBUF_INIT;
+ char *path;
+ int line_terminator = null_terminated ? 0 : '\n';
+ strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
+ : strbuf_getline;
+ the_repository->index->sparse_checkout_patterns = pl;
+ while (!getline_fn(&line, stdin)) {
+ path = line.buf;
+ if (!null_terminated && line.buf[0] == '"') {
+ strbuf_reset(&unquoted);
+ if (unquote_c_style(&unquoted, line.buf, NULL))
+ die(_("unable to unquote C-style string '%s'"),
+ line.buf);
+
+ path = unquoted.buf;
+ }
+
+ if (path_in_sparse_checkout(path, the_repository->index))
+ write_name_quoted(path, stdout, line_terminator);
+ }
+ strbuf_release(&line);
+ strbuf_release(&unquoted);
+
+ return 0;
+}
+
+static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix)
+{
+ static struct option builtin_sparse_checkout_check_rules_options[] = {
+ OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
+ N_("terminate input and output files by a NUL character")),
+ OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
+ N_("when used with --rules-file interpret patterns as cone mode patterns")),
+ OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
+ N_("use patterns in <file> instead of the current ones.")),
+ OPT_END(),
+ };
+
+ FILE *fp;
+ int ret;
+ struct pattern_list pl = {0};
+ char *sparse_filename;
+ check_rules_opts.cone_mode = -1;
+
+ argc = parse_options(argc, argv, prefix,
+ builtin_sparse_checkout_check_rules_options,
+ builtin_sparse_checkout_check_rules_usage, 0);
+
+ if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
+ check_rules_opts.cone_mode = 1;
+
+ update_cone_mode(&check_rules_opts.cone_mode);
+ pl.use_cone_patterns = core_sparse_checkout_cone;
+ if (check_rules_opts.rules_file) {
+ fp = xfopen(check_rules_opts.rules_file, "r");
+ add_patterns_from_input(&pl, argc, argv, fp);
+ fclose(fp);
+ } else {
+ sparse_filename = get_sparse_checkout_filename();
+ if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
+ NULL, 0))
+ die(_("unable to load existing sparse-checkout patterns"));
+ free(sparse_filename);
+ }
+
+ ret = check_rules(&pl, check_rules_opts.null_termination);
+ clear_pattern_list(&pl);
+ return ret;
+}
+
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
{
parse_opt_subcommand_fn *fn = NULL;
@@ -932,6 +1024,7 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
+ OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
OPT_END(),
};
diff --git a/builtin/stash.c b/builtin/stash.c
index 2274aae255..b2813c614c 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,6 +1,12 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "refs.h"
#include "lockfile.h"
@@ -12,81 +18,108 @@
#include "run-command.h"
#include "dir.h"
#include "entry.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "rerere.h"
#include "revision.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "log-tree.h"
#include "diffcore.h"
-#include "exec-cmd.h"
#include "reflog.h"
+#include "add-interactive.h"
#define INCLUDE_ALL_FILES 2
+#define BUILTIN_STASH_LIST_USAGE \
+ N_("git stash list [<log-options>]")
+#define BUILTIN_STASH_SHOW_USAGE \
+ N_("git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]")
+#define BUILTIN_STASH_DROP_USAGE \
+ N_("git stash drop [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_POP_USAGE \
+ N_("git stash pop [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_APPLY_USAGE \
+ N_("git stash apply [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_BRANCH_USAGE \
+ N_("git stash branch <branchname> [<stash>]")
+#define BUILTIN_STASH_STORE_USAGE \
+ N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>")
+#define BUILTIN_STASH_PUSH_USAGE \
+ N_("git stash [push [-p | --patch] [-S | --staged] [-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>...]]")
+#define BUILTIN_STASH_SAVE_USAGE \
+ N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+ " [-u | --include-untracked] [-a | --all] [<message>]")
+#define BUILTIN_STASH_CREATE_USAGE \
+ N_("git stash create [<message>]")
+#define BUILTIN_STASH_CLEAR_USAGE \
+ "git stash clear"
+
static const char * const git_stash_usage[] = {
- N_("git stash list [<options>]"),
- N_("git stash show [<options>] [<stash>]"),
- N_("git stash drop [-q|--quiet] [<stash>]"),
- N_("git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
- N_("git stash branch <branchname> [<stash>]"),
- "git stash clear",
- N_("git stash [push [-p|--patch] [-S|--staged] [-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] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_LIST_USAGE,
+ BUILTIN_STASH_SHOW_USAGE,
+ BUILTIN_STASH_DROP_USAGE,
+ BUILTIN_STASH_POP_USAGE,
+ BUILTIN_STASH_APPLY_USAGE,
+ BUILTIN_STASH_BRANCH_USAGE,
+ BUILTIN_STASH_PUSH_USAGE,
+ BUILTIN_STASH_SAVE_USAGE,
+ BUILTIN_STASH_CLEAR_USAGE,
+ BUILTIN_STASH_CREATE_USAGE,
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_list_usage[] = {
- N_("git stash list [<options>]"),
+ BUILTIN_STASH_LIST_USAGE,
NULL
};
static const char * const git_stash_show_usage[] = {
- N_("git stash show [<options>] [<stash>]"),
+ BUILTIN_STASH_SHOW_USAGE,
NULL
};
static const char * const git_stash_drop_usage[] = {
- N_("git stash drop [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_DROP_USAGE,
NULL
};
static const char * const git_stash_pop_usage[] = {
- N_("git stash pop [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_POP_USAGE,
NULL
};
static const char * const git_stash_apply_usage[] = {
- N_("git stash apply [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_APPLY_USAGE,
NULL
};
static const char * const git_stash_branch_usage[] = {
- N_("git stash branch <branchname> [<stash>]"),
+ BUILTIN_STASH_BRANCH_USAGE,
NULL
};
static const char * const git_stash_clear_usage[] = {
- "git stash clear",
+ BUILTIN_STASH_CLEAR_USAGE,
NULL
};
static const char * const git_stash_store_usage[] = {
- N_("git stash store [-m|--message <message>] [-q|--quiet] <commit>"),
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_push_usage[] = {
- N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
- " [--] [<pathspec>...]]"),
+ BUILTIN_STASH_PUSH_USAGE,
NULL
};
static const char * const git_stash_save_usage[] = {
- N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_SAVE_USAGE,
NULL
};
@@ -177,7 +210,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
revision = info->revision.buf;
- if (get_oid(revision, &info->w_commit))
+ if (repo_get_oid(the_repository, revision, &info->w_commit))
return error(_("%s is not a valid reference"), revision);
assert_stash_like(info, revision);
@@ -187,7 +220,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
end_of_rev = strchrnul(revision, '@');
strbuf_add(&symbolic, revision, end_of_rev - revision);
- ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
+ ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len,
+ &dummy, &expanded_ref, 0);
strbuf_release(&symbolic);
switch (ret) {
case 0: /* Not found, but valid ref */
@@ -207,7 +241,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
static int do_clear_stash(void)
{
struct object_id obj;
- if (get_oid(ref_stash, &obj))
+ if (repo_get_oid(the_repository, ref_stash, &obj))
return 0;
return delete_ref(NULL, ref_stash, &obj, 0);
@@ -238,11 +272,11 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
struct tree *tree;
struct lock_file lock_file = LOCK_INIT;
- read_cache_preload(NULL);
- if (refresh_cache(REFRESH_QUIET))
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL))
return -1;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
@@ -327,7 +361,7 @@ static int is_path_a_directory(const char *path)
}
static void add_diff_to_buf(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -403,7 +437,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* to the index before a merge was run) and the current index
* (reflecting the changes brought in by the merge).
*/
- diff_setup(&diff_opts);
+ repo_diff_setup(the_repository, &diff_opts);
diff_opts.flags.recursive = 1;
diff_opts.detect_rename = 0;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -431,10 +465,10 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* path, but left it out of the working tree, then clear the
* SKIP_WORKTREE bit and write it to the working tree.
*/
- if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+ if (pos >= 0 && ce_skip_worktree(the_index.cache[pos])) {
struct stat st;
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (!lstat(ce->name, &st)) {
/* Conflicting path present; relocate it */
struct strbuf new_path = STRBUF_INIT;
@@ -500,11 +534,13 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
struct tree *head, *merge, *merge_base;
struct lock_file lock = LOCK_INIT;
- read_cache_preload(NULL);
- if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL))
return -1;
- if (write_cache_as_tree(&c_tree, 0, NULL))
+ if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
+ NULL))
return error(_("cannot apply a stash in the middle of a merge"));
if (index) {
@@ -526,14 +562,15 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
return error(_("conflicts in index. "
"Try without --index."));
- discard_cache();
- read_cache();
- if (write_cache_as_tree(&index_tree, 0, NULL))
+ discard_index(&the_index);
+ repo_read_index(the_repository);
+ if (write_index_as_tree(&index_tree, &the_index,
+ get_index_file(), 0, NULL))
return error(_("could not save index tree"));
reset_head();
- discard_cache();
- read_cache();
+ discard_index(&the_index);
+ repo_read_index(the_repository);
}
}
@@ -573,7 +610,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
ret = error(_("could not write index"));
if (ret) {
- rerere(0);
+ repo_rerere(the_repository, 0);
if (index)
fprintf_ln(stderr, _("Index was not unstashed."));
@@ -803,7 +840,8 @@ static int show_stat = 1;
static int show_patch;
static int show_include_untracked;
-static int git_stash_config(const char *var, const char *value, void *cb)
+static int git_stash_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "stash.showstat")) {
show_stat = git_config_bool(var, value);
@@ -817,7 +855,7 @@ static int git_stash_config(const char *var, const char *value, void *cb)
show_include_untracked = git_config_bool(var, value);
return 0;
}
- return git_diff_basic_config(var, value, cb);
+ return git_diff_basic_config(var, value, ctx, cb);
}
static void diff_include_untracked(const struct stash_info *info, struct diff_options *diff_opt)
@@ -873,7 +911,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
- init_revisions(&rev, prefix);
+ repo_init_revisions(the_repository, &rev, prefix);
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -934,7 +972,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
}
log_tree_diff_flush(&rev);
- ret = diff_result_code(&rev.diffopt, 0);
+ ret = diff_result_code(&rev.diffopt);
cleanup:
strvec_clear(&stash_args);
free_stash_info(&info);
@@ -950,6 +988,12 @@ usage:
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
int quiet)
{
+ struct stash_info info;
+ char revision[GIT_MAX_HEXSZ];
+
+ oid_to_hex_r(revision, w_commit);
+ assert_stash_like(&info, revision);
+
if (!stash_msg)
stash_msg = "Created via \"git stash store\".";
@@ -1050,19 +1094,18 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
*/
static int check_changes_tracked_files(const struct pathspec *ps)
{
- int result;
struct rev_info rev;
struct object_id dummy;
int ret = 0;
/* No initial commit. */
- if (get_oid("HEAD", &dummy))
+ if (repo_get_oid(the_repository, "HEAD", &dummy))
return -1;
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
return -1;
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
rev.diffopt.flags.quick = 1;
@@ -1072,14 +1115,14 @@ static int check_changes_tracked_files(const struct pathspec *ps)
add_head_to_pending(&rev);
diff_setup_done(&rev.diffopt);
- result = run_diff_index(&rev, 1);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_index(&rev, DIFF_INDEX_CACHED);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
- result = run_diff_files(&rev, 0);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_files(&rev, 0);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
@@ -1113,7 +1156,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
int ret = 0;
struct strbuf untracked_msg = STRBUF_INIT;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
@@ -1141,7 +1184,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
}
done:
- discard_index(&istate);
+ release_index(&istate);
strbuf_release(&untracked_msg);
remove_path(stash_index_path.buf);
return ret;
@@ -1152,7 +1195,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
{
int ret = 0;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
0, NULL)) {
@@ -1175,7 +1218,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
}
done:
- discard_index(&istate);
+ release_index(&istate);
return ret;
}
@@ -1185,7 +1228,7 @@ 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_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf);
@@ -1205,7 +1248,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
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);
+ ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
@@ -1236,7 +1279,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
}
done:
- discard_index(&istate);
+ release_index(&istate);
remove_path(stash_index_path.buf);
return ret;
}
@@ -1247,9 +1290,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
struct rev_info rev;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
struct strbuf diff_output = STRBUF_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
set_alternate_index_output(stash_index_path.buf);
@@ -1263,17 +1306,14 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
rev.diffopt.format_callback = add_diff_to_buf;
rev.diffopt.format_callback_data = &diff_output;
- if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
ret = -1;
goto done;
}
add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
"");
- if (run_diff_index(&rev, 0)) {
- ret = -1;
- goto done;
- }
+ run_diff_index(&rev, 0);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index",
@@ -1295,7 +1335,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
}
done:
- discard_index(&istate);
+ release_index(&istate);
release_revisions(&rev);
strbuf_release(&diff_output);
remove_path(stash_index_path.buf);
@@ -1321,13 +1361,14 @@ 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) {
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL) < 0) {
ret = -1;
goto done;
}
- if (get_oid("HEAD", &info->b_commit)) {
+ if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) {
if (!quiet)
fprintf_ln(stderr, _("You do not have "
"the initial commit yet"));
@@ -1345,14 +1386,16 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
skip_prefix(branch_ref, "refs/heads/", &branch_name);
- head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
- DEFAULT_ABBREV);
+ head_short_sha1 = repo_find_unique_abbrev(the_repository,
+ &head_commit->object.oid,
+ DEFAULT_ABBREV);
strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
commit_list_insert(head_commit, &parents);
- if (write_cache_as_tree(&info->i_tree, 0, NULL) ||
+ if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
+ NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
if (!quiet)
@@ -1436,7 +1479,7 @@ done:
return ret;
}
-static int create_stash(int argc, const char **argv, const char *prefix)
+static int create_stash(int argc, const char **argv, const char *prefix UNUSED)
{
int ret;
struct strbuf stash_msg_buf = STRBUF_INIT;
@@ -1490,15 +1533,15 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
- read_cache_preload(NULL);
+ repo_read_index_preload(the_repository, NULL, 0);
if (!include_untracked && ps->nr) {
int i;
char *ps_matched = xcalloc(ps->nr, 1);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++)
- ce_path_match(&the_index, active_cache[i], ps,
+ for (i = 0; i < the_index.cache_nr; i++)
+ ce_path_match(&the_index, the_index.cache[i], ps,
ps_matched);
if (report_path_error(ps_matched, ps)) {
@@ -1510,7 +1553,8 @@ 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 (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL)) {
ret = -1;
goto done;
}
@@ -1567,7 +1611,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
}
- discard_cache();
+ discard_index(&the_index);
if (ps->nr) {
struct child_process cp_add = CHILD_PROCESS_INIT;
struct child_process cp_diff = CHILD_PROCESS_INIT;
@@ -1663,8 +1707,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
done:
+ strbuf_release(&patch);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
+ strbuf_release(&untracked_files);
return ret;
}
@@ -1699,6 +1745,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END()
};
+ int ret;
if (argc) {
force_assume = !strcmp(argv[0], "-p");
@@ -1738,8 +1785,10 @@ static int push_stash(int argc, const char **argv, const char *prefix,
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
- return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
- include_untracked, only_staged);
+ ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
+ include_untracked, only_staged);
+ clear_pathspec(&ps);
+ return ret;
}
static int push_stash_unassumed(int argc, const char **argv, const char *prefix)
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 1e34cf2beb..7b700a9fb1 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -1,8 +1,11 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "setup.h"
#include "strbuf.h"
+#include "write-or-die.h"
static void comment_lines(struct strbuf *buf)
{
@@ -10,7 +13,7 @@ static void comment_lines(struct strbuf *buf)
size_t len;
msg = strbuf_detach(buf, &len);
- strbuf_add_commented_lines(buf, msg, len);
+ strbuf_add_commented_lines(buf, msg, len, comment_line_char);
free(msg);
}
@@ -55,7 +58,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
die_errno("could not read the input");
if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
- strbuf_stripspace(&buf, mode == STRIP_COMMENTS);
+ strbuf_stripspace(&buf,
+ mode == STRIP_COMMENTS ? comment_line_char : '\0');
else
comment_lines(&buf);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0b4acb442b..fda50f2af1 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1,12 +1,20 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "repository.h"
-#include "cache.h"
#include "config.h"
#include "parse-options.h"
#include "quote.h"
+#include "path.h"
#include "pathspec.h"
+#include "preload-index.h"
#include "dir.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
#include "string-list.h"
@@ -14,11 +22,12 @@
#include "remote.h"
#include "refs.h"
#include "refspec.h"
-#include "connect.h"
#include "revision.h"
#include "diffcore.h"
#include "diff.h"
-#include "object-store.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
#include "advice.h"
#include "branch.h"
#include "list-objects-filter-options.h"
@@ -113,10 +122,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
}
/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+ const char *super_prefix)
{
- const char *super_prefix = get_super_prefix();
-
if (prefix && super_prefix) {
BUG("cannot have prefix '%s' and superprefix '%s'",
prefix, super_prefix);
@@ -181,7 +189,7 @@ static void module_list_release(struct module_list *ml)
free(ml->entries);
}
-static int module_list_compute(int argc, const char **argv,
+static int module_list_compute(const char **argv,
const char *prefix,
struct pathspec *pathspec,
struct module_list *list)
@@ -196,11 +204,11 @@ static int module_list_compute(int argc, const char **argv,
if (pathspec->nr)
ps_matched = xcalloc(pathspec->nr, 1);
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
+ for (i = 0; i < the_index.cache_nr; i++) {
+ const struct cache_entry *ce = the_index.cache[i];
if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),
0, ps_matched, 1) ||
@@ -209,8 +217,8 @@ static int module_list_compute(int argc, const char **argv,
ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
list->entries[list->nr++] = ce;
- while (i + 1 < active_nr &&
- !strcmp(ce->name, active_cache[i + 1]->name))
+ while (i + 1 < the_index.cache_nr &&
+ !strcmp(ce->name, the_index.cache[i + 1]->name))
/*
* Skip entries with the same name in different stages
* to make sure an entry is returned only once.
@@ -279,6 +287,7 @@ struct foreach_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
int quiet;
int recursive;
};
@@ -294,7 +303,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
struct child_process cp = CHILD_PROCESS_INIT;
char *displaypath;
- displaypath = get_submodule_displaypath(path, info->prefix);
+ displaypath = get_submodule_displaypath(path, info->prefix,
+ info->super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -364,10 +374,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_pushl(&cpr.args, "--super-prefix", NULL);
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
NULL);
+ strvec_pushl(&cpr.args, "--super-prefix", NULL);
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (info->quiet)
strvec_push(&cpr.args, "--quiet");
@@ -391,6 +401,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
struct option module_foreach_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
OPT_BOOL(0, "recursive", &info.recursive,
N_("recurse into nested submodules")),
@@ -405,7 +416,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_foreach_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(NULL, prefix, &pathspec, &list) < 0)
goto cleanup;
info.argc = argc;
@@ -435,11 +446,13 @@ static int starts_with_dot_dot_slash(const char *const path)
struct init_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define INIT_CB_INIT { 0 }
static void init_submodule(const char *path, const char *prefix,
+ const char *super_prefix,
unsigned int flags)
{
const struct submodule *sub;
@@ -447,7 +460,7 @@ static void init_submodule(const char *path, const char *prefix,
const char *upd;
char *url = NULL, *displaypath;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -523,7 +536,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct init_cb *info = cb_data;
- init_submodule(list_item->name, info->prefix, info->flags);
+ init_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_init(int argc, const char **argv, const char *prefix)
@@ -545,14 +559,14 @@ static int module_init(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_init_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
/*
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && git_config_get_value_multi("submodule.active"))
+ if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);
info.prefix = prefix;
@@ -570,6 +584,7 @@ cleanup:
struct status_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define STATUS_CB_INIT { 0 }
@@ -608,20 +623,22 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
static void status_submodule(const char *path, const struct object_id *ce_oid,
unsigned int ce_flags, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
char *displaypath;
struct strvec diff_files_args = STRVEC_INIT;
struct rev_info rev = REV_INFO_INIT;
- int diff_files_result;
struct strbuf buf = STRBUF_INIT;
const char *git_dir;
+ struct setup_revision_opt opt = {
+ .free_removed_argv_elements = 1,
+ };
if (!submodule_from_path(the_repository, null_oid(), path))
die(_("no submodule mapping found in .gitmodules for path '%s'"),
path);
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
print_status(flags, 'U', path, null_oid(), displaypath);
@@ -649,12 +666,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
repo_init_revisions(the_repository, &rev, NULL);
rev.abbrev = 0;
- diff_files_args.nr = setup_revisions(diff_files_args.nr,
- diff_files_args.v,
- &rev, NULL);
- diff_files_result = run_diff_files(&rev, 0);
+ setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
+ run_diff_files(&rev, 0);
- if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+ if (!diff_result_code(&rev.diffopt)) {
print_status(flags, ' ', path, ce_oid,
displaypath);
} else if (!(flags & OPT_CACHED)) {
@@ -681,10 +696,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "status",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (flags & OPT_CACHED)
strvec_push(&cpr.args, "--cached");
@@ -708,7 +723,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
struct status_cb *info = cb_data;
status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
- info->prefix, info->flags);
+ info->prefix, info->super_prefix, info->flags);
}
static int module_status(int argc, const char **argv, const char *prefix)
@@ -718,6 +733,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
int quiet = 0;
struct option module_status_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress submodule status output")),
OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -732,7 +748,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_status_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -786,6 +802,7 @@ struct summary_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
unsigned int cached: 1;
unsigned int for_status: 1;
unsigned int files: 1;
@@ -947,7 +964,8 @@ static void generate_submodule_summary(struct summary_cb *info,
dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
}
- displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+ displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+ info->super_prefix);
if (!missing_src && !missing_dst) {
struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1042,7 +1060,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
}
static void submodule_summary_callback(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -1098,7 +1116,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
strvec_pushv(&diff_args, info->argv);
git_config(git_diff_basic_config, NULL);
- init_revisions(&rev, info->prefix);
+ repo_init_revisions(the_repository, &rev, info->prefix);
rev.abbrev = 0;
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
@@ -1109,19 +1127,19 @@ static int compute_summary_module_list(struct object_id *head_oid,
if (!info->cached) {
if (diff_cmd == DIFF_INDEX)
setup_work_tree();
- if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
- perror("read_cache_preload");
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
+ perror("repo_read_index_preload");
ret = -1;
goto cleanup;
}
- } else if (read_cache() < 0) {
- perror("read_cache");
+ } else if (repo_read_index(the_repository) < 0) {
+ perror("repo_read_cache");
ret = -1;
goto cleanup;
}
if (diff_cmd == DIFF_INDEX)
- run_diff_index(&rev, info->cached);
+ run_diff_index(&rev, info->cached ? DIFF_INDEX_CACHED : 0);
else
run_diff_files(&rev, 0);
prepare_submodule_summary(info, &list);
@@ -1164,7 +1182,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
if (!summary_limit)
return 0;
- if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+ if (!repo_get_oid(the_repository, argc ? argv[0] : "HEAD", &head_oid)) {
if (argc) {
argv++;
argc--;
@@ -1177,7 +1195,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
argc--;
}
} else {
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
die(_("could not fetch a revision for HEAD"));
}
@@ -1202,12 +1220,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
struct sync_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define SYNC_CB_INIT { 0 }
static void sync_submodule(const char *path, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
const struct submodule *sub;
char *remote_key = NULL;
@@ -1238,7 +1257,7 @@ static void sync_submodule(const char *path, const char *prefix,
super_config_url = xstrdup("");
}
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if (!(flags & OPT_QUIET))
printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1275,10 +1294,11 @@ static void sync_submodule(const char *path, const char *prefix,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "sync",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
+
if (flags & OPT_QUIET)
strvec_push(&cpr.args, "--quiet");
@@ -1301,7 +1321,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct sync_cb *info = cb_data;
- sync_submodule(list_item->name, info->prefix, info->flags);
+ sync_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1312,6 +1333,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
int quiet = 0;
int recursive = 0;
struct option module_sync_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
OPT_BOOL(0, "recursive", &recursive,
N_("recurse into nested submodules")),
@@ -1326,7 +1348,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_sync_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -1364,7 +1386,7 @@ static void deinit_submodule(const char *path, const char *prefix,
if (!sub || !sub->name)
goto cleanup;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, NULL);
/* remove the submodule work tree (unless the user already did it) */
if (is_directory(path)) {
@@ -1378,8 +1400,7 @@ static void deinit_submodule(const char *path, const char *prefix,
".git file by using absorbgitdirs."),
displaypath);
- absorb_git_dir_into_superproject(path,
- ABSORB_GITDIR_RECURSE_SUBMODULES);
+ absorb_git_dir_into_superproject(path, NULL);
}
@@ -1479,7 +1500,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
if (!argc && !all)
die(_("Use '--all' if you really want to deinitialize all submodules"));
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -1883,6 +1904,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
struct update_data {
const char *prefix;
+ const char *super_prefix;
char *displaypath;
enum submodule_update_type update_default;
struct object_id suboid;
@@ -1958,7 +1980,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
enum submodule_update_type update_type;
char *key;
const struct update_data *ud = suc->update_data;
- char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+ char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+ ud->super_prefix);
struct strbuf sb = STRBUF_INIT;
int needs_cloning = 0;
int need_free_url = 0;
@@ -2001,14 +2024,17 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
- if (starts_with_dot_slash(sub->url) ||
- starts_with_dot_dot_slash(sub->url)) {
+ if (sub->url && (starts_with_dot_slash(sub->url) ||
+ starts_with_dot_dot_slash(sub->url))) {
url = resolve_relative_url(sub->url, NULL, 0);
need_free_url = 1;
} else
url = sub->url;
}
+ if (!url)
+ die(_("cannot clone submodule '%s' without a URL"), sub->name);
+
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/.git", ce->name);
needs_cloning = !file_exists(sb.buf);
@@ -2117,9 +2143,9 @@ static int update_clone_get_next_task(struct child_process *child,
return 0;
}
-static int update_clone_start_failure(struct strbuf *err,
+static int update_clone_start_failure(struct strbuf *err UNUSED,
void *suc_cb,
- void *idx_task_cb)
+ void *idx_task_cb UNUSED)
{
struct submodule_update_clone *suc = suc_cb;
@@ -2166,12 +2192,13 @@ static int update_clone_task_finished(int result,
}
static int git_update_clone_config(const char *var, const char *value,
+ const struct config_context *ctx,
void *cb)
{
int *max_jobs = cb;
if (!strcmp(var, "submodule.fetchjobs"))
- *max_jobs = parse_submodule_fetchjobs(var, value);
+ *max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi);
return 0;
}
@@ -2438,11 +2465,11 @@ static void update_data_to_args(const struct update_data *update_data,
{
enum submodule_update_type update_type = update_data->update_default;
+ strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
if (update_data->displaypath) {
strvec_push(args, "--super-prefix");
strvec_pushf(args, "%s/", update_data->displaypath);
}
- strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
if (update_data->quiet)
strvec_push(args, "--quiet");
@@ -2567,12 +2594,20 @@ static int update_submodules(struct update_data *update_data)
{
int i, ret = 0;
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "submodule",
+ .tr2_label = "parallel/update",
+
+ .processes = update_data->max_jobs,
+
+ .get_next_task = update_clone_get_next_task,
+ .start_failure = update_clone_start_failure,
+ .task_finished = update_clone_task_finished,
+ .data = &suc,
+ };
suc.update_data = update_data;
- run_processes_parallel_tr2(suc.update_data->max_jobs, update_clone_get_next_task,
- update_clone_start_failure,
- update_clone_task_finished, &suc, "submodule",
- "parallel/update");
+ run_processes_parallel(&opts);
/*
* We saved the output and put it out all at once now.
@@ -2600,7 +2635,8 @@ static int update_submodules(struct update_data *update_data)
goto fail;
update_data->displaypath = get_submodule_displaypath(
- update_data->sm_path, update_data->prefix);
+ update_data->sm_path, update_data->prefix,
+ update_data->super_prefix);
code = update_submodule(update_data);
FREE_AND_NULL(update_data->displaypath);
fail:
@@ -2626,6 +2662,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
LIST_OBJECTS_FILTER_INIT;
int ret;
struct option module_update_options[] = {
+ OPT__SUPER_PREFIX(&opt.super_prefix),
OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
OPT_BOOL(0, "init", &opt.init,
N_("initialize uninitialized submodules before update")),
@@ -2635,9 +2672,6 @@ static int module_update(int argc, const char **argv, const char *prefix)
N_("traverse submodules recursively")),
OPT_BOOL('N', "no-fetch", &opt.nofetch,
N_("don't fetch new objects from the remote site")),
- OPT_STRING(0, "prefix", &opt.prefix,
- N_("path"),
- N_("path into the working tree")),
OPT_SET_INT(0, "checkout", &opt.update_default,
N_("use the 'checkout' update strategy (default)"),
SM_UPDATE_CHECKOUT),
@@ -2693,11 +2727,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
}
opt.filter_options = &filter_options;
+ opt.prefix = prefix;
if (opt.update_default)
opt.update_strategy.type = opt.update_default;
- if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
+ if (module_list_compute(argv, prefix, &pathspec, &opt.list) < 0) {
ret = 1;
goto cleanup;
}
@@ -2709,7 +2744,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
struct init_cb info = INIT_CB_INIT;
- if (module_list_compute(argc, argv, opt.prefix,
+ if (module_list_compute(argv, opt.prefix,
&pathspec2, &list) < 0) {
module_list_release(&list);
ret = 1;
@@ -2720,10 +2755,11 @@ static int module_update(int argc, const char **argv, const char *prefix)
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && git_config_get_value_multi("submodule.active"))
+ if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);
info.prefix = opt.prefix;
+ info.super_prefix = opt.super_prefix;
if (opt.quiet)
info.flags |= OPT_QUIET;
@@ -2740,7 +2776,7 @@ cleanup:
return ret;
}
-static int push_check(int argc, const char **argv, const char *prefix)
+static int push_check(int argc, const char **argv, const char *prefix UNUSED)
{
struct remote *remote;
const char *superproject_head;
@@ -2822,13 +2858,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
int i;
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
- unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
+ const char *super_prefix = NULL;
struct option embed_gitdir_options[] = {
- OPT_STRING(0, "prefix", &prefix,
- N_("path"),
- N_("path into the working tree")),
- OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"),
- ABSORB_GITDIR_RECURSE_SUBMODULES),
+ OPT__SUPER_PREFIX(&super_prefix),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
@@ -2840,11 +2872,12 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, embed_gitdir_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
for (i = 0; i < list.nr; i++)
- absorb_git_dir_into_superproject(list.entries[i]->name, flags);
+ absorb_git_dir_into_superproject(list.entries[i]->name,
+ super_prefix);
ret = 0;
cleanup:
@@ -2853,54 +2886,9 @@ cleanup:
return ret;
}
-static int module_config(int argc, const char **argv, const char *prefix)
-{
- enum {
- CHECK_WRITEABLE = 1,
- DO_UNSET = 2
- } command = 0;
- struct option module_config_options[] = {
- OPT_CMDMODE(0, "check-writeable", &command,
- N_("check if it is safe to write to the .gitmodules file"),
- CHECK_WRITEABLE),
- OPT_CMDMODE(0, "unset", &command,
- N_("unset the config in the .gitmodules file"),
- DO_UNSET),
- OPT_END()
- };
- const char *const git_submodule_helper_usage[] = {
- N_("git submodule--helper config <name> [<value>]"),
- N_("git submodule--helper config --unset <name>"),
- "git submodule--helper config --check-writeable",
- NULL
- };
-
- argc = parse_options(argc, argv, prefix, module_config_options,
- git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0);
-
- if (argc == 1 && command == CHECK_WRITEABLE)
- return is_writing_gitmodules_ok() ? 0 : -1;
-
- /* Equivalent to ACTION_GET in builtin/config.c */
- if (argc == 2 && command != DO_UNSET)
- return print_config_from_gitmodules(the_repository, argv[1]);
-
- /* Equivalent to ACTION_SET in builtin/config.c */
- if (argc == 3 || (argc == 2 && command == DO_UNSET)) {
- const char *value = (argc == 3) ? argv[2] : NULL;
-
- if (!is_writing_gitmodules_ok())
- die(_("please make sure that the .gitmodules file is in the working tree"));
-
- return config_set_in_gitmodules_file_gently(argv[1], value);
- }
-
- usage_with_options(git_submodule_helper_usage, module_config_options);
-}
-
static int module_set_url(int argc, const char **argv, const char *prefix)
{
- int quiet = 0;
+ int quiet = 0, ret;
const char *newurl;
const char *path;
char *config_name;
@@ -2912,20 +2900,29 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
N_("git submodule set-url [--quiet] <path> <newurl>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.url", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
- config_set_in_gitmodules_file_gently(config_name, newurl);
- sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
- free(config_name);
+ config_name = xstrfmt("submodule.%s.url", sub->name);
+ ret = config_set_in_gitmodules_file_gently(config_name, newurl);
- return 0;
+ if (!ret) {
+ repo_read_gitmodules(the_repository, 0);
+ sync_submodule(sub->path, prefix, NULL, quiet ? OPT_QUIET : 0);
+ }
+
+ free(config_name);
+ return !!ret;
}
static int module_set_branch(int argc, const char **argv, const char *prefix)
@@ -2952,6 +2949,7 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -2964,7 +2962,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
if (argc != 1 || !(path = argv[0]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.branch", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
+
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
+
+ config_name = xstrfmt("submodule.%s.branch", sub->name);
ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
free(config_name);
@@ -3164,7 +3168,6 @@ static int config_submodule_in_gitmodules(const char *name, const char *var, con
static void configure_added_submodule(struct add_data *add_data)
{
char *key;
- const char *val;
struct child_process add_submod = CHILD_PROCESS_INIT;
struct child_process add_gitmodules = CHILD_PROCESS_INIT;
@@ -3209,7 +3212,7 @@ static void configure_added_submodule(struct add_data *add_data)
* is_submodule_active(), since that function needs to find
* out the value of "submodule.active" again anyway.
*/
- if (!git_config_get_string_tmp("submodule.active", &val)) {
+ if (!git_config_get("submodule.active")) {
/*
* If the submodule being added isn't already covered by the
* current configured pathspec, set the submodule's active flag
@@ -3232,7 +3235,7 @@ static void die_on_index_match(const char *path, int force)
const char *args[] = { path, NULL };
parse_pathspec(&ps, 0, PATHSPEC_PREFER_CWD, NULL, args);
- if (read_cache_preload(NULL) < 0)
+ if (repo_read_index_preload(the_repository, NULL, 0) < 0)
die(_("index file corrupt"));
if (ps.nr) {
@@ -3243,19 +3246,18 @@ static void die_on_index_match(const char *path, int force)
ensure_full_index(&the_index);
/*
- * Since there is only one pathspec, we just need
- * need to check ps_matched[0] to know if a cache
- * entry matched.
+ * Since there is only one pathspec, we just need to
+ * check ps_matched[0] to know if a cache entry matched.
*/
- for (i = 0; i < active_nr; i++) {
- ce_path_match(&the_index, active_cache[i], &ps,
+ for (i = 0; i < the_index.cache_nr; i++) {
+ ce_path_match(&the_index, the_index.cache[i], &ps,
ps_matched);
if (ps_matched[0]) {
if (!force)
die(_("'%s' already exists in the index"),
path);
- if (!S_ISGITLINK(active_cache[i]->ce_mode))
+ if (!S_ISGITLINK(the_index.cache[i]->ce_mode))
die(_("'%s' already exists in the index "
"and is not a submodule"), path);
break;
@@ -3396,48 +3398,31 @@ cleanup:
return ret;
}
-#define SUPPORT_SUPER_PREFIX (1<<0)
-
-struct cmd_struct {
- const char *cmd;
- int (*fn)(int, const char **, const char *);
- unsigned option;
-};
-
-static struct cmd_struct commands[] = {
- {"clone", module_clone, SUPPORT_SUPER_PREFIX},
- {"add", module_add, 0},
- {"update", module_update, SUPPORT_SUPER_PREFIX},
- {"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
- {"init", module_init, 0},
- {"status", module_status, SUPPORT_SUPER_PREFIX},
- {"sync", module_sync, SUPPORT_SUPER_PREFIX},
- {"deinit", module_deinit, 0},
- {"summary", module_summary, 0},
- {"push-check", push_check, 0},
- {"absorbgitdirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
- {"config", module_config, 0},
- {"set-url", module_set_url, 0},
- {"set-branch", module_set_branch, 0},
- {"create-branch", module_create_branch, 0},
-};
-
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
{
- int i;
- if (argc < 2 || !strcmp(argv[1], "-h"))
- usage("git submodule--helper <command>");
-
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- if (!strcmp(argv[1], commands[i].cmd)) {
- if (get_super_prefix() &&
- !(commands[i].option & SUPPORT_SUPER_PREFIX))
- die(_("%s doesn't support --super-prefix"),
- commands[i].cmd);
- return commands[i].fn(argc - 1, argv + 1, prefix);
- }
- }
+ parse_opt_subcommand_fn *fn = NULL;
+ const char *const usage[] = {
+ N_("git submodule--helper <command>"),
+ NULL
+ };
+ struct option options[] = {
+ OPT_SUBCOMMAND("clone", &fn, module_clone),
+ OPT_SUBCOMMAND("add", &fn, module_add),
+ OPT_SUBCOMMAND("update", &fn, module_update),
+ OPT_SUBCOMMAND("foreach", &fn, module_foreach),
+ OPT_SUBCOMMAND("init", &fn, module_init),
+ OPT_SUBCOMMAND("status", &fn, module_status),
+ OPT_SUBCOMMAND("sync", &fn, module_sync),
+ OPT_SUBCOMMAND("deinit", &fn, module_deinit),
+ OPT_SUBCOMMAND("summary", &fn, module_summary),
+ OPT_SUBCOMMAND("push-check", &fn, push_check),
+ OPT_SUBCOMMAND("absorbgitdirs", &fn, absorb_git_dirs),
+ OPT_SUBCOMMAND("set-url", &fn, module_set_url),
+ OPT_SUBCOMMAND("set-branch", &fn, module_set_branch),
+ OPT_SUBCOMMAND("create-branch", &fn, module_create_branch),
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
- die(_("'%s' is not a valid submodule--helper "
- "subcommand"), argv[1]);
+ return fn(argc, argv, prefix);
}
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 1b0f10225f..c9defe4d2e 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,19 +1,24 @@
#include "builtin.h"
#include "config.h"
-#include "cache.h"
+#include "gettext.h"
#include "refs.h"
#include "parse-options.h"
+#include "strbuf.h"
static const char * const git_symbolic_ref_usage[] = {
- N_("git symbolic-ref [<options>] <name> [<ref>]"),
- N_("git symbolic-ref -d [-q] <name>"),
+ N_("git symbolic-ref [-m <reason>] <name> <ref>"),
+ N_("git symbolic-ref [-q] [--short] [--no-recurse] <name>"),
+ N_("git symbolic-ref --delete [-q] <name>"),
NULL
};
-static int check_symref(const char *HEAD, int quiet, int shorten, int print)
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
{
- int flag;
- const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
+ int resolve_flags, flag;
+ const char *refname;
+
+ resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+ refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
if (!refname)
die("No such ref: %s", HEAD);
@@ -35,13 +40,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{
- int quiet = 0, delete = 0, shorten = 0, ret = 0;
+ int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet,
N_("suppress error message for non-symbolic (detached) refs")),
OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+ OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_END(),
};
@@ -55,7 +61,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
if (delete) {
if (argc != 1)
usage_with_options(git_symbolic_ref_usage, options);
- ret = check_symref(argv[0], 1, 0, 0);
+ ret = check_symref(argv[0], 1, 0, 0, 0);
if (ret)
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
@@ -65,7 +71,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
switch (argc) {
case 1:
- ret = check_symref(argv[0], quiet, shorten, 1);
+ ret = check_symref(argv[0], quiet, shorten, recurse, 1);
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
diff --git a/builtin/tag.c b/builtin/tag.c
index 75dece0e4f..f036cf32f5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -6,13 +6,18 @@
* Based on git-tag.sh and mktag.c by Linus Torvalds.
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "refs.h"
-#include "object-store.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
#include "tag.h"
-#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
@@ -21,13 +26,16 @@
#include "column.h"
#include "ref-filter.h"
#include "date.h"
+#include "write-or-die.h"
static const char * const git_tag_usage[] = {
- N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
- " <tagname> [<head>]"),
+ N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+ " <tagname> [<commit> | <object>]"),
N_("git tag -d <tagname>..."),
- N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]\n"
- " [--format=<format>] [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
+ N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
+ " [--points-at <object>] [--column[=<options>] | --no-column]\n"
+ " [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+ " [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
N_("git tag -v [--format=<format>] <tagname>..."),
NULL
};
@@ -39,13 +47,7 @@ static int config_sign_tag = -1; /* unspecified */
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
struct ref_format *format)
{
- struct ref_array array;
- struct strbuf output = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
- int i;
-
- memset(&array, 0, sizeof(array));
if (filter->lines == -1)
filter->lines = 0;
@@ -63,21 +65,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
if (verify_ref_format(format))
die(_("unable to parse format string"));
filter->with_commit_tag_algo = 1;
- filter_refs(&array, filter, FILTER_REFS_TAGS);
- ref_array_sort(sorting, &array);
-
- for (i = 0; i < array.nr; i++) {
- strbuf_reset(&output);
- strbuf_reset(&err);
- if (format_ref_array_item(array.items[i], format, &output, &err))
- die("%s", err.buf);
- fwrite(output.buf, 1, output.len, stdout);
- putchar('\n');
- }
+ filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format);
- strbuf_release(&err);
- strbuf_release(&output);
- ref_array_clear(&array);
free(to_free);
return 0;
@@ -109,7 +98,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
return had_error;
}
-static int collect_tags(const char *name, const char *ref,
+static int collect_tags(const char *name UNUSED, const char *ref,
const struct object_id *oid, void *cb_data)
{
struct string_list *ref_list = cb_data;
@@ -135,7 +124,7 @@ static int delete_tags(const char **argv)
if (!ref_exists(name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
- find_unique_abbrev(oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
free(oid);
}
@@ -143,7 +132,7 @@ static int delete_tags(const char **argv)
return result;
}
-static int verify_tag(const char *name, const char *ref,
+static int verify_tag(const char *name, const char *ref UNUSED,
const struct object_id *oid, void *cb_data)
{
int flags;
@@ -176,10 +165,9 @@ static const char tag_template_nocleanup[] =
"Lines starting with '%c' will be kept; you may remove them"
" yourself if you want to.\n");
-static int git_tag_config(const char *var, const char *value, void *cb)
+static int git_tag_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
- int status;
-
if (!strcmp(var, "tag.gpgsign")) {
config_sign_tag = git_config_bool(var, value);
return 0;
@@ -192,9 +180,6 @@ static int git_tag_config(const char *var, const char *value, void *cb)
return 0;
}
- status = git_gpg_config(var, value, cb);
- if (status)
- return status;
if (!strcmp(var, "tag.forcesignannotated")) {
force_sign_annotate = git_config_bool(var, value);
return 0;
@@ -202,7 +187,11 @@ static int git_tag_config(const char *var, const char *value, void *cb)
if (starts_with(var, "column."))
return git_column_config(var, value, "tag", &colopts);
- return git_color_default_config(var, value, cb);
+
+ if (git_color_config(var, value, cb) < 0)
+ return -1;
+
+ return git_default_config(var, value, ctx, cb);
}
static void write_tag_body(int fd, const struct object_id *oid)
@@ -213,7 +202,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
- orig = buf = read_object_file(oid, &type, &size);
+ orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf)
return;
if (parse_signature(buf, size, &payload, &signature)) {
@@ -264,11 +253,10 @@ static const char message_advice_nested_tag[] =
static void create_tag(const struct object_id *object, const char *object_ref,
const char *tag,
struct strbuf *buf, struct create_tag_options *opt,
- struct object_id *prev, struct object_id *result)
+ struct object_id *prev, struct object_id *result, char *path)
{
enum object_type type;
struct strbuf header = STRBUF_INIT;
- char *path = NULL;
type = oid_object_info(the_repository, object, NULL);
if (type <= OBJ_NONE)
@@ -292,7 +280,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
int fd;
/* write the template message before editing: */
- path = git_pathdup("TAG_EDITMSG");
fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (opt->message_given) {
@@ -304,9 +291,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
- strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template), tag, comment_line_char);
else
- strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template_nocleanup), tag, comment_line_char);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -320,7 +309,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
}
if (opt->cleanup_mode != CLEANUP_NONE)
- strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);
+ strbuf_stripspace(buf,
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
@@ -334,10 +324,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
path);
exit(128);
}
- if (path) {
- unlink_or_warn(path);
- free(path);
- }
}
static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
@@ -364,7 +350,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
strbuf_addstr(sb, "object of unknown type");
break;
case OBJ_COMMIT:
- if ((buf = read_object_file(oid, &type, &size))) {
+ if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -431,11 +417,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
int create_reflog = 0;
int annotate = 0, force = 0;
int cmdmode = 0, create_tag_object = 0;
- const char *msgfile = NULL, *keyid = NULL;
+ char *msgfile = NULL;
+ const char *keyid = NULL;
struct msg_arg msg = { .buf = STRBUF_INIT };
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- struct ref_filter filter;
+ struct ref_filter filter = REF_FILTER_INIT;
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -471,6 +458,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_MERGED(&filter, N_("print only tags that are merged")),
OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
+ OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty,
+ N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options),
{
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
@@ -485,13 +474,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
};
int ret = 0;
const char *only_in_list = NULL;
+ char *path = NULL;
setup_ref_filter_porcelain_msg();
+ /*
+ * Try to set sort keys from config. If config does not set any,
+ * fall back on default (refname) sorting.
+ */
git_config(git_tag_config, &sorting_options);
+ if (!sorting_options.nr)
+ string_list_append(&sorting_options, "refname");
memset(&opt, 0, sizeof(opt));
- memset(&filter, 0, sizeof(filter));
filter.lines = -1;
opt.sign = -1;
@@ -591,7 +586,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (argc > 2)
die(_("too many arguments"));
- if (get_oid(object_ref, &object))
+ if (repo_get_oid(the_repository, object_ref, &object))
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
if (strbuf_check_tag_ref(&ref, tag))
@@ -619,7 +614,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
- create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object);
+ path = git_pathdup("TAG_EDITMSG");
+ create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
+ path);
}
transaction = ref_transaction_begin(&err);
@@ -627,19 +624,30 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
- ref_transaction_commit(transaction, &err))
+ ref_transaction_commit(transaction, &err)) {
+ if (path)
+ fprintf(stderr,
+ _("The tag message has been left in %s\n"),
+ path);
die("%s", err.buf);
+ }
+ if (path) {
+ unlink_or_warn(path);
+ free(path);
+ }
ref_transaction_free(transaction);
if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
printf(_("Updated tag '%s' (was %s)\n"), tag,
- find_unique_abbrev(&prev, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV));
cleanup:
ref_sorting_release(sorting);
+ ref_filter_clear(&filter);
strbuf_release(&buf);
strbuf_release(&ref);
strbuf_release(&reflog_msg);
strbuf_release(&msg.buf);
strbuf_release(&err);
+ free(msgfile);
return ret;
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 58652229f2..c129e2bb6c 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "config.h"
-#include "object-store.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
static char *create_temp_file(struct object_id *oid)
{
@@ -10,7 +12,7 @@ static char *create_temp_file(struct object_id *oid)
unsigned long size;
int fd;
- buf = read_object_file(oid, &type, &size);
+ buf = repo_read_object_file(the_repository, oid, &type, &size);
if (!buf || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(oid));
@@ -19,16 +21,17 @@ static char *create_temp_file(struct object_id *oid)
if (write_in_full(fd, buf, size) < 0)
die_errno("unable to write temp-file");
close(fd);
+ free(buf);
return path;
}
-int cmd_unpack_file(int argc, const char **argv, const char *prefix)
+int cmd_unpack_file(int argc, const char **argv, const char *prefix UNUSED)
{
struct object_id oid;
if (argc != 2 || !strcmp(argv[1], "-h"))
- usage("git unpack-file <sha1>");
- if (get_oid(argv[1], &oid))
+ usage("git unpack-file <blob>");
+ if (repo_get_oid(the_repository, argv[1], &oid))
die("Not a valid object name %s", argv[1]);
git_config(git_default_config, NULL);
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 43789b8ef2..e0a701f2b3 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,16 +1,17 @@
#include "builtin.h"
-#include "cache.h"
#include "bulk-checkin.h"
#include "config.h"
-#include "object-store.h"
+#include "environment.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "object-store-ll.h"
#include "object.h"
#include "delta.h"
#include "pack.h"
#include "blob.h"
-#include "commit.h"
-#include "tag.h"
-#include "tree.h"
-#include "tree-walk.h"
+#include "replace-object.h"
+#include "strbuf.h"
#include "progress.h"
#include "decorate.h"
#include "fsck.h"
@@ -210,7 +211,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
* Verify its reachability and validity recursively and write it out.
*/
static int check_object(struct object *obj, enum object_type type,
- void *data, struct fsck_options *options)
+ void *data UNUSED,
+ struct fsck_options *options UNUSED)
{
struct obj_buffer *obj_buf;
@@ -442,7 +444,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
delta_data = get_data(delta_size);
if (!delta_data)
return;
- if (has_object_file(&base_oid))
+ if (repo_has_object_file(the_repository, &base_oid))
; /* Ok we have this one */
else if (resolve_against_held(nr, &base_oid,
delta_data, delta_size))
@@ -508,7 +510,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
return;
- base = read_object_file(&base_oid, &type, &base_size);
+ base = repo_read_object_file(the_repository, &base_oid, &type,
+ &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
oid_to_hex(&base_oid));
@@ -598,12 +601,13 @@ static void unpack_all(void)
die("unresolved deltas left after unpacking");
}
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
{
int i;
struct object_id oid;
+ git_hash_ctx tmp_ctx;
- read_replace_refs = 0;
+ disable_replace_refs();
git_config(git_default_config, NULL);
@@ -662,7 +666,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
the_hash_algo->init_fn(&ctx);
unpack_all();
the_hash_algo->update_fn(&ctx, buffer, offset);
- the_hash_algo->final_oid_fn(&oid, &ctx);
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &ctx);
+ the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
if (strict) {
write_rest();
if (fsck_finish(&fsck_options))
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b62249905f..7bcaa1476c 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,22 +3,32 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
-#include "cache.h"
+#define USE_THE_INDEX_VARIABLE
+#include "builtin.h"
#include "bulk-checkin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
-#include "builtin.h"
+#include "object-file.h"
#include "refs.h"
#include "resolve-undo.h"
#include "parse-options.h"
#include "pathspec.h"
#include "dir.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "split-index.h"
+#include "symlinks.h"
#include "fsmonitor.h"
+#include "write-or-die.h"
/*
* Default to not allowing changes to the list of files. The
@@ -237,16 +247,16 @@ done:
static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
- int pos = cache_name_pos(path, namelen);
+ int pos = index_name_pos(&the_index, path, namelen);
if (0 <= pos) {
- mark_fsmonitor_invalid(&the_index, active_cache[pos]);
+ mark_fsmonitor_invalid(&the_index, the_index.cache[pos]);
if (mark)
- active_cache[pos]->ce_flags |= flag;
+ the_index.cache[pos]->ce_flags |= flag;
else
- active_cache[pos]->ce_flags &= ~flag;
- active_cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
+ the_index.cache[pos]->ce_flags &= ~flag;
+ the_index.cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
cache_tree_invalidate_path(&the_index, path);
- active_cache_changed |= CE_ENTRY_CHANGED;
+ the_index.cache_changed |= CE_ENTRY_CHANGED;
return 0;
}
return -1;
@@ -256,7 +266,7 @@ static int remove_one_path(const char *path)
{
if (!allow_remove)
return error("%s: does not exist and --remove not passed", path);
- if (remove_file_from_cache(path))
+ if (remove_file_from_index(&the_index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -281,7 +291,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
- if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
+ if (old && !ce_stage(old) && !ie_match_stat(&the_index, old, st, 0))
return 0;
ce = make_empty_cache_entry(&the_index, len);
@@ -298,7 +308,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option)) {
+ if (add_index_entry(&the_index, ce, option)) {
discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
@@ -331,11 +341,11 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
static int process_directory(const char *path, int len, struct stat *st)
{
struct object_id oid;
- int pos = cache_name_pos(path, len);
+ int pos = index_name_pos(&the_index, path, len);
/* Exact match: file or existing gitlink */
if (pos >= 0) {
- const struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = the_index.cache[pos];
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
@@ -350,8 +360,8 @@ static int process_directory(const char *path, int len, struct stat *st)
/* Inexact match: is there perhaps a subdirectory match? */
pos = -pos-1;
- while (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos++];
+ while (pos < the_index.cache_nr) {
+ const struct cache_entry *ce = the_index.cache[pos++];
if (strncmp(ce->name, path, len))
break;
@@ -381,8 +391,8 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);
- pos = cache_name_pos(path, len);
- ce = pos < 0 ? NULL : active_cache[pos];
+ pos = index_name_pos(&the_index, path, len);
+ ce = pos < 0 ? NULL : the_index.cache[pos];
if (ce && ce_skip_worktree(ce)) {
/*
* working directory version is assumed "good"
@@ -390,7 +400,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
* On the other hand, removing it from index should work
*/
if (!ignore_skip_worktree_entries && allow_remove &&
- remove_file_from_cache(path))
+ remove_file_from_index(&the_index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
@@ -429,7 +439,7 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
ce->ce_flags |= CE_VALID;
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option))
+ if (add_index_entry(&the_index, ce, option))
return error("%s: cannot add to the index - missing --add option?",
path);
report("add '%s'", path);
@@ -441,11 +451,11 @@ static void chmod_path(char flip, const char *path)
int pos;
struct cache_entry *ce;
- pos = cache_name_pos(path, strlen(path));
+ pos = index_name_pos(&the_index, path, strlen(path));
if (pos < 0)
goto fail;
- ce = active_cache[pos];
- if (chmod_cache_entry(ce, flip) < 0)
+ ce = the_index.cache[pos];
+ if (chmod_index_entry(&the_index, ce, flip) < 0)
goto fail;
report("chmod %cx '%s'", flip, path);
@@ -488,7 +498,7 @@ static void update_one(const char *path)
}
if (force_remove) {
- if (remove_file_from_cache(path))
+ if (remove_file_from_index(&the_index, path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
return;
@@ -571,7 +581,7 @@ static void read_index_info(int nul_term_line)
if (!mode) {
/* mode == 0 means there is no such path -- remove */
- if (remove_file_from_cache(path_name))
+ if (remove_file_from_index(&the_index, path_name))
die("git update-index: unable to remove %s",
ptr);
}
@@ -599,9 +609,6 @@ static const char * const update_index_usage[] = {
NULL
};
-static struct object_id head_oid;
-static struct object_id merge_head_oid;
-
static struct cache_entry *read_one_ent(const char *which,
struct object_id *ent, const char *path,
int namelen, int stage)
@@ -632,84 +639,17 @@ static struct cache_entry *read_one_ent(const char *which,
static int unresolve_one(const char *path)
{
- int namelen = strlen(path);
- int pos;
- int ret = 0;
- struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
-
- /* See if there is such entry in the index. */
- pos = cache_name_pos(path, namelen);
- if (0 <= pos) {
- /* already merged */
- pos = unmerge_cache_entry_at(pos);
- if (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos];
- if (ce_stage(ce) &&
- ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen))
- return 0;
- }
- /* no resolve-undo information; fall back */
- } else {
- /* If there isn't, either it is unmerged, or
- * resolved as "removed" by mistake. We do not
- * want to do anything in the former case.
- */
- pos = -pos-1;
- if (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos];
- if (ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen)) {
- fprintf(stderr,
- "%s: skipping still unmerged path.\n",
- path);
- goto free_return;
- }
- }
- }
-
- /* Grab blobs from given path from HEAD and MERGE_HEAD,
- * stuff HEAD version in stage #2,
- * stuff MERGE_HEAD version in stage #3.
- */
- ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
- ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
-
- if (!ce_2 || !ce_3) {
- ret = -1;
- goto free_return;
- }
- if (oideq(&ce_2->oid, &ce_3->oid) &&
- ce_2->ce_mode == ce_3->ce_mode) {
- fprintf(stderr, "%s: identical in both, skipping.\n",
- path);
- goto free_return;
- }
-
- remove_file_from_cache(path);
- if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
- error("%s: cannot add our version to the index.", path);
- ret = -1;
- goto free_return;
- }
- if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
- return 0;
- error("%s: cannot add their version to the index.", path);
- ret = -1;
- free_return:
- discard_cache_entry(ce_2);
- discard_cache_entry(ce_3);
- return ret;
-}
-
-static void read_head_pointers(void)
-{
- if (read_ref("HEAD", &head_oid))
- die("No HEAD -- no initial commit yet?");
- if (read_ref("MERGE_HEAD", &merge_head_oid)) {
- fprintf(stderr, "Not in the middle of a merge.\n");
- exit(0);
- }
+ struct string_list_item *item;
+ int res = 0;
+
+ if (!the_index.resolve_undo)
+ return res;
+ item = string_list_lookup(the_index.resolve_undo, path);
+ if (!item)
+ return res; /* no resolve-undo record for the path */
+ res = unmerge_index_entry(&the_index, path, item->util, 0);
+ FREE_AND_NULL(item->util);
+ return res;
}
static int do_unresolve(int ac, const char **av,
@@ -718,11 +658,6 @@ static int do_unresolve(int ac, const char **av,
int i;
int err = 0;
- /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
- * are not doing a merge, so exit with success status.
- */
- read_head_pointers();
-
for (i = 1; i < ac; i++) {
const char *arg = av[i];
char *p = prefix_path(prefix, prefix_length, arg);
@@ -732,7 +667,7 @@ static int do_unresolve(int ac, const char **av,
return err;
}
-static int do_reupdate(int ac, const char **av,
+static int do_reupdate(const char **paths,
const char *prefix)
{
/* Read HEAD and run update-index on paths that are
@@ -741,10 +676,11 @@ static int do_reupdate(int ac, const char **av,
int pos;
int has_head = 1;
struct pathspec pathspec;
+ struct object_id head_oid;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
- prefix, av + 1);
+ prefix, paths);
if (read_ref("HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
@@ -752,8 +688,8 @@ static int do_reupdate(int ac, const char **av,
*/
has_head = 0;
redo:
- for (pos = 0; pos < active_nr; pos++) {
- const struct cache_entry *ce = active_cache[pos];
+ for (pos = 0; pos < the_index.cache_nr; pos++) {
+ const struct cache_entry *ce = the_index.cache[pos];
struct cache_entry *old = NULL;
int save_nr;
char *path;
@@ -782,12 +718,12 @@ static int do_reupdate(int ac, const char **av,
* path anymore, in which case, under 'allow_remove',
* or worse yet 'allow_replace', active_nr may decrease.
*/
- save_nr = active_nr;
+ save_nr = the_index.cache_nr;
path = xstrdup(ce->name);
update_one(path);
free(path);
discard_cache_entry(old);
- if (save_nr != active_nr)
+ if (save_nr != the_index.cache_nr)
goto redo;
}
clear_pathspec(&pathspec);
@@ -802,18 +738,19 @@ struct refresh_params {
static int refresh(struct refresh_params *o, unsigned int flag)
{
setup_work_tree();
- read_cache();
- *o->has_errors |= refresh_cache(o->flags | flag);
+ repo_read_index(the_repository);
+ *o->has_errors |= refresh_index(&the_index, o->flags | flag, NULL,
+ NULL, NULL);
if (has_racy_timestamp(&the_index)) {
/*
* Even if nothing else has changed, updating the file
* increases the chance that racy timestamps become
* non-racy, helping future run-time performance.
* We do that even in case of "errors" returned by
- * refresh_cache() as these are no actual errors.
+ * refresh_index() as these are no actual errors.
* cmd_status() does the same.
*/
- active_cache_changed |= SOMETHING_CHANGED;
+ the_index.cache_changed |= SOMETHING_CHANGED;
}
return 0;
}
@@ -845,12 +782,12 @@ static int chmod_callback(const struct option *opt,
return 0;
}
-static int resolve_undo_clear_callback(const struct option *opt,
+static int resolve_undo_clear_callback(const struct option *opt UNUSED,
const char *arg, int unset)
{
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
return 0;
}
@@ -879,7 +816,7 @@ static int parse_new_style_cacheinfo(const char *arg,
}
static enum parse_opt_result cacheinfo_callback(
- struct parse_opt_ctx_t *ctx, const struct option *opt,
+ struct parse_opt_ctx_t *ctx, const struct option *opt UNUSED,
const char *arg, int unset)
{
struct object_id oid;
@@ -951,7 +888,7 @@ static enum parse_opt_result unresolve_callback(
*has_errors = do_unresolve(ctx->argc, ctx->argv,
prefix, prefix ? strlen(prefix) : 0);
if (*has_errors)
- active_cache_changed = 0;
+ the_index.cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
@@ -970,9 +907,9 @@ static enum parse_opt_result reupdate_callback(
/* consume remaining arguments. */
setup_work_tree();
- *has_errors = do_reupdate(ctx->argc, ctx->argv, prefix);
+ *has_errors = do_reupdate(ctx->argv + 1, prefix);
if (*has_errors)
- active_cache_changed = 0;
+ the_index.cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
@@ -1079,6 +1016,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
resolve_undo_clear_callback),
OPT_INTEGER(0, "index-version", &preferred_index_format,
N_("write index in this format")),
+ OPT_SET_INT(0, "show-index-version", &preferred_index_format,
+ N_("report on-disk index format version"), -1),
OPT_BOOL(0, "split-index", &split_index,
N_("enable or disable split index")),
OPT_BOOL(0, "untracked-cache", &untracked_cache,
@@ -1109,11 +1048,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
the_repository->settings.command_requires_full_index = 0;
/* we will diagnose later if it turns out that we need to update it */
- newfd = hold_locked_index(&lock_file, 0);
+ newfd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (newfd < 0)
lock_error = errno;
- entries = read_cache();
+ entries = repo_read_index(the_repository);
if (entries < 0)
die("cache corrupted");
@@ -1171,15 +1110,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
if (preferred_index_format) {
- if (preferred_index_format < INDEX_FORMAT_LB ||
- INDEX_FORMAT_UB < preferred_index_format)
+ if (preferred_index_format < 0) {
+ printf(_("%d\n"), the_index.version);
+ } else if (preferred_index_format < INDEX_FORMAT_LB ||
+ INDEX_FORMAT_UB < preferred_index_format) {
die("index-version %d not in range: %d..%d",
preferred_index_format,
INDEX_FORMAT_LB, INDEX_FORMAT_UB);
-
- if (the_index.version != preferred_index_format)
- active_cache_changed |= SOMETHING_CHANGED;
- the_index.version = preferred_index_format;
+ } else {
+ if (the_index.version != preferred_index_format)
+ the_index.cache_changed |= SOMETHING_CHANGED;
+ report(_("index-version: was %d, set to %d"),
+ the_index.version, preferred_index_format);
+ the_index.version = preferred_index_format;
+ }
}
if (read_from_stdin) {
@@ -1290,7 +1234,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
report(_("fsmonitor disabled"));
}
- if (active_cache_changed || force_write) {
+ if (the_index.cache_changed || force_write) {
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index a84e7b47a2..61338a01ec 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -1,10 +1,12 @@
-#include "cache.h"
+#include "builtin.h"
#include "config.h"
+#include "gettext.h"
+#include "hash.h"
#include "refs.h"
-#include "builtin.h"
+#include "object-name.h"
#include "parse-options.h"
#include "quote.h"
-#include "strvec.h"
+#include "repository.h"
static const char * const git_update_ref_usage[] = {
N_("git update-ref [<options>] -d <refname> [<old-val>]"),
@@ -116,7 +118,7 @@ static int parse_next_oid(const char **next, const char *end,
(*next)++;
*next = parse_arg(*next, &arg);
if (arg.len) {
- if (get_oid(arg.buf, oid))
+ if (repo_get_oid(the_repository, arg.buf, oid))
goto invalid;
} else {
/* Without -z, an empty value means all zeros: */
@@ -134,7 +136,7 @@ static int parse_next_oid(const char **next, const char *end,
*next += arg.len;
if (arg.len) {
- if (get_oid(arg.buf, oid))
+ if (repo_get_oid(the_repository, arg.buf, oid))
goto invalid;
} else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
/* With -z, treat an empty value as all zeros: */
@@ -308,8 +310,8 @@ static void report_ok(const char *command)
fflush(stdout);
}
-static void parse_cmd_option(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
const char *rest;
if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
@@ -318,8 +320,8 @@ static void parse_cmd_option(struct ref_transaction *transaction,
die("option unknown: %s", next);
}
-static void parse_cmd_start(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
if (*next != line_termination)
die("start: extra input: %s", next);
@@ -327,7 +329,7 @@ static void parse_cmd_start(struct ref_transaction *transaction,
}
static void parse_cmd_prepare(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -338,7 +340,7 @@ static void parse_cmd_prepare(struct ref_transaction *transaction,
}
static void parse_cmd_abort(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -349,7 +351,7 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
}
static void parse_cmd_commit(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -549,7 +551,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
refname = argv[0];
value = argv[1];
oldval = argv[2];
- if (get_oid(value, &oid))
+ if (repo_get_oid(the_repository, value, &oid))
die("%s: not a valid SHA1", value);
}
@@ -560,7 +562,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* must not already exist:
*/
oidclr(&oldoid);
- else if (get_oid(oldval, &oldoid))
+ else if (repo_get_oid(the_repository, oldval, &oldoid))
die("%s: not a valid old SHA1", oldval);
}
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 880fffec58..1dc3971ede 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,10 +1,11 @@
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "parse-options.h"
+#include "server-info.h"
static const char * const update_server_info_usage[] = {
- "git update-server-info [--force]",
+ "git update-server-info [-f | --force]",
NULL
};
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 98d028dae6..1b09e5e1aa 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -1,16 +1,17 @@
/*
* Copyright (c) 2006 Franck Bui-Huu
*/
-#include "cache.h"
#include "builtin.h"
#include "archive.h"
+#include "path.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "repository.h"
#include "run-command.h"
#include "strvec.h"
static const char upload_archive_usage[] =
- "git upload-archive <repo>";
+ "git upload-archive <repository>";
static const char deadchild[] =
"git upload-archive: archiver died with error";
@@ -79,6 +80,8 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
struct child_process writer = CHILD_PROCESS_INIT;
+ BUG_ON_NON_EMPTY_PREFIX(prefix);
+
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(upload_archive_usage);
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 125af53885..9b021ef026 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -1,14 +1,17 @@
-#include "cache.h"
#include "builtin.h"
#include "exec-cmd.h"
+#include "gettext.h"
#include "pkt-line.h"
#include "parse-options.h"
+#include "path.h"
#include "protocol.h"
+#include "replace-object.h"
#include "upload-pack.h"
#include "serve.h"
static const char * const upload_pack_usage[] = {
- N_("git upload-pack [<options>] <dir>"),
+ N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+ " [--advertise-refs] <directory>"),
NULL
};
@@ -33,7 +36,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
};
packet_trace_identity("upload-pack");
- read_replace_refs = 0;
+ disable_replace_refs();
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
diff --git a/builtin/var.c b/builtin/var.c
index 491db27429..8cf7dd9e2e 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -4,84 +4,216 @@
* Copyright (C) Eric Biederman, 2005
*/
#include "builtin.h"
+#include "attr.h"
#include "config.h"
+#include "editor.h"
+#include "ident.h"
+#include "pager.h"
#include "refs.h"
+#include "path.h"
+#include "strbuf.h"
static const char var_usage[] = "git var (-l | <variable>)";
-static const char *editor(int flag)
+static char *committer(int ident_flag)
{
- const char *pgm = git_editor();
+ return xstrdup_or_null(git_committer_info(ident_flag));
+}
- if (!pgm && flag & IDENT_STRICT)
- die("Terminal is dumb, but EDITOR unset");
+static char *author(int ident_flag)
+{
+ return xstrdup_or_null(git_author_info(ident_flag));
+}
- return pgm;
+static char *editor(int ident_flag UNUSED)
+{
+ return xstrdup_or_null(git_editor());
}
-static const char *pager(int flag)
+static char *sequence_editor(int ident_flag UNUSED)
+{
+ return xstrdup_or_null(git_sequence_editor());
+}
+
+static char *pager(int ident_flag UNUSED)
{
const char *pgm = git_pager(1);
if (!pgm)
pgm = "cat";
- return pgm;
+ return xstrdup(pgm);
+}
+
+static char *default_branch(int ident_flag UNUSED)
+{
+ return xstrdup_or_null(git_default_branch_name(1));
+}
+
+static char *shell_path(int ident_flag UNUSED)
+{
+ return xstrdup(SHELL_PATH);
+}
+
+static char *git_attr_val_system(int ident_flag UNUSED)
+{
+ if (git_attr_system_is_enabled()) {
+ char *file = xstrdup(git_attr_system_file());
+ normalize_path_copy(file, file);
+ return file;
+ }
+ return NULL;
}
-static const char *default_branch(int flag)
+static char *git_attr_val_global(int ident_flag UNUSED)
{
- return git_default_branch_name(1);
+ char *file = xstrdup_or_null(git_attr_global_file());
+ if (file) {
+ normalize_path_copy(file, file);
+ return file;
+ }
+ return NULL;
+}
+
+static char *git_config_val_system(int ident_flag UNUSED)
+{
+ if (git_config_system()) {
+ char *file = git_system_config();
+ normalize_path_copy(file, file);
+ return file;
+ }
+ return NULL;
+}
+
+static char *git_config_val_global(int ident_flag UNUSED)
+{
+ struct strbuf buf = STRBUF_INIT;
+ char *user, *xdg;
+ size_t unused;
+
+ git_global_config(&user, &xdg);
+ if (xdg && *xdg) {
+ normalize_path_copy(xdg, xdg);
+ strbuf_addf(&buf, "%s\n", xdg);
+ }
+ if (user && *user) {
+ normalize_path_copy(user, user);
+ strbuf_addf(&buf, "%s\n", user);
+ }
+ free(xdg);
+ free(user);
+ strbuf_trim_trailing_newline(&buf);
+ if (buf.len == 0) {
+ strbuf_release(&buf);
+ return NULL;
+ }
+ return strbuf_detach(&buf, &unused);
}
struct git_var {
const char *name;
- const char *(*read)(int);
+ char *(*read)(int);
+ int multivalued;
};
static struct git_var git_vars[] = {
- { "GIT_COMMITTER_IDENT", git_committer_info },
- { "GIT_AUTHOR_IDENT", git_author_info },
- { "GIT_EDITOR", editor },
- { "GIT_PAGER", pager },
- { "GIT_DEFAULT_BRANCH", default_branch },
- { "", NULL },
+ {
+ .name = "GIT_COMMITTER_IDENT",
+ .read = committer,
+ },
+ {
+ .name = "GIT_AUTHOR_IDENT",
+ .read = author,
+ },
+ {
+ .name = "GIT_EDITOR",
+ .read = editor,
+ },
+ {
+ .name = "GIT_SEQUENCE_EDITOR",
+ .read = sequence_editor,
+ },
+ {
+ .name = "GIT_PAGER",
+ .read = pager,
+ },
+ {
+ .name = "GIT_DEFAULT_BRANCH",
+ .read = default_branch,
+ },
+ {
+ .name = "GIT_SHELL_PATH",
+ .read = shell_path,
+ },
+ {
+ .name = "GIT_ATTR_SYSTEM",
+ .read = git_attr_val_system,
+ },
+ {
+ .name = "GIT_ATTR_GLOBAL",
+ .read = git_attr_val_global,
+ },
+ {
+ .name = "GIT_CONFIG_SYSTEM",
+ .read = git_config_val_system,
+ },
+ {
+ .name = "GIT_CONFIG_GLOBAL",
+ .read = git_config_val_global,
+ .multivalued = 1,
+ },
+ {
+ .name = "",
+ .read = NULL,
+ },
};
static void list_vars(void)
{
struct git_var *ptr;
- const char *val;
+ char *val;
for (ptr = git_vars; ptr->read; ptr++)
- if ((val = ptr->read(0)))
- printf("%s=%s\n", ptr->name, val);
+ if ((val = ptr->read(0))) {
+ if (ptr->multivalued && *val) {
+ struct string_list list = STRING_LIST_INIT_DUP;
+ int i;
+
+ string_list_split(&list, val, '\n', -1);
+ for (i = 0; i < list.nr; i++)
+ printf("%s=%s\n", ptr->name, list.items[i].string);
+ string_list_clear(&list, 0);
+ } else {
+ printf("%s=%s\n", ptr->name, val);
+ }
+ free(val);
+ }
}
-static const char *read_var(const char *var)
+static const struct git_var *get_git_var(const char *var)
{
struct git_var *ptr;
- const char *val;
- val = NULL;
for (ptr = git_vars; ptr->read; ptr++) {
if (strcmp(var, ptr->name) == 0) {
- val = ptr->read(IDENT_STRICT);
- break;
+ return ptr;
}
}
- return val;
+ return NULL;
}
-static int show_config(const char *var, const char *value, void *cb)
+static int show_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (value)
printf("%s=%s\n", var, value);
else
printf("%s\n", var);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
-int cmd_var(int argc, const char **argv, const char *prefix)
+int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
{
- const char *val = NULL;
+ const struct git_var *git_var;
+ char *val;
+
if (argc != 2)
usage(var_usage);
@@ -91,11 +223,17 @@ int cmd_var(int argc, const char **argv, const char *prefix)
return 0;
}
git_config(git_default_config, NULL);
- val = read_var(argv[1]);
- if (!val)
+
+ git_var = get_git_var(argv[1]);
+ if (!git_var)
usage(var_usage);
+ val = git_var->read(IDENT_STRICT);
+ if (!val)
+ return 1;
+
printf("%s\n", val);
+ free(val);
return 0;
}
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 40c69a0bed..0d2b9aea2a 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -5,18 +5,17 @@
*
* Based on git-verify-tag
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
-#include "object-store.h"
+#include "config.h"
+#include "gettext.h"
+#include "object-name.h"
#include "repository.h"
#include "commit.h"
-#include "run-command.h"
#include "parse-options.h"
#include "gpg-interface.h"
static const char * const verify_commit_usage[] = {
- N_("git verify-commit [-v | --verbose] <commit>..."),
+ N_("git verify-commit [-v | --verbose] [--raw] <commit>..."),
NULL
};
@@ -39,7 +38,7 @@ static int verify_commit(const char *name, unsigned flags)
struct object_id oid;
struct object *obj;
- if (get_oid(name, &oid))
+ if (repo_get_oid(the_repository, name, &oid))
return error("commit '%s' not found.", name);
obj = parse_object(the_repository, &oid);
@@ -52,14 +51,6 @@ static int verify_commit(const char *name, unsigned flags)
return run_gpg_verify((struct commit *)obj, flags);
}
-static int git_verify_commit_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, cb);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
int cmd_verify_commit(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
@@ -70,7 +61,7 @@ int cmd_verify_commit(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(git_verify_commit_config, NULL);
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_commit_options,
verify_commit_usage, PARSE_OPT_KEEP_ARGV0);
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 05c5213594..011dddd2dc 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,8 +1,9 @@
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
+#include "strbuf.h"
#define VERIFY_PACK_VERBOSE 01
#define VERIFY_PACK_STAT_ONLY 02
@@ -56,7 +57,7 @@ static int verify_one_pack(const char *path, unsigned int flags, const char *has
}
static const char * const verify_pack_usage[] = {
- N_("git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."),
+ N_("git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."),
NULL
};
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index f45136a06b..c731e2f87b 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -5,28 +5,20 @@
*
* Based on git-verify-tag.sh
*/
-#include "cache.h"
-#include "config.h"
#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
#include "tag.h"
-#include "run-command.h"
+#include "object-name.h"
#include "parse-options.h"
#include "gpg-interface.h"
#include "ref-filter.h"
static const char * const verify_tag_usage[] = {
- N_("git verify-tag [-v | --verbose] [--format=<format>] <tag>..."),
+ N_("git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."),
NULL
};
-static int git_verify_tag_config(const char *var, const char *value, void *cb)
-{
- int status = git_gpg_config(var, value, cb);
- if (status)
- return status;
- return git_default_config(var, value, cb);
-}
-
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
@@ -39,7 +31,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
- git_config(git_verify_tag_config, NULL);
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_tag_options,
verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
@@ -60,7 +52,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
struct object_id oid;
const char *name = argv[i++];
- if (get_oid(name, &oid)) {
+ if (repo_get_oid(the_repository, name, &oid)) {
had_error = !!error("tag '%s' not found.", name);
continue;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c6710b2552..cac83a9419 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,12 +1,23 @@
-#include "cache.h"
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
#include "checkout.h"
#include "config.h"
-#include "builtin.h"
+#include "copy.h"
#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "strvec.h"
#include "branch.h"
+#include "read-cache-ll.h"
#include "refs.h"
+#include "remote.h"
+#include "repository.h"
#include "run-command.h"
#include "hook.h"
#include "sigchain.h"
@@ -15,15 +26,91 @@
#include "worktree.h"
#include "quote.h"
-static const char * const worktree_usage[] = {
- N_("git worktree add [<options>] <path> [<commit-ish>]"),
- N_("git worktree list [<options>]"),
- N_("git worktree lock [<options>] <path>"),
- N_("git worktree move <worktree> <new-path>"),
- N_("git worktree prune [<options>]"),
- N_("git worktree remove [<options>] <worktree>"),
- N_("git worktree repair [<path>...]"),
- N_("git worktree unlock <path>"),
+#define BUILTIN_WORKTREE_ADD_USAGE \
+ N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n" \
+ " [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]")
+
+#define BUILTIN_WORKTREE_LIST_USAGE \
+ N_("git worktree list [-v | --porcelain [-z]]")
+#define BUILTIN_WORKTREE_LOCK_USAGE \
+ N_("git worktree lock [--reason <string>] <worktree>")
+#define BUILTIN_WORKTREE_MOVE_USAGE \
+ N_("git worktree move <worktree> <new-path>")
+#define BUILTIN_WORKTREE_PRUNE_USAGE \
+ N_("git worktree prune [-n] [-v] [--expire <expire>]")
+#define BUILTIN_WORKTREE_REMOVE_USAGE \
+ N_("git worktree remove [-f] <worktree>")
+#define BUILTIN_WORKTREE_REPAIR_USAGE \
+ N_("git worktree repair [<path>...]")
+#define BUILTIN_WORKTREE_UNLOCK_USAGE \
+ N_("git worktree unlock <worktree>")
+
+#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \
+ _("No possible source branch, inferring '--orphan'")
+
+#define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
+ _("If you meant to create a worktree containing a new unborn branch\n" \
+ "(branch with no commits) for this repository, you can do so\n" \
+ "using the --orphan flag:\n" \
+ "\n" \
+ " git worktree add --orphan -b %s %s\n")
+
+#define WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT \
+ _("If you meant to create a worktree containing a new unborn branch\n" \
+ "(branch with no commits) for this repository, you can do so\n" \
+ "using the --orphan flag:\n" \
+ "\n" \
+ " git worktree add --orphan %s\n")
+
+static const char * const git_worktree_usage[] = {
+ BUILTIN_WORKTREE_ADD_USAGE,
+ BUILTIN_WORKTREE_LIST_USAGE,
+ BUILTIN_WORKTREE_LOCK_USAGE,
+ BUILTIN_WORKTREE_MOVE_USAGE,
+ BUILTIN_WORKTREE_PRUNE_USAGE,
+ BUILTIN_WORKTREE_REMOVE_USAGE,
+ BUILTIN_WORKTREE_REPAIR_USAGE,
+ BUILTIN_WORKTREE_UNLOCK_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_add_usage[] = {
+ BUILTIN_WORKTREE_ADD_USAGE,
+ NULL,
+};
+
+static const char * const git_worktree_list_usage[] = {
+ BUILTIN_WORKTREE_LIST_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_lock_usage[] = {
+ BUILTIN_WORKTREE_LOCK_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_move_usage[] = {
+ BUILTIN_WORKTREE_MOVE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_prune_usage[] = {
+ BUILTIN_WORKTREE_PRUNE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_remove_usage[] = {
+ BUILTIN_WORKTREE_REMOVE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_repair_usage[] = {
+ BUILTIN_WORKTREE_REPAIR_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_unlock_usage[] = {
+ BUILTIN_WORKTREE_UNLOCK_USAGE,
NULL
};
@@ -32,6 +119,7 @@ struct add_opts {
int detach;
int quiet;
int checkout;
+ int orphan;
const char *keep_locked;
};
@@ -40,14 +128,15 @@ static int verbose;
static int guess_remote;
static timestamp_t expire;
-static int git_worktree_config(const char *var, const char *value, void *cb)
+static int git_worktree_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "worktree.guessremote")) {
guess_remote = git_config_bool(var, value);
return 0;
}
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
static int delete_git_dir(const char *id)
@@ -115,7 +204,7 @@ static void prune_worktrees(void)
{
struct strbuf reason = STRBUF_INIT;
struct strbuf main_path = STRBUF_INIT;
- struct string_list kept = STRING_LIST_INIT_NODUP;
+ struct string_list kept = STRING_LIST_INIT_DUP;
DIR *dir = opendir(git_path("worktrees"));
struct dirent *d;
if (!dir)
@@ -126,14 +215,14 @@ static void prune_worktrees(void)
if (should_prune_worktree(d->d_name, &reason, &path, expire))
prune_worktree(d->d_name, reason.buf);
else if (path)
- string_list_append(&kept, path)->util = xstrdup(d->d_name);
+ string_list_append_nodup(&kept, path)->util = xstrdup(d->d_name);
}
closedir(dir);
strbuf_add_absolute_path(&main_path, get_git_common_dir());
/* massage main worktree absolute path to match 'gitdir' content */
strbuf_strip_suffix(&main_path, "/.");
- string_list_append(&kept, strbuf_detach(&main_path, NULL));
+ string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
prune_dups(&kept);
string_list_clear(&kept, 1);
@@ -153,9 +242,10 @@ static int prune(int ac, const char **av, const char *prefix)
};
expire = TIME_MAX;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_prune_usage,
+ 0);
if (ac)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_prune_usage, options);
prune_worktrees();
return 0;
}
@@ -260,7 +350,6 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (file_exists(from_file)) {
struct config_set cs = { { 0 } };
- const char *core_worktree;
int bare;
if (safe_create_leading_directories(to_file) ||
@@ -279,7 +368,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
to_file, "core.bare", NULL, "true", 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
- if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
+ if (!git_configset_get(&cs, "core.worktree") &&
git_config_set_in_file_gently(to_file,
"core.worktree", NULL))
error(_("failed to unset '%s' in '%s'"),
@@ -305,6 +394,22 @@ static int checkout_worktree(const struct add_opts *opts,
return run_command(&cp);
}
+static int make_worktree_orphan(const char * ref, const struct add_opts *opts,
+ struct strvec *child_env)
+{
+ struct strbuf symref = STRBUF_INIT;
+ struct child_process cp = CHILD_PROCESS_INIT;
+
+ validate_new_branchname(ref, &symref, 0);
+ strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL);
+ if (opts->quiet)
+ strvec_push(&cp.args, "--quiet");
+ strvec_pushv(&cp.env, child_env->v);
+ strbuf_release(&symref);
+ cp.git_cmd = 1;
+ return run_command(&cp);
+}
+
static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
@@ -334,7 +439,7 @@ static int add_worktree(const char *path, const char *refname,
die_if_checked_out(symref.buf, 0);
}
commit = lookup_commit_reference_by_name(refname);
- if (!commit)
+ if (!commit && !opts->orphan)
die(_("invalid reference: %s"), refname);
name = worktree_basename(path, &len);
@@ -416,17 +521,17 @@ static int add_worktree(const char *path, const char *refname,
* values from the current worktree into the new one, that way the
* new worktree behaves the same as this one.
*/
- if (repository_format_worktree_config)
+ if (the_repository->repository_format_worktree_config)
copy_filtered_worktree_config(sb_repo.buf);
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
- if (!is_branch)
+ if (!is_branch && commit) {
strvec_pushl(&cp.args, "update-ref", "HEAD",
oid_to_hex(&commit->object.oid), NULL);
- else {
+ } else {
strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
symref.buf, NULL);
if (opts->quiet)
@@ -438,6 +543,10 @@ static int add_worktree(const char *path, const char *refname,
if (ret)
goto done;
+ if (opts->orphan &&
+ (ret = make_worktree_orphan(refname, opts, &child_env)))
+ goto done;
+
if (opts->checkout &&
(ret = checkout_worktree(opts, &child_env)))
goto done;
@@ -457,7 +566,7 @@ done:
* Hook failure does not warrant worktree deletion, so run hook after
* is_junk is cleared, but do return appropriate code when hook fails.
*/
- if (!ret && opts->checkout) {
+ if (!ret && opts->checkout && !opts->orphan) {
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
@@ -493,7 +602,7 @@ static void print_preparing_worktree_line(int detach,
else
fprintf_ln(stderr, _("Preparing worktree (resetting branch '%s'; was at %s)"),
new_branch,
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
} else if (new_branch) {
fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
} else {
@@ -505,14 +614,131 @@ static void print_preparing_worktree_line(int detach,
else {
struct commit *commit = lookup_commit_reference_by_name(branch);
if (!commit)
- die(_("invalid reference: %s"), branch);
+ BUG(_("unreachable: invalid reference: %s"), branch);
fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
}
strbuf_release(&s);
}
}
+/**
+ * Callback to short circuit iteration over refs on the first reference
+ * corresponding to a valid oid.
+ *
+ * Returns 0 on failure and non-zero on success.
+ */
+static int first_valid_ref(const char *refname UNUSED,
+ const struct object_id *oid UNUSED,
+ int flags UNUSED,
+ void *cb_data UNUSED)
+{
+ return 1;
+}
+
+/**
+ * Verifies HEAD and determines whether there exist any valid local references.
+ *
+ * - Checks whether HEAD points to a valid reference.
+ *
+ * - Checks whether any valid local branches exist.
+ *
+ * - Emits a warning if there exist any valid branches but HEAD does not point
+ * to a valid reference.
+ *
+ * Returns 1 if any of the previous checks are true, otherwise returns 0.
+ */
+static int can_use_local_refs(const struct add_opts *opts)
+{
+ if (head_ref(first_valid_ref, NULL)) {
+ return 1;
+ } else if (for_each_branch_ref(first_valid_ref, NULL)) {
+ if (!opts->quiet) {
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf contents = STRBUF_INIT;
+
+ strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
+ strbuf_addstr(&path, "/HEAD");
+ strbuf_read_file(&contents, path.buf, 64);
+ strbuf_stripspace(&contents, 0);
+ strbuf_strip_suffix(&contents, "\n");
+
+ warning(_("HEAD points to an invalid (or orphaned) reference.\n"
+ "HEAD path: '%s'\n"
+ "HEAD contents: '%s'"),
+ path.buf, contents.buf);
+ strbuf_release(&path);
+ strbuf_release(&contents);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Reports whether the necessary flags were set and whether the repository has
+ * remote references to attempt DWIM tracking of upstream branches.
+ *
+ * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`.
+ *
+ * 2. Checks whether any valid remote branches exist.
+ *
+ * 3. Checks that there exists at least one remote and emits a warning/error
+ * if both checks 1. and 2. are false (can be bypassed with `--force`).
+ *
+ * Returns 1 if checks 1. and 2. are true, otherwise 0.
+ */
+static int can_use_remote_refs(const struct add_opts *opts)
+{
+ if (!guess_remote) {
+ return 0;
+ } else if (for_each_remote_ref(first_valid_ref, NULL)) {
+ return 1;
+ } else if (!opts->force && remote_get(NULL)) {
+ die(_("No local or remote refs exist despite at least one remote\n"
+ "present, stopping; use 'add -f' to override or fetch a remote first"));
+ }
+ return 0;
+}
+
+/**
+ * Determines whether `--orphan` should be inferred in the evaluation of
+ * `worktree add path/` or `worktree add -b branch path/` and emits an error
+ * if the supplied arguments would produce an illegal combination when the
+ * `--orphan` flag is included.
+ *
+ * `opts` and `opt_track` contain the other options & flags supplied to the
+ * command.
+ *
+ * remote determines whether to check `can_use_remote_refs()` or not. This
+ * is primarily to differentiate between the basic `add` DWIM and `add -b`.
+ *
+ * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when
+ * `--orphan` is inferred but doing so produces an illegal combination of
+ * options and flags. Additionally produces an error when remote refs are
+ * checked and the repo is in a state that looks like the user added a remote
+ * but forgot to fetch (and did not override the warning with -f).
+ */
+static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
+{
+ if (can_use_local_refs(opts)) {
+ return 0;
+ } else if (remote && can_use_remote_refs(opts)) {
+ return 0;
+ } else if (!opts->quiet) {
+ fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
+ }
+
+ if (opt_track) {
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--track");
+ } else if (!opts->checkout) {
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--no-checkout");
+ }
+ return 1;
+}
+
static const char *dwim_branch(const char *path, const char **new_branch)
{
int n;
@@ -549,6 +775,7 @@ static int add(int ac, const char **av, const char *prefix)
const char *opt_track = NULL;
const char *lock_reason = NULL;
int keep_locked = 0;
+ int used_new_branch_options;
struct option options[] = {
OPT__FORCE(&opts.force,
N_("checkout <branch> even if already checked out in other worktree"),
@@ -557,6 +784,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
N_("create or reset a branch")),
+ OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn branch")),
OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
OPT_BOOL(0, "lock", &keep_locked, N_("keep the new working tree locked")),
@@ -570,12 +798,25 @@ static int add(int ac, const char **av, const char *prefix)
N_("try to match the new branch name with a remote-tracking branch")),
OPT_END()
};
+ int ret;
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
+ if (opts.detach && opts.orphan)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--detach");
+ if (opts.orphan && opt_track)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--track");
+ if (opts.orphan && !opts.checkout)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--orphan", "--no-checkout");
+ if (opts.orphan && ac == 2)
+ die(_("option '%s' and commit-ish cannot be used together"),
+ "--orphan");
if (lock_reason && !keep_locked)
die(_("the option '%s' requires '%s'"), "--reason", "--lock");
if (lock_reason)
@@ -584,10 +825,11 @@ static int add(int ac, const char **av, const char *prefix)
opts.keep_locked = _("added with --lock");
if (ac < 1 || ac > 2)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_add_usage, options);
path = prefix_filename(prefix, av[0]);
branch = ac < 2 ? "HEAD" : av[1];
+ used_new_branch_options = new_branch || new_branch_force;
if (!strcmp(branch, "-"))
branch = "@{-1}";
@@ -604,13 +846,28 @@ static int add(int ac, const char **av, const char *prefix)
strbuf_release(&symref);
}
- if (ac < 2 && !new_branch && !opts.detach) {
+ if (opts.orphan && !new_branch) {
+ int n;
+ const char *s = worktree_basename(path, &n);
+ new_branch = xstrndup(s, n);
+ } else if (opts.orphan) {
+ // No-op
+ } else if (opts.detach) {
+ // Check HEAD
+ if (!strcmp(branch, "HEAD"))
+ can_use_local_refs(&opts);
+ } else if (ac < 2 && new_branch) {
+ // DWIM: Infer --orphan when repo has no refs.
+ opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
+ } else if (ac < 2) {
+ // DWIM: Guess branch name from path.
const char *s = dwim_branch(path, &new_branch);
if (s)
branch = s;
- }
- if (ac == 2 && !new_branch && !opts.detach) {
+ // DWIM: Infer --orphan when repo has no refs.
+ opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
+ } else if (ac == 2) {
struct object_id oid;
struct commit *commit;
const char *remote;
@@ -623,11 +880,31 @@ static int add(int ac, const char **av, const char *prefix)
branch = remote;
}
}
+
+ if (!strcmp(branch, "HEAD"))
+ can_use_local_refs(&opts);
+
+ }
+
+ if (!opts.orphan && !lookup_commit_reference_by_name(branch)) {
+ int attempt_hint = !opts.quiet && (ac < 2);
+ if (attempt_hint && used_new_branch_options) {
+ advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+ WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT,
+ new_branch, path);
+ } else if (attempt_hint) {
+ advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+ WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT, path);
+ }
+ die(_("invalid reference: %s"), branch);
}
+
if (!opts.quiet)
print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
- if (new_branch) {
+ if (opts.orphan) {
+ branch = new_branch;
+ } else if (new_branch) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
strvec_push(&cp.args, "branch");
@@ -646,9 +923,9 @@ static int add(int ac, const char **av, const char *prefix)
die(_("--[no-]track can only be used if a new branch is created"));
}
- UNLEAK(path);
- UNLEAK(opts);
- return add_worktree(path, branch, &opts);
+ ret = add_worktree(path, branch, &opts);
+ free(path);
+ return ret;
}
static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
@@ -696,7 +973,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_addstr(&sb, "(bare)");
else {
strbuf_addf(&sb, "%-*s ", abbrev_len,
- find_unique_abbrev(&wt->head_oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &wt->head_oid, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
@@ -733,7 +1010,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
if (path_len > *maxlen)
*maxlen = path_len;
- sha1_len = strlen(find_unique_abbrev(&wt[i]->head_oid, *abbrev));
+ sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
@@ -772,9 +1049,9 @@ static int list(int ac, const char **av, const char *prefix)
};
expire = TIME_MAX;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_list_usage, 0);
if (ac)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_list_usage, options);
else if (verbose && porcelain)
die(_("options '%s' and '%s' cannot be used together"), "--verbose", "--porcelain");
else if (!line_terminator && !porcelain)
@@ -811,9 +1088,9 @@ static int lock_worktree(int ac, const char **av, const char *prefix)
};
struct worktree **worktrees, *wt;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_lock_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_lock_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -844,9 +1121,9 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
struct worktree **worktrees, *wt;
int ret;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_unlock_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_unlock_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -863,7 +1140,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
static void validate_no_submodules(const struct worktree *wt)
{
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
@@ -914,9 +1191,10 @@ static int move_worktree(int ac, const char **av, const char *prefix)
const char *reason = NULL;
char *path;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_move_usage,
+ 0);
if (ac != 2)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_move_usage, options);
path = prefix_filename(prefix, av[1]);
strbuf_addstr(&dst, path);
@@ -1042,9 +1320,9 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
const char *reason = NULL;
int ret = 0;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_remove_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_remove_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -1102,7 +1380,7 @@ static int repair(int ac, const char **av, const char *prefix)
};
int rc = 0;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0);
p = ac > 0 ? av : self;
for (; *p; p++)
repair_worktree_at_path(*p, report_repair, &rc);
@@ -1130,6 +1408,10 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
if (!prefix)
prefix = "";
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
return fn(ac, av, prefix);
}
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 45d61707e7..66e83d0ecb 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,13 +3,16 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
-#include "cache.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
+#include "repository.h"
static const char * const write_tree_usage[] = {
N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
@@ -38,7 +41,11 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
write_tree_usage, 0);
- ret = write_cache_as_tree(&oid, flags, tree_prefix);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
+ ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
+ tree_prefix);
switch (ret) {
case 0:
printf("%s\n", oid_to_hex(&oid));