die_errno(_("could not read '%s'"), am_path(state, file));
}
-/**
- * Take a series of KEY='VALUE' lines where VALUE part is
- * sq-quoted, and append <KEY, VALUE> at the end of the string list
- */
-static int parse_key_value_squoted(char *buf, struct string_list *list)
-{
- while (*buf) {
- struct string_list_item *item;
- char *np;
- char *cp = strchr(buf, '=');
- if (!cp)
- return -1;
- np = strchrnul(cp, '\n');
- *cp++ = '\0';
- item = string_list_append(list, buf);
-
- buf = np + (*np == '\n');
- *np = '\0';
- cp = sq_dequote(cp);
- if (!cp)
- return -1;
- item->util = xstrdup(cp);
- }
- return 0;
-}
-
/**
* Reads and parses the state directory's "author-script" file, and sets
* state->author_name, state->author_email and state->author_date accordingly.
* script, and thus if the file differs from what this function expects, it is
* better to bail out than to do something that the user does not expect.
*/
-static int read_author_script(struct am_state *state)
+static int read_am_author_script(struct am_state *state)
{
const char *filename = am_path(state, "author-script");
- struct strbuf buf = STRBUF_INIT;
- struct string_list kv = STRING_LIST_INIT_DUP;
- int retval = -1; /* assume failure */
- int fd;
assert(!state->author_name);
assert(!state->author_email);
assert(!state->author_date);
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
- die_errno(_("could not open '%s' for reading"), filename);
- }
- strbuf_read(&buf, fd, 0);
- close(fd);
- if (parse_key_value_squoted(buf.buf, &kv))
- goto finish;
-
- if (kv.nr != 3 ||
- strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
- strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
- strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
- goto finish;
- state->author_name = kv.items[0].util;
- state->author_email = kv.items[1].util;
- state->author_date = kv.items[2].util;
- retval = 0;
-finish:
- string_list_clear(&kv, !!retval);
- strbuf_release(&buf);
- return retval;
+ return read_author_script(filename, &state->author_name,
+ &state->author_email, &state->author_date, 1);
}
/**
BUG("state file 'last' does not exist");
state->last = strtol(sb.buf, NULL, 10);
- if (read_author_script(state) < 0)
+ if (read_am_author_script(state) < 0)
die(_("could not parse author script"));
read_commit_msg(state);
if (merge_tree(remote_tree))
return -1;
- remove_branch_state();
+ remove_branch_state(the_repository);
return 0;
}
static void am_rerere_clear(void)
{
struct string_list merge_rr = STRING_LIST_INIT_DUP;
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
}
{
int *opt_value = opt->value;
- if (!strcmp(arg, "mbox"))
+ if (unset)
+ *opt_value = PATCH_FORMAT_UNKNOWN;
+ else if (!strcmp(arg, "mbox"))
*opt_value = PATCH_FORMAT_MBOX;
else if (!strcmp(arg, "stgit"))
*opt_value = PATCH_FORMAT_STGIT;
static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
{
const char **value = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
if (arg != NULL && *arg == '=')
arg = arg + 1;
static void status_init_config(struct wt_status *s, config_fn_t fn)
{
- wt_status_prepare(s);
+ wt_status_prepare(the_repository, s);
init_diff_ui_defaults();
git_config(fn, s);
determine_whence(s);
if (ignore_submodule_arg &&
!strcmp(ignore_submodule_arg, "all"))
flags.ignore_submodules = 1;
- committable = index_differs_from(parent, &flags, 1);
+ committable = index_differs_from(the_repository,
+ parent, &flags, 1);
}
}
strbuf_release(&committer_ident);
OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
{ OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
N_("n"), N_("detect renames, optionally set similarity index"),
- PARSE_OPT_OPTARG, opt_parse_rename_score },
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score },
OPT_END(),
};
if (status_format != STATUS_FORMAT_PORCELAIN &&
status_format != STATUS_FORMAT_PORCELAIN_V2)
progress_flag = REFRESH_PROGRESS;
- read_index_preload(&the_index, &s.pathspec, progress_flag);
+ read_index(&the_index);
refresh_index(&the_index,
REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
&s.pathspec, NULL, NULL);
flags |= SUMMARY_INITIAL_COMMIT;
if (author_date_is_interesting())
flags |= SUMMARY_SHOW_AUTHOR_DATE;
- print_commit_summary(prefix, &oid, flags);
+ print_commit_summary(the_repository, prefix,
+ &oid, flags);
}
UNLEAK(err);
#include "packfile.h"
#include "object-store.h"
#include "run-command.h"
+#include "worktree.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
static int keep_cache_objects;
static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
-static struct object_id head_oid;
-static const char *head_points_at;
static int errors_found;
static int write_lost_and_found;
static int verbose;
if (obj->type == OBJ_TREE)
free_tree_buffer((struct tree *)obj);
if (obj->type == OBJ_COMMIT)
- free_commit_buffer((struct commit *)obj);
+ free_commit_buffer(the_repository->parsed_objects,
+ (struct commit *)obj);
return err;
}
static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
int flag, void *cb_data)
{
- for_each_reflog_ent(logname, fsck_handle_reflog_ent, (void *)logname);
+ struct strbuf refname = STRBUF_INIT;
+
+ strbuf_worktree_ref(cb_data, &refname, logname);
+ for_each_reflog_ent(refname.buf, fsck_handle_reflog_ent, refname.buf);
+ strbuf_release(&refname);
return 0;
}
return 0;
}
+static int fsck_head_link(const char *head_ref_name,
+ const char **head_points_at,
+ struct object_id *head_oid);
+
static void get_default_heads(void)
{
- if (head_points_at && !is_null_oid(&head_oid))
- fsck_handle_ref("HEAD", &head_oid, 0, NULL);
+ struct worktree **worktrees, **p;
+ const char *head_points_at;
+ struct object_id head_oid;
+
for_each_rawref(fsck_handle_ref, NULL);
- if (include_reflogs)
- for_each_reflog(fsck_handle_reflog, NULL);
+
+ worktrees = get_worktrees(0);
+ for (p = worktrees; *p; p++) {
+ struct worktree *wt = *p;
+ struct strbuf ref = STRBUF_INIT;
+
+ strbuf_worktree_ref(wt, &ref, "HEAD");
+ fsck_head_link(ref.buf, &head_points_at, &head_oid);
+ if (head_points_at && !is_null_oid(&head_oid))
+ fsck_handle_ref(ref.buf, &head_oid, 0, NULL);
+ strbuf_release(&ref);
+
+ if (include_reflogs)
+ refs_for_each_reflog(get_worktree_ref_store(wt),
+ fsck_handle_reflog, wt);
+ }
+ free_worktrees(worktrees);
/*
* Not having any default heads isn't really fatal, but
stop_progress(&progress);
}
-static int fsck_head_link(void)
+static int fsck_head_link(const char *head_ref_name,
+ const char **head_points_at,
+ struct object_id *head_oid)
{
int null_is_error = 0;
if (verbose)
- fprintf(stderr, "Checking HEAD link\n");
+ fprintf(stderr, "Checking %s link\n", head_ref_name);
- head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
- if (!head_points_at) {
+ *head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL);
+ if (!*head_points_at) {
errors_found |= ERROR_REFS;
- return error("Invalid HEAD");
+ return error("Invalid %s", head_ref_name);
}
- if (!strcmp(head_points_at, "HEAD"))
+ if (!strcmp(*head_points_at, head_ref_name))
/* detached HEAD */
null_is_error = 1;
- else if (!starts_with(head_points_at, "refs/heads/")) {
+ else if (!starts_with(*head_points_at, "refs/heads/")) {
errors_found |= ERROR_REFS;
- return error("HEAD points to something strange (%s)",
- head_points_at);
+ return error("%s points to something strange (%s)",
+ head_ref_name, *head_points_at);
}
- if (is_null_oid(&head_oid)) {
+ if (is_null_oid(head_oid)) {
if (null_is_error) {
errors_found |= ERROR_REFS;
- return error("HEAD: detached HEAD points at nothing");
+ return error("%s: detached HEAD points at nothing",
+ head_ref_name);
}
- fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n",
- head_points_at + 11);
+ fprintf(stderr, "notice: %s points to an unborn branch (%s)\n",
+ head_ref_name, *head_points_at + 11);
}
return 0;
}
git_config(fsck_config, NULL);
- fsck_head_link();
if (connectivity_only) {
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
for (p = get_all_packs(the_repository); p;
p = p->next) {
/* verify gives error messages itself */
- if (verify_pack(p, fsck_obj_buffer,
+ if (verify_pack(the_repository,
+ p, fsck_obj_buffer,
progress, count))
errors_found |= ERROR_PACK;
count += p->num_objects;
static int option_parse_n(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
show_diffstat = unset;
return 0;
}
filename = git_path_merge_msg(the_repository);
fp = xfopen(filename, "a");
- append_conflicts_hint(&msgbuf);
+ append_conflicts_hint(&the_index, &msgbuf);
fputs(msgbuf.buf, fp);
strbuf_release(&msgbuf);
fclose(fp);
die(_("%s - not something we can merge"), argv[0]);
if (remoteheads->next)
die(_("Can merge only exactly one commit into empty head"));
+
+ if (verify_signatures)
+ verify_merge_signature(remoteheads->item, verbosity);
+
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid, 0);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
if (verify_signatures) {
for (p = remoteheads; p; p = p->next) {
- struct commit *commit = p->item;
- char hex[GIT_MAX_HEXSZ + 1];
- struct signature_check signature_check;
- memset(&signature_check, 0, sizeof(signature_check));
-
- check_commit_signature(commit, &signature_check);
-
- find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
- switch (signature_check.result) {
- case 'G':
- break;
- case 'U':
- die(_("Commit %s has an untrusted GPG signature, "
- "allegedly by %s."), hex, signature_check.signer);
- case 'B':
- die(_("Commit %s has a bad GPG signature "
- "allegedly by %s."), hex, signature_check.signer);
- default: /* 'N' */
- die(_("Commit %s does not have a GPG signature."), hex);
- }
- if (verbosity >= 0 && signature_check.result == 'G')
- printf(_("Commit %s has a good GPG signature by %s\n"),
- hex, signature_check.signer);
-
- signature_check_clear(&signature_check);
+ verify_merge_signature(p->item, verbosity);
}
}
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
strbuf_grow(&d->buf, strlen(arg) + 2);
if (d->buf.len)
strbuf_addch(&d->buf, '\n');
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (d->buf.len)
strbuf_addch(&d->buf, '\n');
if (!strcmp(arg, "-")) {
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))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_object_file(&object, &type, &len))) {
- free(buf);
+ if (!(buf = read_object_file(&object, &type, &len)))
die(_("failed to read object '%s'."), arg);
- }
if (type != OBJ_BLOB) {
free(buf);
die(_("cannot read note data from non-blob object '%s'."), arg);
static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
d->use_editor = 1;
return parse_reuse_arg(opt, arg, unset);
}
usage_with_options(git_notes_merge_usage, options);
}
- init_notes_merge_options(&o);
+ init_notes_merge_options(the_repository, &o);
o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;
if (do_abort)
return 0;
}
-#ifndef NO_PTHREADS
-
/* Protect access to object database */
static pthread_mutex_t read_mutex;
#define read_lock() pthread_mutex_lock(&read_mutex)
* ahead in the list because they can be stolen and would need
* progress_mutex for protection.
*/
-#else
-
-#define read_lock() (void)0
-#define read_unlock() (void)0
-#define cache_lock() (void)0
-#define cache_unlock() (void)0
-#define progress_lock() (void)0
-#define progress_unlock() (void)0
-
-#endif
/*
* Return the size of the object without doing any delta
die(_("object %s cannot be read"),
oid_to_hex(&trg_entry->idx.oid));
if (sz != trg_size)
- die(_("object %s inconsistent object length (%lu vs %lu)"),
- oid_to_hex(&trg_entry->idx.oid), sz,
- trg_size);
+ die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"),
+ oid_to_hex(&trg_entry->idx.oid), (uintmax_t)sz,
+ (uintmax_t)trg_size);
*mem_usage += sz;
}
if (!src->data) {
oid_to_hex(&src_entry->idx.oid));
}
if (sz != src_size)
- die(_("object %s inconsistent object length (%lu vs %lu)"),
- oid_to_hex(&src_entry->idx.oid), sz,
- src_size);
+ die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"),
+ oid_to_hex(&src_entry->idx.oid), (uintmax_t)sz,
+ (uintmax_t)src_size);
*mem_usage += sz;
}
if (!src->index) {
free(array);
}
-#ifndef NO_PTHREADS
-
static void try_to_free_from_threads(size_t size)
{
read_lock();
free(p);
}
-#else
-#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
-#endif
-
static void add_tag_chain(const struct object_id *oid)
{
struct tag *tag;
unsigned n;
if (use_delta_islands)
- resolve_tree_islands(progress, &to_pack);
+ resolve_tree_islands(the_repository, progress, &to_pack);
get_object_details();
if (delta_search_threads < 0)
die(_("invalid number of threads specified (%d)"),
delta_search_threads);
-#ifdef NO_PTHREADS
- if (delta_search_threads != 1) {
+ if (!HAVE_THREADS && delta_search_threads != 1) {
warning(_("no threads support, ignoring %s"), k);
delta_search_threads = 0;
}
-#endif
return 0;
}
if (!strcmp(k, "pack.indexversion")) {
if (use_delta_islands) {
const char *p;
- unsigned depth = 0;
+ unsigned depth;
struct object_entry *ent;
+ /* the empty string is a root tree, which is depth 0 */
+ depth = *name ? 1 : 0;
for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
depth++;
struct rev_info revs;
char line[1000];
int flags = 0;
+ int save_warning;
repo_init_revisions(the_repository, &revs, NULL);
save_commit_buffer = 0;
/* make sure shallows are read */
is_repository_shallow(the_repository);
+ save_warning = warn_on_object_refname_ambiguity;
+ warn_on_object_refname_ambiguity = 0;
+
while (fgets(line, sizeof(line), stdin) != NULL) {
int len = strlen(line);
if (len && line[len - 1] == '\n')
die(_("bad revision '%s'"), line);
}
+ warn_on_object_refname_ambiguity = save_warning;
+
if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
return;
if (use_delta_islands)
- load_delta_islands();
+ load_delta_islands(the_repository);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
{
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)
die(_("unsupported index version %s"), val);
N_("similar to --all-progress when progress meter is shown")),
{ OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
- 0, option_parse_index_version },
+ PARSE_OPT_NONEG, option_parse_index_version },
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();
-#ifdef NO_PTHREADS
- if (delta_search_threads != 1)
+ if (!HAVE_THREADS && delta_search_threads != 1)
warning(_("no threads support, ignoring --threads"));
-#endif
if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
}
}
- prepare_packing_data(&to_pack);
+ prepare_packing_data(the_repository, &to_pack);
if (progress)
progress_state = start_progress(_("Enumerating objects"), 0);
static int pull_into_void(const struct object_id *merge_head,
const struct object_id *curr_head)
{
+ if (opt_verify_signatures) {
+ struct commit *commit;
+
+ commit = lookup_commit(the_repository, merge_head);
+ if (!commit)
+ die(_("unable to access commit %s"),
+ oid_to_hex(merge_head));
+
+ verify_merge_signature(commit, opt_verbosity);
+ }
+
/*
* Two-way merge: we treat the index as based on an empty tree,
* and try to fast-forward to HEAD. This ensures we will not lose
die(_("Updating an unborn branch with changes added to the index."));
if (!autostash)
- require_clean_work_tree(N_("pull with rebase"),
+ require_clean_work_tree(the_repository,
+ N_("pull with rebase"),
_("please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
"\n"
"To push to the branch of the same name on the remote, use\n"
"\n"
- " git push %s %s\n"
+ " git push %s HEAD\n"
"%s"),
remote->name, short_upstream,
- remote->name, branch->name, advice_maybe);
+ remote->name, advice_maybe);
}
static const char message_detached_head_die[] =
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
- err = transport_push(transport, rs, flags, &reject_reasons);
+ err = transport_push(the_repository, transport,
+ rs, flags, &reject_reasons);
if (err != 0) {
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
error(_("failed to push some refs to '%s'"), transport->url);
static int index_output_cb(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_NEG(unset);
set_alternate_index_output(arg);
return 0;
}
struct dir_struct *dir;
struct unpack_trees_options *opts;
+ BUG_ON_OPT_NEG(unset);
+
opts = (struct unpack_trees_options *)opt->value;
if (opts->dir)
* what came from the tree.
*/
if (nr_trees == 1 && !opts.prefix)
- prime_cache_tree(&the_index, trees[0]);
+ prime_cache_tree(the_repository,
+ the_repository->index,
+ trees[0]);
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("unable to write new index file");
#include "revision.h"
#include "commit-reach.h"
#include "rerere.h"
+#include "branch.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf out = STRBUF_INIT;
- int ret;
+ int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
+
+ if (env != -1)
+ return env;
argv_array_pushl(&cp.args,
"config", "--bool", "rebase.usebuiltin", NULL);
REBASE_FORCE = 1<<3,
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
} flags;
- struct strbuf git_am_opt;
+ struct argv_array git_am_opts;
const char *action;
int signoff;
int allow_rerere_autoupdate;
static int run_specific_rebase(struct rebase_options *opts)
{
const char *argv[] = { NULL, NULL };
- struct strbuf script_snippet = STRBUF_INIT;
+ struct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT;
int status;
const char *backend, *backend_func;
oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
add_var(&script_snippet, "GIT_QUIET",
opts->flags & REBASE_NO_QUIET ? "" : "t");
- add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
+ sq_quote_argv_pretty(&buf, opts->git_am_opts.argv);
+ add_var(&script_snippet, "git_am_opt", buf.buf);
+ strbuf_release(&buf);
add_var(&script_snippet, "verbose",
opts->flags & REBASE_VERBOSE ? "t" : "");
add_var(&script_snippet, "diffstat",
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
+#define RESET_HEAD_DETACH (1<<0)
+#define RESET_HEAD_HARD (1<<1)
+
static int reset_head(struct object_id *oid, const char *action,
- const char *switch_to_branch, int detach_head,
+ const char *switch_to_branch, unsigned flags,
const char *reflog_orig_head, const char *reflog_head)
{
+ unsigned detach_head = flags & RESET_HEAD_DETACH;
+ unsigned reset_hard = flags & RESET_HEAD_HARD;
struct object_id head_oid;
- struct tree_desc desc;
+ struct tree_desc desc[2] = { { NULL }, { NULL } };
struct lock_file lock = LOCK_INIT;
struct unpack_trees_options unpack_tree_opts;
struct tree *tree;
size_t prefix_len;
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
- int ret = 0;
+ int ret = 0, nr = 0;
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
- if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
- return -1;
+ if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
+ ret = -1;
+ goto leave_reset_head;
+ }
- if (!oid) {
- if (get_oid("HEAD", &head_oid)) {
- rollback_lock_file(&lock);
- return error(_("could not determine HEAD revision"));
- }
- oid = &head_oid;
+ if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
+ ret = error(_("could not determine HEAD revision"));
+ goto leave_reset_head;
}
+ if (!oid)
+ oid = &head_oid;
+
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, action);
unpack_tree_opts.head_idx = 1;
unpack_tree_opts.src_index = the_repository->index;
unpack_tree_opts.dst_index = the_repository->index;
- unpack_tree_opts.fn = oneway_merge;
+ unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
if (!detach_head)
unpack_tree_opts.reset = 1;
if (read_index_unmerged(the_repository->index) < 0) {
- rollback_lock_file(&lock);
- return error(_("could not read index"));
+ ret = error(_("could not read index"));
+ goto leave_reset_head;
}
- if (!fill_tree_descriptor(&desc, oid)) {
- error(_("failed to find tree of %s"), oid_to_hex(oid));
- rollback_lock_file(&lock);
- free((void *)desc.buffer);
- return -1;
+ if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) {
+ ret = error(_("failed to find tree of %s"),
+ oid_to_hex(&head_oid));
+ goto leave_reset_head;
}
- if (unpack_trees(1, &desc, &unpack_tree_opts)) {
- rollback_lock_file(&lock);
- free((void *)desc.buffer);
- return -1;
+ if (!fill_tree_descriptor(&desc[nr++], oid)) {
+ ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
+ goto leave_reset_head;
+ }
+
+ if (unpack_trees(nr, desc, &unpack_tree_opts)) {
+ ret = -1;
+ goto leave_reset_head;
}
tree = parse_tree_indirect(oid);
- prime_cache_tree(the_repository->index, tree);
+ prime_cache_tree(the_repository, the_repository->index, tree);
- if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)
+ if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
ret = error(_("could not write index"));
- free((void *)desc.buffer);
-
- if (ret)
- return ret;
+ goto leave_reset_head;
+ }
reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
reflog_head = msg.buf;
}
if (!switch_to_branch)
- ret = update_ref(reflog_head, "HEAD", oid, orig, REF_NO_DEREF,
+ ret = update_ref(reflog_head, "HEAD", oid, orig,
+ detach_head ? REF_NO_DEREF : 0,
UPDATE_REFS_MSG_ON_ERR);
else {
ret = create_symref("HEAD", switch_to_branch, msg.buf);
UPDATE_REFS_MSG_ON_ERR);
}
+leave_reset_head:
strbuf_release(&msg);
+ rollback_lock_file(&lock);
+ while (nr)
+ free((void *)desc[--nr].buffer);
return ret;
}
{
struct rebase_options *opts = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
if (!is_interactive(opts))
opts->type = REBASE_MERGE;
{
struct rebase_options *opts = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
opts->type = REBASE_INTERACTIVE;
opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
exit(1);
}
+static void set_reflog_action(struct rebase_options *options)
+{
+ const char *env;
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!is_interactive(options))
+ return;
+
+ env = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
+ if (env && strcmp("rebase", env))
+ return; /* only override it if it is "rebase" */
+
+ strbuf_addf(&buf, "rebase -i (%s)", options->action);
+ setenv(GIT_REFLOG_ACTION_ENVIRONMENT, buf.buf, 1);
+ strbuf_release(&buf);
+}
+
int cmd_rebase(int argc, const char **argv, const char *prefix)
{
struct rebase_options options = {
.type = REBASE_UNSPECIFIED,
.flags = REBASE_NO_QUIET,
- .git_am_opt = STRBUF_INIT,
+ .git_am_opts = ARGV_ARRAY_INIT,
.allow_rerere_autoupdate = -1,
.allow_empty_message = 1,
.git_format_patch_opt = STRBUF_INIT,
ACTION_EDIT_TODO,
ACTION_SHOW_CURRENT_PATCH,
} action = NO_ACTION;
- int committer_date_is_author_date = 0;
- int ignore_date = 0;
- int ignore_whitespace = 0;
const char *gpg_sign = NULL;
- int opt_c = -1;
- struct string_list whitespace = STRING_LIST_INIT_NODUP;
struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
int fork_point = -1;
{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
N_("do not show diffstat of what changed upstream"),
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
- OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
- N_("passed to 'git apply'")),
OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by: line to each commit")),
- OPT_BOOL(0, "committer-date-is-author-date",
- &committer_date_is_author_date,
- N_("passed to 'git am'")),
- OPT_BOOL(0, "ignore-date", &ignore_date,
- N_("passed to 'git am'")),
+ OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
+ NULL, N_("passed to 'git am'"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
+ &options.git_am_opts, NULL,
+ N_("passed to 'git am'"), PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
+ N_("passed to 'git am'"), PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
+ N_("passed to 'git apply'"), 0),
+ OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
+ N_("action"), N_("passed to 'git apply'"), 0),
OPT_BIT('f', "force-rebase", &options.flags,
N_("cherry-pick all commits, even if unchanged"),
REBASE_FORCE),
"them"), REBASE_PRESERVE_MERGES),
OPT_BOOL(0, "rerere-autoupdate",
&options.allow_rerere_autoupdate,
- N_("allow rerere to update index with resolved "
+ N_("allow rerere to update index with resolved "
"conflict")),
OPT_BOOL('k', "keep-empty", &options.keep_empty,
N_("preserve empty commits during rebase")),
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_STRING_LIST(0, "whitespace", &whitespace,
- N_("whitespace"), N_("passed to 'git apply'")),
- OPT_SET_INT('C', NULL, &opt_c, N_("passed to 'git apply'"),
- REBASE_AM),
OPT_BOOL(0, "autostash", &options.autostash,
N_("automatically stash/stash pop before and after")),
OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
N_("rebase all reachable commits up to the root(s)")),
OPT_END(),
};
+ int i;
/*
* NEEDSWORK: Once the builtin rebase has been tested enough
if (action != NO_ACTION && !in_progress)
die(_("No rebase in progress?"));
+ setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0);
if (action == ACTION_EDIT_TODO && !is_interactive(&options))
die(_("The --edit-todo action can only be used during "
int fd;
options.action = "continue";
+ set_reflog_action(&options);
/* Sanity check */
if (get_oid("HEAD", &head))
&lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(1)) {
+ if (has_unstaged_changes(the_repository, 1)) {
puts(_("You must edit all merge conflicts and then\n"
"mark them as resolved using git add"));
exit(1);
struct string_list merge_rr = STRING_LIST_INIT_DUP;
options.action = "skip";
+ set_reflog_action(&options);
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
- if (reset_head(NULL, "reset", NULL, 0, NULL, NULL) < 0)
+ if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD,
+ NULL, NULL) < 0)
die(_("could not discard worktree changes"));
- remove_branch_state();
++ remove_branch_state(the_repository);
if (read_basic_state(&options))
exit(1);
goto run_rebase;
case ACTION_ABORT: {
struct string_list merge_rr = STRING_LIST_INIT_DUP;
options.action = "abort";
+ set_reflog_action(&options);
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
if (read_basic_state(&options))
exit(1);
if (reset_head(&options.orig_head, "reset",
- options.head_name, 0, NULL, NULL) < 0)
+ options.head_name, RESET_HEAD_HARD,
+ NULL, NULL) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head));
- remove_branch_state();
++ remove_branch_state(the_repository);
ret = finish_rebase(&options);
goto cleanup;
}
state_dir_base, cmd_live_rebase, buf.buf);
}
- if (!(options.flags & REBASE_NO_QUIET))
- strbuf_addstr(&options.git_am_opt, " -q");
-
- if (committer_date_is_author_date) {
- strbuf_addstr(&options.git_am_opt,
- " --committer-date-is-author-date");
- options.flags |= REBASE_FORCE;
+ for (i = 0; i < options.git_am_opts.argc; i++) {
+ const char *option = options.git_am_opts.argv[i], *p;
+ if (!strcmp(option, "--committer-date-is-author-date") ||
+ !strcmp(option, "--ignore-date") ||
+ !strcmp(option, "--whitespace=fix") ||
+ !strcmp(option, "--whitespace=strip"))
+ options.flags |= REBASE_FORCE;
+ else if (skip_prefix(option, "-C", &p)) {
+ while (*p)
+ if (!isdigit(*(p++)))
+ die(_("switch `C' expects a "
+ "numerical value"));
+ } else if (skip_prefix(option, "--whitespace=", &p)) {
+ if (*p && strcmp(p, "warn") && strcmp(p, "nowarn") &&
+ strcmp(p, "error") && strcmp(p, "error-all"))
+ die("Invalid whitespace option: '%s'", p);
+ }
}
- if (ignore_whitespace)
- strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
-
- if (ignore_date) {
- strbuf_addstr(&options.git_am_opt, " --ignore-date");
- options.flags |= REBASE_FORCE;
- }
+ if (!(options.flags & REBASE_NO_QUIET))
+ argv_array_push(&options.git_am_opts, "-q");
if (options.keep_empty)
imply_interactive(&options, "--keep-empty");
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
}
- if (opt_c >= 0)
- strbuf_addf(&options.git_am_opt, " -C%d", opt_c);
-
- if (whitespace.nr) {
- int i;
-
- for (i = 0; i < whitespace.nr; i++) {
- const char *item = whitespace.items[i].string;
-
- strbuf_addf(&options.git_am_opt, " --whitespace=%s",
- item);
-
- if ((!strcmp(item, "fix")) || (!strcmp(item, "strip")))
- options.flags |= REBASE_FORCE;
- }
- }
-
if (exec.nr) {
int i;
break;
}
- if (options.git_am_opt.len) {
- const char *p;
-
+ if (options.git_am_opts.argc) {
/* all am options except -q are compatible only with --am */
- strbuf_reset(&buf);
- strbuf_addbuf(&buf, &options.git_am_opt);
- strbuf_addch(&buf, ' ');
- while ((p = strstr(buf.buf, " -q ")))
- strbuf_splice(&buf, p - buf.buf, 4, " ", 1);
- strbuf_trim(&buf);
+ for (i = options.git_am_opts.argc - 1; i >= 0; i--)
+ if (strcmp(options.git_am_opts.argv[i], "-q"))
+ break;
- if (is_interactive(&options) && buf.len)
+ if (is_interactive(&options) && i >= 0)
die(_("error: cannot combine interactive options "
"(--interactive, --exec, --rebase-merges, "
"--preserve-merges, --keep-empty, --root + "
"--onto) with am options (%s)"), buf.buf);
- if (options.type == REBASE_MERGE && buf.len)
+ if (options.type == REBASE_MERGE && i >= 0)
die(_("error: cannot combine merge options (--merge, "
"--strategy, --strategy-option) with am options "
"(%s)"), buf.buf);
if (options.type == REBASE_PRESERVE_MERGES)
die("cannot combine '--signoff' with "
"'--preserve-merges'");
- strbuf_addstr(&options.git_am_opt, " --signoff");
+ argv_array_push(&options.git_am_opts, "--signoff");
options.flags |= REBASE_FORCE;
}
update_index_if_able(&the_index, &lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(1) || has_uncommitted_changes(1)) {
+ if (has_unstaged_changes(the_repository, 1) ||
+ has_uncommitted_changes(the_repository, 1)) {
const char *autostash =
state_dir_path("autostash", &options);
struct child_process stash = CHILD_PROCESS_INIT;
write_file(autostash, "%s", oid_to_hex(&oid));
printf(_("Created autostash: %s\n"), buf.buf);
if (reset_head(&head->object.oid, "reset --hard",
- NULL, 0, NULL, NULL) < 0)
+ NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
die(_("could not reset --hard"));
printf(_("HEAD is now at %s"),
find_unique_abbrev(&head->object.oid,
}
}
- if (require_clean_work_tree("rebase",
+ if (require_clean_work_tree(the_repository, "rebase",
_("Please commit or stash them."), 1, 1)) {
ret = 1;
goto cleanup;
}
strbuf_reset(&buf);
- strbuf_addf(&buf, "rebase: checkout %s",
+ strbuf_addf(&buf, "%s: checkout %s",
+ getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
options.switch_to);
if (reset_head(&oid, "checkout",
options.head_name, 0,
- NULL, NULL) < 0) {
+ NULL, buf.buf) < 0) {
ret = !!error(_("could not switch to "
"%s"),
options.switch_to);
if (options.flags & REBASE_DIFFSTAT) {
struct diff_options opts;
- if (options.flags & REBASE_VERBOSE)
- printf(_("Changes from %s to %s:\n"),
- oid_to_hex(&merge_base),
- oid_to_hex(&options.onto->object.oid));
+ if (options.flags & REBASE_VERBOSE) {
+ if (is_null_oid(&merge_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(&options.onto->object.oid));
+ }
/* We want color (if set), but no pager */
diff_setup(&opts);
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
diff_setup_done(&opts);
- diff_tree_oid(&merge_base, &options.onto->object.oid,
- "", &opts);
+ diff_tree_oid(is_null_oid(&merge_base) ?
+ the_hash_algo->empty_tree : &merge_base,
+ &options.onto->object.oid, "", &opts);
diffcore_std(&opts);
diff_flush(&opts);
}
printf(_("First, rewinding head to replay your work on top of "
"it...\n"));
- strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
- if (reset_head(&options.onto->object.oid, "checkout", NULL, 1,
- NULL, msg.buf))
+ strbuf_addf(&msg, "%s: checkout %s",
+ getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
+ if (reset_head(&options.onto->object.oid, "checkout", NULL,
+ RESET_HEAD_DETACH, NULL, msg.buf))
die(_("Could not detach HEAD"));
strbuf_release(&msg);
*/
strbuf_reset(&msg);
if (!oidcmp(&merge_base, &options.orig_head)) {
- printf(_("Fast-forwarded %s to %s. \n"),
+ 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",
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
- ecb.outf = outf;
+ ecb.out_hunk = NULL;
+ ecb.out_line = outf;
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
}
if (!strcmp(argv[0], "clear")) {
- rerere_clear(&merge_rr);
+ rerere_clear(the_repository, &merge_rr);
} else if (!strcmp(argv[0], "gc"))
- rerere_gc(&merge_rr);
+ rerere_gc(the_repository, &merge_rr);
else if (!strcmp(argv[0], "status")) {
- if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)
+ if (setup_rerere(the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (i = 0; i < merge_rr.nr; i++)
printf("%s\n", merge_rr.items[i].string);
merge_rr.items[i].util = NULL;
}
} else if (!strcmp(argv[0], "diff")) {
- if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)
+ if (setup_rerere(the_repository, &merge_rr,
+ flags | RERERE_READONLY) < 0)
return 0;
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
#include "submodule.h"
#include "submodule-config.h"
+#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
+
static const char * const git_reset_usage[] = {
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
- prime_cache_tree(&the_index, tree);
+ prime_cache_tree(the_repository, the_repository->index, tree);
}
ret = 0;
};
git_config(git_reset_config, NULL);
+ git_config_get_bool("reset.quiet", &quiet);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
if (read_from_tree(&pathspec, &oid, intent_to_add))
return 1;
- if (get_git_work_tree())
+ if (!quiet && get_git_work_tree()) {
+ uint64_t t_begin, t_delta_in_ms;
+
+ t_begin = getnanotime();
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
+ t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
+ if (advice_reset_quiet_warning && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
+ printf(_("\nIt took %.2f seconds to enumerate unstaged changes after reset. You can\n"
+ "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n"
+ "to make this the default.\n"), t_delta_in_ms / 1000.0);
+ }
+ }
} else {
int err = reset_index(&oid, reset_type, quiet);
if (reset_type == KEEP && !err)
print_new_head_line(lookup_commit_reference(the_repository, &oid));
}
if (!pathspec.nr)
- remove_branch_state();
+ remove_branch_state(the_repository);
return update_ref_status;
}
/* Remember to update object flag allocation in object.h */
#define PREREQ_MARK (1u<<16)
- int verify_bundle(struct bundle_header *header, int verbose)
+ int verify_bundle(struct repository *r,
+ struct bundle_header *header,
+ int verbose)
{
/*
* Do fast check, then if any prereqs are missing then go line by line
int i, ret = 0, req_nr;
const char *message = _("Repository lacks these prerequisite commits:");
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(the_repository, &e->oid);
+ struct object *o = parse_object(r, &e->oid);
if (o) {
o->flags |= PREREQ_MARK;
add_pending_object(&revs, o, e->name);
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- struct object *o = parse_object(the_repository, &e->oid);
+ struct object *o = parse_object(r, &e->oid);
assert(o); /* otherwise we'd have returned early */
if (o->flags & SHOWN)
continue;
/* Clean up objects used, as they will be reused. */
for (i = 0; i < p->nr; i++) {
struct ref_list_entry *e = p->list + i;
- commit = lookup_commit_reference_gently(the_repository, &e->oid, 1);
+ commit = lookup_commit_reference_gently(r, &e->oid, 1);
if (commit)
clear_commit_marks(commit, ALL_REV_FLAGS);
}
}
-/* Write the pack data to bundle_fd, then close it if it is > 1. */
+/* Write the pack data to bundle_fd */
static int write_pack_data(int bundle_fd, struct rev_info *revs)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
pack_objects.in = -1;
pack_objects.out = bundle_fd;
pack_objects.git_cmd = 1;
+
+ /*
+ * start_command() will close our descriptor if it's >1. Duplicate it
+ * to avoid surprising the caller.
+ */
+ if (pack_objects.out > 1) {
+ pack_objects.out = dup(pack_objects.out);
+ if (pack_objects.out < 0) {
+ error_errno(_("unable to dup bundle descriptor"));
+ child_process_clear(&pack_objects);
+ return -1;
+ }
+ }
+
if (start_command(&pack_objects))
return error(_("Could not spawn pack-objects"));
* in terms of a tag (e.g. v2.0 from the range
* "v1.0..v2.0")?
*/
- struct commit *one = lookup_commit_reference(the_repository,
- &oid);
+ struct commit *one = lookup_commit_reference(revs->repo, &oid);
struct object *obj;
if (e->item == &(one->object)) {
return ref_count;
}
- int create_bundle(struct bundle_header *header, const char *path,
- int argc, const char **argv)
+ int create_bundle(struct repository *r, struct bundle_header *header,
+ const char *path, int argc, const char **argv)
{
struct lock_file lock = LOCK_INIT;
int bundle_fd = -1;
bundle_to_stdout = !strcmp(path, "-");
if (bundle_to_stdout)
bundle_fd = 1;
- else {
+ else
bundle_fd = hold_lock_file_for_update(&lock, path,
LOCK_DIE_ON_ERROR);
- /*
- * write_pack_data() will close the fd passed to it,
- * but commit_lock_file() will also try to close the
- * lockfile's fd. So make a copy of the file
- * descriptor to avoid trying to close it twice.
- */
- bundle_fd = dup(bundle_fd);
- if (bundle_fd < 0)
- die_errno("unable to dup file descriptor");
- }
-
/* write signature */
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
/* init revs to list objects for pack-objects later */
save_commit_buffer = 0;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
/* write prerequisites */
if (compute_and_write_prerequisites(bundle_fd, &revs, argc, argv))
goto err;
/* write pack */
- if (write_pack_data(bundle_fd, &revs)) {
- bundle_fd = -1; /* already closed by the above call */
+ if (write_pack_data(bundle_fd, &revs))
goto err;
- }
if (!bundle_to_stdout) {
if (commit_lock_file(&lock))
}
return 0;
err:
- if (!bundle_to_stdout) {
- if (0 <= bundle_fd)
- close(bundle_fd);
- rollback_lock_file(&lock);
- }
+ rollback_lock_file(&lock);
return -1;
}
- int unbundle(struct bundle_header *header, int bundle_fd, int flags)
+ int unbundle(struct repository *r, struct bundle_header *header,
+ int bundle_fd, int flags)
{
const char *argv_index_pack[] = {"index-pack",
"--fix-thin", "--stdin", NULL, NULL};
if (flags & BUNDLE_VERBOSE)
argv_index_pack[3] = "-v";
- if (verify_bundle(header, 0))
+ if (verify_bundle(r, header, 0))
return -1;
ip.argv = argv_index_pack;
ip.in = bundle_fd;
struct sline *lost_bucket;
};
-static void consume_line(void *state_, char *line, unsigned long len)
+static void consume_hunk(void *state_,
+ long ob, long on,
+ long nb, long nn,
+ const char *funcline, long funclen)
{
struct combine_diff_state *state = state_;
- if (5 < len && !memcmp("@@ -", line, 4)) {
- if (parse_hunk_header(line, len,
- &state->ob, &state->on,
- &state->nb, &state->nn))
- return;
- state->lno = state->nb;
- if (state->nn == 0) {
- /* @@ -X,Y +N,0 @@ removed Y lines
- * that would have come *after* line N
- * in the result. Our lost buckets hang
- * to the line after the removed lines,
- *
- * Note that this is correct even when N == 0,
- * in which case the hunk removes the first
- * line in the file.
- */
- state->lost_bucket = &state->sline[state->nb];
- if (!state->nb)
- state->nb = 1;
- } else {
- state->lost_bucket = &state->sline[state->nb-1];
- }
- if (!state->sline[state->nb-1].p_lno)
- state->sline[state->nb-1].p_lno =
- xcalloc(state->num_parent,
- sizeof(unsigned long));
- state->sline[state->nb-1].p_lno[state->n] = state->ob;
- return;
+
+ state->ob = ob;
+ state->on = on;
+ state->nb = nb;
+ state->nn = nn;
+ state->lno = state->nb;
+ if (state->nn == 0) {
+ /* @@ -X,Y +N,0 @@ removed Y lines
+ * that would have come *after* line N
+ * in the result. Our lost buckets hang
+ * to the line after the removed lines,
+ *
+ * Note that this is correct even when N == 0,
+ * in which case the hunk removes the first
+ * line in the file.
+ */
+ state->lost_bucket = &state->sline[state->nb];
+ if (!state->nb)
+ state->nb = 1;
+ } else {
+ state->lost_bucket = &state->sline[state->nb-1];
}
+ if (!state->sline[state->nb-1].p_lno)
+ state->sline[state->nb-1].p_lno =
+ xcalloc(state->num_parent, sizeof(unsigned long));
+ state->sline[state->nb-1].p_lno[state->n] = state->ob;
+}
+
+static void consume_line(void *state_, char *line, unsigned long len)
+{
+ struct combine_diff_state *state = state_;
if (!state->lost_bucket)
return; /* not in any hunk yet */
switch (line[0]) {
state.num_parent = num_parent;
state.n = n;
- if (xdi_diff_outf(&parent_file, result_file, consume_line, &state,
- &xpp, &xecfg))
+ if (xdi_diff_outf(&parent_file, result_file, consume_hunk,
+ consume_line, &state, &xpp, &xecfg))
die("unable to generate combined diff for %s",
oid_to_hex(parent));
free(parent_file.ptr);
if (!userdiff)
userdiff = userdiff_find_by_name("default");
if (opt->flags.allow_textconv)
- textconv = userdiff_get_textconv(userdiff);
+ textconv = userdiff_get_textconv(opt->repo, userdiff);
/* Read the result of merge first */
if (!working_tree_file)
}
}
-static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
+static void fn_out_diff_words_aux(void *priv,
+ long minus_first, long minus_len,
+ long plus_first, long plus_len,
+ const char *func, long funclen)
{
struct diff_words_data *diff_words = priv;
struct diff_words_style *style = diff_words->style;
- int minus_first, minus_len, plus_first, plus_len;
const char *minus_begin, *minus_end, *plus_begin, *plus_end;
struct diff_options *opt = diff_words->opt;
const char *line_prefix;
- if (line[0] != '@' || parse_hunk_header(line, len,
- &minus_first, &minus_len, &plus_first, &plus_len))
- return;
-
assert(opt);
line_prefix = diff_line_prefix(opt);
xpp.flags = 0;
/* as only the hunk header will be parsed, we need a 0-context */
xecfg.ctxlen = 0;
- if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
- &xpp, &xecfg))
+ if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, NULL,
+ diff_words, &xpp, &xecfg))
die("unable to generate word diff");
free(minus.ptr);
free(plus.ptr);
return 1;
}
+static void checkdiff_consume_hunk(void *priv,
+ long ob, long on, long nb, long nn,
+ const char *func, long funclen)
+
+{
+ struct checkdiff_t *data = priv;
+ data->lineno = nb - 1;
+}
+
static void checkdiff_consume(void *priv, char *line, unsigned long len)
{
struct checkdiff_t *data = priv;
data->o->file, set, reset, ws);
} else if (line[0] == ' ') {
data->lineno++;
- } else if (line[0] == '@') {
- char *plus = strchr(line, '+');
- if (plus)
- data->lineno = strtol(plus, NULL, 10) - 1;
- else
- die("invalid diff");
}
}
}
if (delta && delta_size < deflate_size) {
- char *s = xstrfmt("%lu", orig_size);
+ char *s = xstrfmt("%"PRIuMAX , (uintmax_t)orig_size);
emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER_DELTA,
s, strlen(s), 0);
free(s);
options->b_prefix = b;
}
- struct userdiff_driver *get_textconv(struct index_state *istate,
+ struct userdiff_driver *get_textconv(struct repository *r,
struct diff_filespec *one)
{
if (!DIFF_FILE_VALID(one))
return NULL;
- diff_filespec_load_driver(one, istate);
- return userdiff_get_textconv(one->driver);
+ diff_filespec_load_driver(one, r->index);
+ return userdiff_get_textconv(r, one->driver);
}
static void builtin_diff(const char *name_a,
}
if (o->flags.allow_textconv) {
- textconv_one = get_textconv(o->repo->index, one);
- textconv_two = get_textconv(o->repo->index, two);
+ textconv_one = get_textconv(o->repo, one);
+ textconv_two = get_textconv(o->repo, two);
}
/* Never use a non-valid filename anywhere if at all possible */
xecfg.ctxlen = strtoul(v, NULL, 10);
if (o->word_diff)
init_diff_words_data(&ecbdata, o, one, two);
- if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
- &xpp, &xecfg))
+ if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
+ &ecbdata, &xpp, &xecfg))
die("unable to generate diff for %s", one->path);
if (o->word_diff)
free_diff_words_data(&ecbdata);
xpp.anchors_nr = o->anchors_nr;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
- if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
- &xpp, &xecfg))
+ if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
+ diffstat_consume, diffstat, &xpp, &xecfg))
die("unable to generate diffstat for %s", one->path);
}
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 1; /* at least one context line */
xpp.flags = 0;
- if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
+ if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume_hunk,
+ checkdiff_consume, &data,
&xpp, &xecfg))
die("unable to generate checkdiff for %s", one->path);
struct patch_id_t *data = priv;
int new_len;
- /* Ignore line numbers when computing the SHA1 of the patch */
- if (starts_with(line, "@@ -"))
- return;
-
new_len = remove_space(line, len);
git_SHA1_Update(data->ctx, line, new_len);
xpp.flags = 0;
xecfg.ctxlen = 3;
xecfg.flags = 0;
- if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
- &xpp, &xecfg))
+ if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
+ patch_id_consume, &data, &xpp, &xecfg))
return error("unable to generate patch-id diff for %s",
p->one->path);
}
df = alloc_filespec(path);
fill_filespec(df, oid, oid_valid, mode);
- textconv = get_textconv(r->index, df);
+ textconv = get_textconv(r, df);
if (!textconv) {
free_filespec(df);
return 0;
ecbdata.hit = 0;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
- if (xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, &xpp, &xecfg))
+ if (xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume,
+ &ecbdata, &xpp, &xecfg))
return 0;
return ecbdata.hit;
}
return 0;
if (o->flags.allow_textconv) {
- textconv_one = get_textconv(o->repo->index, p->one);
- textconv_two = get_textconv(o->repo->index, p->two);
+ textconv_one = get_textconv(o->repo, p->one);
+ textconv_two = get_textconv(o->repo, p->two);
}
/*
}
}
-#ifndef NO_PTHREADS
int grep_use_locks;
/*
*/
pthread_mutex_t grep_read_mutex;
-#else
-#define grep_attr_lock()
-#define grep_attr_unlock()
-#endif
-
static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol)
{
xdemitconf_t *xecfg = opt->priv;
* is not thread-safe.
*/
grep_attr_lock();
- textconv = userdiff_get_textconv(gs->driver);
+ textconv = userdiff_get_textconv(opt->repo, gs->driver);
grep_attr_unlock();
}
#include "thread-utils.h"
#include "pack.h"
+ struct repository;
+
#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024)
#define OE_DFS_STATE_BITS 2
};
struct packing_data {
+ struct repository *repo;
struct object_entry *objects;
uint32_t nr_objects, nr_alloc;
struct packed_git **in_pack_by_idx;
struct packed_git **in_pack;
-#ifndef NO_PTHREADS
pthread_mutex_t lock;
-#endif
/*
* This list contains entries for bases which we know the other side
unsigned char *layer;
};
- void prepare_packing_data(struct packing_data *pdata);
+ void prepare_packing_data(struct repository *r, struct packing_data *pdata);
static inline void packing_data_lock(struct packing_data *pdata)
{
-#ifndef NO_PTHREADS
pthread_mutex_lock(&pdata->lock);
-#endif
}
static inline void packing_data_unlock(struct packing_data *pdata)
{
-#ifndef NO_PTHREADS
pthread_mutex_unlock(&pdata->lock);
-#endif
}
struct object_entry *packlist_alloc(struct packing_data *pdata,
unsigned int tree_depth)
{
if (!pack->tree_depth)
- ALLOC_ARRAY(pack->tree_depth, pack->nr_objects);
+ CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc);
pack->tree_depth[e - pack->objects] = tree_depth;
}
unsigned char layer)
{
if (!pack->layer)
- ALLOC_ARRAY(pack->layer, pack->nr_objects);
+ CALLOC_ARRAY(pack->layer, pack->nr_alloc);
pack->layer[e - pack->objects] = layer;
}
typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
+ /*
+ * Use the multi-threaded preload_index() to refresh most of the
+ * cache entries quickly then in the single threaded loop below,
+ * we only have to do the special cases that are left.
+ */
+ preload_index(istate, pathspec, 0);
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new_entry;
int cache_errno = 0;
size_t len;
const char *name;
unsigned int flags;
- size_t copy_len;
+ size_t copy_len = 0;
/*
* Adjacent cache entries tend to share the leading paths, so it makes
* sense to only store the differences in later entries. In the v4
die(_("malformed name field in the index, near path '%s'"),
previous_ce->name);
copy_len = previous_len - strip_len;
- } else {
- copy_len = 0;
}
name = (const char *)cp;
}
struct index_entry_offset entries[FLEX_ARRAY];
};
-#ifndef NO_PTHREADS
static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset);
static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot);
-#endif
static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
struct load_index_extensions
{
-#ifndef NO_PTHREADS
pthread_t pthread;
-#endif
struct index_state *istate;
const char *mmap;
size_t mmap_size;
return consumed;
}
-#ifndef NO_PTHREADS
-
/*
* Mostly randomly chosen maximum thread counts: we
* cap the parallelism to online_cpus() threads, and we want
return consumed;
}
-#endif
/* remember to discard_cache() before reading a different cache! */
int do_read_index(struct index_state *istate, const char *path, int must_exist)
size_t mmap_size;
struct load_index_extensions p;
size_t extension_offset = 0;
-#ifndef NO_PTHREADS
int nr_threads, cpus;
struct index_entry_offset_table *ieot = NULL;
-#endif
if (istate->initialized)
return istate->cache_nr;
src_offset = sizeof(*hdr);
-#ifndef NO_PTHREADS
- nr_threads = git_config_get_index_threads();
+ if (git_config_get_index_threads(&nr_threads))
+ nr_threads = 1;
/* TODO: does creating more threads than cores help? */
if (!nr_threads) {
nr_threads = cpus;
}
+ if (!HAVE_THREADS)
+ nr_threads = 1;
+
if (nr_threads > 1) {
extension_offset = read_eoie_extension(mmap, mmap_size);
if (extension_offset) {
} else {
src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset);
}
-#else
- src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset);
-#endif
istate->timestamp.sec = st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st);
/* if we created a thread, join it otherwise load the extensions on the primary thread */
-#ifndef NO_PTHREADS
if (extension_offset) {
int ret = pthread_join(p.pthread, NULL);
if (ret)
die(_("unable to join load_index_extensions thread: %s"), strerror(ret));
- }
-#endif
- if (!extension_offset) {
+ } else {
p.src_offset = src_offset;
load_index_extensions(&p);
}
rollback_lock_file(lockfile);
}
+static int record_eoie(void)
+{
+ int val;
+
+ if (!git_config_get_bool("index.recordendofindexentries", &val))
+ return val;
+
+ /*
+ * As a convenience, the end of index entries extension
+ * used for threading is written by default if the user
+ * explicitly requested threaded index reads.
+ */
+ return !git_config_get_index_threads(&val) && val != 1;
+}
+
+static int record_ieot(void)
+{
+ int val;
+
+ if (!git_config_get_bool("index.recordoffsettable", &val))
+ return val;
+
+ /*
+ * As a convenience, the offset table used for threading is
+ * written by default if the user explicitly requested
+ * threaded index reads.
+ */
+ return !git_config_get_index_threads(&val) && val != 1;
+}
+
/*
* On success, `tempfile` is closed. If it is the temporary file
* of a `struct lock_file`, we will therefore effectively perform
if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
return -1;
-#ifndef NO_PTHREADS
- nr_threads = git_config_get_index_threads();
- if (nr_threads != 1) {
+ if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+ nr_threads = 1;
+
+ if (nr_threads != 1 && record_ieot()) {
int ieot_blocks, cpus;
/*
ieot_entries = DIV_ROUND_UP(entries, ieot_blocks);
}
}
-#endif
offset = lseek(newfd, 0, SEEK_CUR);
if (offset < 0) {
* strip_extensions parameter as we need it when loading the shared
* index.
*/
-#ifndef NO_PTHREADS
if (ieot) {
struct strbuf sb = STRBUF_INIT;
if (err)
return -1;
}
-#endif
if (!strip_extensions && istate->split_index) {
struct strbuf sb = STRBUF_INIT;
* read. Write it out regardless of the strip_extensions parameter as we need it
* when loading the shared index.
*/
- if (offset) {
+ if (offset && record_eoie()) {
struct strbuf sb = STRBUF_INIT;
write_eoie_extension(&sb, &eoie_c, offset);
struct split_index *si = istate->split_index;
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
- cache_tree_verify(istate);
+ cache_tree_verify(the_repository, istate);
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
if (flags & COMMIT_LOCK)
struct tempfile *temp;
int saved_errno;
- temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
+ /* Same initial permissions as the main .git/index file */
+ temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
if (!temp) {
oidclr(&si->base_oid);
ret = do_write_locked_index(istate, lock, flags);
strbuf_add(sb, hash, the_hash_algo->rawsz);
}
-#ifndef NO_PTHREADS
#define IEOT_VERSION (1)
static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
strbuf_add(sb, &buffer, sizeof(uint32_t));
}
}
-#endif
if (ARRAY_SIZE(valid_atom) <= i)
return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"),
(int)(ep-atom), atom);
+ if (valid_atom[i].source != SOURCE_NONE && !have_git_dir())
+ return strbuf_addf_ret(err, -1,
+ _("not a git repository, but the field '%.*s' requires access to object data"),
+ (int)(ep-atom), atom);
/* Add it in, including the deref prefix */
at = used_atom_cnt;
v->s = xstrdup(type_name(oi->type));
else if (!strcmp(name, "objectsize")) {
v->value = oi->size;
- v->s = xstrfmt("%lu", oi->size);
+ v->s = xstrfmt("%"PRIuMAX , (uintmax_t)oi->size);
}
else if (deref)
grab_objectname(name, &oi->oid, v, &used_atom[i]);
struct strbuf desc = STRBUF_INIT;
struct wt_status_state state;
memset(&state, 0, sizeof(state));
- wt_status_get_state(&state, 1);
+ wt_status_get_state(the_repository, &state, 1);
if (state.rebase_in_progress ||
state.rebase_interactive_in_progress) {
if (state.branch)
struct object_id oid;
int no_merged = starts_with(opt->long_name, "no");
+ BUG_ON_OPT_NEG(unset);
+
if (rf->merge) {
if (no_merged) {
return opterror(opt, "is incompatible with --merged", 0);
unuse_commit_buffer(commit, msg->message);
}
- static void print_advice(int show_hint, struct replay_opts *opts)
+ static void print_advice(struct repository *r, int show_hint,
+ struct replay_opts *opts)
{
char *msg = getenv("GIT_CHERRY_PICK_HELP");
* (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD
*/
- unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_cherry_pick_head(r));
return;
}
return 1;
}
- static struct tree *empty_tree(void)
+ static struct tree *empty_tree(struct repository *r)
{
- return lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
+ return lookup_tree(r, the_hash_algo->empty_tree);
}
- static int error_dirty_index(struct replay_opts *opts)
+ static int error_dirty_index(struct index_state *istate, struct replay_opts *opts)
{
- if (read_cache_unmerged())
+ if (read_index_unmerged(istate))
return error_resolve_conflict(_(action_name(opts)));
error(_("your local changes would be overwritten by %s."),
write_file(git_path_abort_safety_file(), "%s", "");
}
- static int fast_forward_to(const struct object_id *to, const struct object_id *from,
- int unborn, struct replay_opts *opts)
+ static int fast_forward_to(struct repository *r,
+ const struct object_id *to,
+ const struct object_id *from,
+ int unborn,
+ struct replay_opts *opts)
{
struct ref_transaction *transaction;
struct strbuf sb = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- read_index(&the_index);
- if (checkout_fast_forward(the_repository, from, to, 1))
+ read_index(r->index);
+ if (checkout_fast_forward(r, from, to, 1))
return -1; /* the callee should have complained already */
strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
return 0;
}
- void append_conflicts_hint(struct strbuf *msgbuf)
+ void append_conflicts_hint(struct index_state *istate,
+ struct strbuf *msgbuf)
{
int i;
strbuf_addch(msgbuf, '\n');
strbuf_commented_addf(msgbuf, "Conflicts:\n");
- for (i = 0; i < active_nr;) {
- const struct cache_entry *ce = active_cache[i++];
+ for (i = 0; i < istate->cache_nr;) {
+ const struct cache_entry *ce = istate->cache[i++];
if (ce_stage(ce)) {
strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
+ while (i < istate->cache_nr &&
+ !strcmp(ce->name, istate->cache[i]->name))
i++;
}
}
}
- static int do_recursive_merge(struct commit *base, struct commit *next,
+ static int do_recursive_merge(struct repository *r,
+ struct commit *base, struct commit *next,
const char *base_label, const char *next_label,
struct object_id *head, struct strbuf *msgbuf,
struct replay_opts *opts)
if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0)
return -1;
- read_cache();
+ read_index(r->index);
init_merge_options(&o);
o.ancestor = base ? base_label : "(empty tree)";
o.show_rename_progress = 1;
head_tree = parse_tree_indirect(head);
- next_tree = next ? get_commit_tree(next) : empty_tree();
- base_tree = base ? get_commit_tree(base) : empty_tree();
+ next_tree = next ? get_commit_tree(next) : empty_tree(r);
+ base_tree = base ? get_commit_tree(base) : empty_tree(r);
for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
parse_merge_opt(&o, *xopt);
return clean;
}
- if (write_locked_index(&the_index, &index_lock,
+ if (write_locked_index(r->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
/*
* TRANSLATORS: %s will be "revert", "cherry-pick" or
_(action_name(opts)));
if (!clean)
- append_conflicts_hint(msgbuf);
+ append_conflicts_hint(r->index, msgbuf);
return !clean;
}
- static struct object_id *get_cache_tree_oid(void)
+ static struct object_id *get_cache_tree_oid(struct index_state *istate)
{
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
+ if (!istate->cache_tree)
+ istate->cache_tree = cache_tree();
- if (!cache_tree_fully_valid(active_cache_tree))
- if (cache_tree_update(&the_index, 0)) {
+ if (!cache_tree_fully_valid(istate->cache_tree))
+ if (cache_tree_update(istate, 0)) {
error(_("unable to update cache tree"));
return NULL;
}
- return &active_cache_tree->oid;
+ return &istate->cache_tree->oid;
}
- static int is_index_unchanged(void)
+ static int is_index_unchanged(struct repository *r)
{
struct object_id head_oid, *cache_tree_oid;
struct commit *head_commit;
+ struct index_state *istate = r->index;
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return error(_("could not resolve HEAD commit"));
- head_commit = lookup_commit(the_repository, &head_oid);
+ head_commit = lookup_commit(r, &head_oid);
/*
* If head_commit is NULL, check_commit, called from
if (parse_commit(head_commit))
return -1;
- if (!(cache_tree_oid = get_cache_tree_oid()))
+ if (!(cache_tree_oid = get_cache_tree_oid(istate)))
return -1;
return oideq(cache_tree_oid, get_commit_tree_oid(head_commit));
return res;
}
+/**
+ * Take a series of KEY='VALUE' lines where VALUE part is
+ * sq-quoted, and append <KEY, VALUE> at the end of the string list
+ */
+static int parse_key_value_squoted(char *buf, struct string_list *list)
+{
+ while (*buf) {
+ struct string_list_item *item;
+ char *np;
+ char *cp = strchr(buf, '=');
+ if (!cp) {
+ np = strchrnul(buf, '\n');
+ return error(_("no key present in '%.*s'"),
+ (int) (np - buf), buf);
+ }
+ np = strchrnul(cp, '\n');
+ *cp++ = '\0';
+ item = string_list_append(list, buf);
+
+ buf = np + (*np == '\n');
+ *np = '\0';
+ cp = sq_dequote(cp);
+ if (!cp)
+ return error(_("unable to dequote value of '%s'"),
+ item->string);
+ item->util = xstrdup(cp);
+ }
+ return 0;
+}
-/*
- * write_author_script() used to fail to terminate the last line with a "'" and
- * also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
- * the terminating "'" on the last line to see how "'" has been escaped in case
- * git was upgraded while rebase was stopped.
+/**
+ * Reads and parses the state directory's "author-script" file, and sets name,
+ * email and date accordingly.
+ * Returns 0 on success, -1 if the file could not be parsed.
+ *
+ * The author script is of the format:
+ *
+ * GIT_AUTHOR_NAME='$author_name'
+ * GIT_AUTHOR_EMAIL='$author_email'
+ * GIT_AUTHOR_DATE='$author_date'
+ *
+ * where $author_name, $author_email and $author_date are quoted. We are strict
+ * with our parsing, as the file was meant to be eval'd in the old
+ * git-am.sh/git-rebase--interactive.sh scripts, and thus if the file differs
+ * from what this function expects, it is better to bail out than to do
+ * something that the user does not expect.
*/
-static int quoting_is_broken(const char *s, size_t n)
+int read_author_script(const char *path, char **name, char **email, char **date,
+ int allow_missing)
{
- /* Skip any empty lines in case the file was hand edited */
- while (n > 0 && s[--n] == '\n')
- ; /* empty */
- if (n > 0 && s[n] != '\'')
- return 1;
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list kv = STRING_LIST_INIT_DUP;
+ int retval = -1; /* assume failure */
+ int i, name_i = -2, email_i = -2, date_i = -2, err = 0;
- return 0;
+ if (strbuf_read_file(&buf, path, 256) <= 0) {
+ strbuf_release(&buf);
+ if (errno == ENOENT && allow_missing)
+ return 0;
+ else
+ return error_errno(_("could not open '%s' for reading"),
+ path);
+ }
+
+ if (parse_key_value_squoted(buf.buf, &kv))
+ goto finish;
+
+ for (i = 0; i < kv.nr; i++) {
+ if (!strcmp(kv.items[i].string, "GIT_AUTHOR_NAME")) {
+ if (name_i != -2)
+ name_i = error(_("'GIT_AUTHOR_NAME' already given"));
+ else
+ name_i = i;
+ } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_EMAIL")) {
+ if (email_i != -2)
+ email_i = error(_("'GIT_AUTHOR_EMAIL' already given"));
+ else
+ email_i = i;
+ } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_DATE")) {
+ if (date_i != -2)
+ date_i = error(_("'GIT_AUTHOR_DATE' already given"));
+ else
+ date_i = i;
+ } else {
+ err = error(_("unknown variable '%s'"),
+ kv.items[i].string);
+ }
+ }
+ if (name_i == -2)
+ error(_("missing 'GIT_AUTHOR_NAME'"));
+ if (email_i == -2)
+ error(_("missing 'GIT_AUTHOR_EMAIL'"));
+ if (date_i == -2)
+ error(_("missing 'GIT_AUTHOR_DATE'"));
+ if (date_i < 0 || email_i < 0 || date_i < 0 || err)
+ goto finish;
+ *name = kv.items[name_i].util;
+ *email = kv.items[email_i].util;
+ *date = kv.items[date_i].util;
+ retval = 0;
+finish:
+ string_list_clear(&kv, !!retval);
+ strbuf_release(&buf);
+ return retval;
}
/*
- * Read a list of environment variable assignments (such as the author-script
- * file) into an environment block. Returns -1 on error, 0 otherwise.
+ * Read a GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL AND GIT_AUTHOR_DATE from a
+ * file with shell quoting into struct argv_array. Returns -1 on
+ * error, 0 otherwise.
*/
static int read_env_script(struct argv_array *env)
{
- struct strbuf script = STRBUF_INIT;
- int i, count = 0, sq_bug;
- const char *p2;
- char *p;
+ char *name, *email, *date;
- if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
+ if (read_author_script(rebase_path_author_script(),
+ &name, &email, &date, 0))
return -1;
- /* write_author_script() used to quote incorrectly */
- sq_bug = quoting_is_broken(script.buf, script.len);
- for (p = script.buf; *p; p++)
- if (sq_bug && skip_prefix(p, "'\\\\''", &p2))
- strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
- else if (skip_prefix(p, "'\\''", &p2))
- strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
- else if (*p == '\'')
- strbuf_splice(&script, p-- - script.buf, 1, "", 0);
- else if (*p == '\n') {
- *p = '\0';
- count++;
- }
- for (i = 0, p = script.buf; i < count; i++) {
- argv_array_push(env, p);
- p += strlen(p) + 1;
- }
+ argv_array_pushf(env, "GIT_AUTHOR_NAME=%s", name);
+ argv_array_pushf(env, "GIT_AUTHOR_EMAIL=%s", email);
+ argv_array_pushf(env, "GIT_AUTHOR_DATE=%s", date);
+ free(name);
+ free(email);
+ free(date);
return 0;
}
/* Read author-script and return an ident line (author <email> timestamp) */
static const char *read_author_ident(struct strbuf *buf)
{
- const char *keys[] = {
- "GIT_AUTHOR_NAME=", "GIT_AUTHOR_EMAIL=", "GIT_AUTHOR_DATE="
- };
struct strbuf out = STRBUF_INIT;
- char *in, *eol;
- const char *val[3];
- int i = 0;
+ char *name, *email, *date;
- if (strbuf_read_file(buf, rebase_path_author_script(), 256) <= 0)
+ if (read_author_script(rebase_path_author_script(),
+ &name, &email, &date, 0))
return NULL;
- /* dequote values and construct ident line in-place */
- for (in = buf->buf; i < 3 && in - buf->buf < buf->len; i++) {
- if (!skip_prefix(in, keys[i], (const char **)&in)) {
- warning(_("could not parse '%s' (looking for '%s')"),
- rebase_path_author_script(), keys[i]);
- return NULL;
- }
-
- eol = strchrnul(in, '\n');
- *eol = '\0';
- if (!sq_dequote(in)) {
- warning(_("bad quoting on %s value in '%s'"),
- keys[i], rebase_path_author_script());
- return NULL;
- }
- val[i] = in;
- in = eol + 1;
- }
-
- if (i < 3) {
- warning(_("could not parse '%s' (looking for '%s')"),
- rebase_path_author_script(), keys[i]);
- return NULL;
- }
-
/* validate date since fmt_ident() will die() on bad value */
- if (parse_date(val[2], &out)){
+ if (parse_date(date, &out)){
warning(_("invalid date format '%s' in '%s'"),
- val[2], rebase_path_author_script());
+ date, rebase_path_author_script());
strbuf_release(&out);
return NULL;
}
strbuf_reset(&out);
- strbuf_addstr(&out, fmt_ident(val[0], val[1], val[2], 0));
+ strbuf_addstr(&out, fmt_ident(name, email, date, 0));
strbuf_swap(buf, &out);
strbuf_release(&out);
+ free(name);
+ free(email);
+ free(date);
return buf->buf;
}
* interactive rebase: in that case, we will want to retain the
* author metadata.
*/
- static int run_git_commit(const char *defmsg, struct replay_opts *opts,
+ static int run_git_commit(struct repository *r,
+ const char *defmsg,
+ struct replay_opts *opts,
unsigned int flags)
{
struct child_process cmd = CHILD_PROCESS_INIT;
if (!defmsg)
BUG("root commit without message");
- if (!(cache_tree_oid = get_cache_tree_oid()))
+ if (!(cache_tree_oid = get_cache_tree_oid(r->index)))
res = -1;
if (!res)
run_rewrite_hook(&old_head->object.oid, new_head);
}
- static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit)
+ static int run_prepare_commit_msg_hook(struct repository *r,
+ struct strbuf *msg,
+ const char *commit)
{
struct argv_array hook_env = ARGV_ARRAY_INIT;
int ret;
if (write_message(msg->buf, msg->len, name, 0))
return -1;
- argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file());
+ argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file);
argv_array_push(&hook_env, "GIT_EDITOR=:");
if (commit)
ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
}
- void print_commit_summary(const char *prefix, const struct object_id *oid,
+ void print_commit_summary(struct repository *r,
+ const char *prefix,
+ const struct object_id *oid,
unsigned int flags)
{
struct rev_info rev;
struct strbuf author_ident = STRBUF_INIT;
struct strbuf committer_ident = STRBUF_INIT;
- commit = lookup_commit(the_repository, oid);
+ commit = lookup_commit(r, oid);
if (!commit)
die(_("couldn't look up newly created commit"));
if (parse_commit(commit))
strbuf_release(&author_ident);
strbuf_release(&committer_ident);
- repo_init_revisions(the_repository, &rev, prefix);
+ repo_init_revisions(r, &rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
rev.diff = 1;
strbuf_release(&format);
}
- static int parse_head(struct commit **head)
+ static int parse_head(struct repository *r, struct commit **head)
{
struct commit *current_head;
struct object_id oid;
if (get_oid("HEAD", &oid)) {
current_head = NULL;
} else {
- current_head = lookup_commit_reference(the_repository, &oid);
+ current_head = lookup_commit_reference(r, &oid);
if (!current_head)
return error(_("could not parse HEAD"));
if (!oideq(&oid, ¤t_head->object.oid)) {
* 0 - success
* 1 - run 'git commit'
*/
- static int try_to_commit(struct strbuf *msg, const char *author,
+ static int try_to_commit(struct repository *r,
+ struct strbuf *msg, const char *author,
struct replay_opts *opts, unsigned int flags,
struct object_id *oid)
{
enum commit_msg_cleanup_mode cleanup;
int res = 0;
- if (parse_head(¤t_head))
+ if (parse_head(r, ¤t_head))
return -1;
if (flags & AMEND_MSG) {
commit_list_insert(current_head, &parents);
}
- if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL)) {
+ if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
}
}
if (find_hook("prepare-commit-msg")) {
- res = run_prepare_commit_msg_hook(msg, hook_commit);
+ res = run_prepare_commit_msg_hook(r, msg, hook_commit);
if (res)
goto out;
if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
return res;
}
- static int do_commit(const char *msg_file, const char *author,
+ static int do_commit(struct repository *r,
+ const char *msg_file, const char *author,
struct replay_opts *opts, unsigned int flags)
{
int res = 1;
"from '%s'"),
msg_file);
- res = try_to_commit(msg_file ? &sb : NULL, author, opts, flags,
- &oid);
+ res = try_to_commit(r, msg_file ? &sb : NULL,
+ author, opts, flags, &oid);
strbuf_release(&sb);
if (!res) {
- unlink(git_path_cherry_pick_head(the_repository));
- unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_cherry_pick_head(r));
+ unlink(git_path_merge_msg(r));
if (!is_rebase_i(opts))
- print_commit_summary(NULL, &oid,
+ print_commit_summary(r, NULL, &oid,
SUMMARY_SHOW_AUTHOR_DATE);
return res;
}
}
if (res == 1)
- return run_git_commit(msg_file, opts, flags);
+ return run_git_commit(r, msg_file, opts, flags);
return res;
}
/*
* Do we run "git commit" with "--allow-empty"?
*/
- static int allow_empty(struct replay_opts *opts, struct commit *commit)
+ static int allow_empty(struct repository *r,
+ struct replay_opts *opts,
+ struct commit *commit)
{
int index_unchanged, empty_commit;
if (!opts->allow_empty)
return 0; /* let "git commit" barf as necessary */
- index_unchanged = is_index_unchanged();
+ index_unchanged = is_index_unchanged(r);
if (index_unchanged < 0)
return index_unchanged;
if (!index_unchanged)
}
}
- static int update_squash_messages(enum todo_command command,
- struct commit *commit, struct replay_opts *opts)
+ static int update_squash_messages(struct repository *r,
+ enum todo_command command,
+ struct commit *commit,
+ struct replay_opts *opts)
{
struct strbuf buf = STRBUF_INIT;
int res;
if (get_oid("HEAD", &head))
return error(_("need a HEAD to fixup"));
- if (!(head_commit = lookup_commit_reference(the_repository, &head)))
+ if (!(head_commit = lookup_commit_reference(r, &head)))
return error(_("could not read HEAD"));
if (!(head_message = get_commit_buffer(head_commit, NULL)))
return error(_("could not read HEAD's commit message"));
flush_rewritten_pending();
}
- static int do_pick_commit(enum todo_command command, struct commit *commit,
- struct replay_opts *opts, int final_fixup)
+ static int do_pick_commit(struct repository *r,
+ enum todo_command command,
+ struct commit *commit,
+ struct replay_opts *opts,
+ int final_fixup)
{
unsigned int flags = opts->edit ? EDIT_MSG : 0;
- const char *msg_file = opts->edit ? NULL : git_path_merge_msg(the_repository);
+ const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r);
struct object_id head;
struct commit *base, *next, *parent;
const char *base_label, *next_label;
* that represents the "current" state for merge-recursive
* to work on.
*/
- if (write_index_as_tree(&head, &the_index, get_index_file(), 0, NULL))
+ if (write_index_as_tree(&head, r->index, r->index_file, 0, NULL))
return error(_("your index file is unmerged."));
} else {
unborn = get_oid("HEAD", &head);
unborn = 1;
} else if (unborn)
oidcpy(&head, the_hash_algo->empty_tree);
- if (index_differs_from(unborn ? empty_tree_oid_hex() : "HEAD",
+ if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
NULL, 0))
- return error_dirty_index(opts);
+ return error_dirty_index(r->index, opts);
}
- discard_cache();
+ discard_index(r->index);
if (!commit->parents)
parent = NULL;
(!parent && unborn))) {
if (is_rebase_i(opts))
write_author_script(msg.message);
- res = fast_forward_to(&commit->object.oid, &head, unborn,
+ res = fast_forward_to(r, &commit->object.oid, &head, unborn,
opts);
if (res || command != TODO_REWORD)
goto leave;
if (command == TODO_REWORD)
flags |= EDIT_MSG | VERIFY_MSG;
else if (is_fixup(command)) {
- if (update_squash_messages(command, commit, opts))
+ if (update_squash_messages(r, command, commit, opts))
return -1;
flags |= AMEND_MSG;
if (!final_fixup)
flags |= CLEANUP_MSG;
msg_file = rebase_path_fixup_msg();
} else {
- const char *dest = git_path_squash_msg(the_repository);
+ const char *dest = git_path_squash_msg(r);
unlink(dest);
if (copy_file(dest, rebase_path_squash_msg(), 0666))
return error(_("could not rename '%s' to '%s'"),
rebase_path_squash_msg(), dest);
- unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_msg(r));
msg_file = dest;
flags |= EDIT_MSG;
}
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
res = -1;
else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
- res = do_recursive_merge(base, next, base_label, next_label,
+ res = do_recursive_merge(r, base, next, base_label, next_label,
&head, &msgbuf, opts);
if (res < 0)
goto leave;
res |= write_message(msgbuf.buf, msgbuf.len,
- git_path_merge_msg(the_repository), 0);
+ git_path_merge_msg(r), 0);
} else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
res = write_message(msgbuf.buf, msgbuf.len,
- git_path_merge_msg(the_repository), 0);
+ git_path_merge_msg(r), 0);
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
- res |= try_merge_command(the_repository, opts->strategy,
+ res |= try_merge_command(r, opts->strategy,
opts->xopts_nr, (const char **)opts->xopts,
common, oid_to_hex(&head), remotes);
free_commit_list(common);
? _("could not revert %s... %s")
: _("could not apply %s... %s"),
short_commit_name(commit), msg.subject);
- print_advice(res == 1, opts);
- repo_rerere(the_repository, opts->allow_rerere_auto);
+ print_advice(r, res == 1, opts);
+ repo_rerere(r, opts->allow_rerere_auto);
goto leave;
}
- allow = allow_empty(opts, commit);
+ allow = allow_empty(r, opts, commit);
if (allow < 0) {
res = allow;
goto leave;
if (!opts->no_commit) {
fast_forward_edit:
if (author || command == TODO_REVERT || (flags & AMEND_MSG))
- res = do_commit(msg_file, author, opts, flags);
+ res = do_commit(r, msg_file, author, opts, flags);
else
res = error(_("unable to parse commit author"));
}
return 0;
}
- static int read_and_refresh_cache(struct replay_opts *opts)
+ static int read_and_refresh_cache(struct repository *r,
+ struct replay_opts *opts)
{
struct lock_file index_lock = LOCK_INIT;
int index_fd = hold_locked_index(&index_lock, 0);
- if (read_index(&the_index) < 0) {
- if (read_index_preload(r->index, NULL, 0) < 0) {
++ if (read_index(r->index) < 0) {
rollback_lock_file(&index_lock);
return error(_("git %s: failed to read the index"),
_(action_name(opts)));
}
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
+ refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
if (index_fd >= 0) {
- if (write_locked_index(&the_index, &index_lock,
+ if (write_locked_index(r->index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
return error(_("git %s: failed to refresh the index"),
_(action_name(opts)));
return todo_list->items + todo_list->nr++;
}
- static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
+ static int parse_insn_line(struct repository *r, struct todo_item *item,
+ const char *bol, char *eol)
{
struct object_id commit_oid;
char *end_of_object_name;
if (status < 0)
return -1;
- item->commit = lookup_commit_reference(the_repository, &commit_oid);
+ item->commit = lookup_commit_reference(r, &commit_oid);
return !item->commit;
}
- static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
+ static int parse_insn_buffer(struct repository *r, char *buf,
+ struct todo_list *todo_list)
{
struct todo_item *item;
char *p = buf, *next_p;
item = append_new_todo(todo_list);
item->offset_in_buf = p - todo_list->buf.buf;
- if (parse_insn_line(item, p, eol)) {
+ if (parse_insn_line(r, item, p, eol)) {
res = error(_("invalid line %d: %.*s"),
i, (int)(eol - p), p);
item->command = TODO_NOOP;
return len;
}
- static int read_populate_todo(struct todo_list *todo_list,
- struct replay_opts *opts)
+ static int read_populate_todo(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts)
{
struct stat st;
const char *todo_file = get_todo_path(opts);
return error(_("could not stat '%s'"), todo_file);
fill_stat_data(&todo_list->stat, &st);
- res = parse_insn_buffer(todo_list->buf.buf, todo_list);
+ res = parse_insn_buffer(r, todo_list->buf.buf, todo_list);
if (res) {
if (is_rebase_i(opts))
return error(_("please fix this using "
FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
- !parse_insn_buffer(done.buf.buf, &done))
+ !parse_insn_buffer(r, done.buf.buf, &done))
todo_list->done_nr = count_commands(&done);
else
todo_list->done_nr = 0;
return run_command_v_opt(argv, RUN_GIT_CMD);
}
- static int rollback_single_pick(void)
+ static int rollback_single_pick(struct repository *r)
{
struct object_id head_oid;
- if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
- !file_exists(git_path_revert_head(the_repository)))
+ if (!file_exists(git_path_cherry_pick_head(r)) &&
+ !file_exists(git_path_revert_head(r)))
return error(_("no cherry-pick or revert in progress"));
if (read_ref_full("HEAD", 0, &head_oid, NULL))
return error(_("cannot resolve HEAD"));
return reset_for_rollback(&head_oid);
}
- int sequencer_rollback(struct replay_opts *opts)
+ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
{
FILE *f;
struct object_id oid;
* If CHERRY_PICK_HEAD or REVERT_HEAD indicates
* a single-cherry-pick in progress, abort that.
*/
- return rollback_single_pick();
+ return rollback_single_pick(r);
}
if (!f)
return error_errno(_("cannot open '%s'"), git_path_head_file());
return res;
}
- static int make_patch(struct commit *commit, struct replay_opts *opts)
+ static int make_patch(struct repository *r,
+ struct commit *commit,
+ struct replay_opts *opts)
{
struct strbuf buf = STRBUF_INIT;
struct rev_info log_tree_opt;
strbuf_addf(&buf, "%s/patch", get_dir(opts));
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
- repo_init_revisions(the_repository, &log_tree_opt, NULL);
+ repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.abbrev = 0;
log_tree_opt.diff = 1;
log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
return write_message(p, strlen(p), rebase_path_amend(), 1);
}
- static int error_with_patch(struct commit *commit,
- const char *subject, int subject_len,
- struct replay_opts *opts, int exit_code, int to_amend)
+ static int error_with_patch(struct repository *r,
+ struct commit *commit,
+ const char *subject, int subject_len,
+ struct replay_opts *opts,
+ int exit_code, int to_amend)
{
if (commit) {
- if (make_patch(commit, opts))
+ if (make_patch(r, commit, opts))
return -1;
} else if (copy_file(rebase_path_message(),
- git_path_merge_msg(the_repository), 0666))
+ git_path_merge_msg(r), 0666))
return error(_("unable to copy '%s' to '%s'"),
- git_path_merge_msg(the_repository), rebase_path_message());
+ git_path_merge_msg(r), rebase_path_message());
if (to_amend) {
if (intend_to_amend())
return exit_code;
}
- static int error_failed_squash(struct commit *commit,
- struct replay_opts *opts, int subject_len, const char *subject)
+ static int error_failed_squash(struct repository *r,
+ struct commit *commit,
+ struct replay_opts *opts,
+ int subject_len,
+ const char *subject)
{
if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
return error(_("could not copy '%s' to '%s'"),
rebase_path_squash_msg(), rebase_path_message());
- unlink(git_path_merge_msg(the_repository));
- if (copy_file(git_path_merge_msg(the_repository), rebase_path_message(), 0666))
+ unlink(git_path_merge_msg(r));
+ if (copy_file(git_path_merge_msg(r), rebase_path_message(), 0666))
return error(_("could not copy '%s' to '%s'"),
rebase_path_message(),
- git_path_merge_msg(the_repository));
- return error_with_patch(commit, subject, subject_len, opts, 1, 0);
+ git_path_merge_msg(r));
+ return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
}
- static int do_exec(const char *command_line)
+ static int do_exec(struct repository *r, const char *command_line)
{
struct argv_array child_env = ARGV_ARRAY_INIT;
const char *child_argv[] = { NULL, NULL };
child_env.argv);
/* force re-reading of the cache */
- if (discard_cache() < 0 || read_cache() < 0)
+ if (discard_index(r->index) < 0 || read_index(r->index) < 0)
return error(_("could not read index"));
- dirty = require_clean_work_tree("rebase", NULL, 1, 1);
+ dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1);
if (status) {
warning(_("execution failed: %s\n%s"
return 0;
}
- static int do_label(const char *name, int len)
+ static int do_label(struct repository *r, const char *name, int len)
{
- struct ref_store *refs = get_main_ref_store(the_repository);
+ struct ref_store *refs = get_main_ref_store(r);
struct ref_transaction *transaction;
struct strbuf ref_name = STRBUF_INIT, err = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
static const char *reflog_message(struct replay_opts *opts,
const char *sub_action, const char *fmt, ...);
- static int do_reset(const char *name, int len, struct replay_opts *opts)
+ static int do_reset(struct repository *r,
+ const char *name, int len,
+ struct replay_opts *opts)
{
struct strbuf ref_name = STRBUF_INIT;
struct object_id oid;
struct tree_desc desc;
struct tree *tree;
struct unpack_trees_options unpack_tree_opts;
- int ret = 0, i;
+ int ret = 0;
if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
return -1;
}
oidcpy(&oid, &opts->squash_onto);
} else {
+ int i;
+
/* Determine the length of the label */
for (i = 0; i < len; i++)
if (isspace(name[i]))
- len = i;
+ break;
+ len = i;
strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
if (get_oid(ref_name.buf, &oid) &&
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, "reset");
unpack_tree_opts.head_idx = 1;
- unpack_tree_opts.src_index = &the_index;
- unpack_tree_opts.dst_index = &the_index;
+ unpack_tree_opts.src_index = r->index;
+ unpack_tree_opts.dst_index = r->index;
unpack_tree_opts.fn = oneway_merge;
unpack_tree_opts.merge = 1;
unpack_tree_opts.update = 1;
- if (read_cache_unmerged()) {
+ if (read_index_unmerged(r->index)) {
rollback_lock_file(&lock);
strbuf_release(&ref_name);
return error_resolve_conflict(_(action_name(opts)));
}
tree = parse_tree_indirect(&oid);
- prime_cache_tree(&the_index, tree);
+ prime_cache_tree(r, r->index, tree);
- if (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)
+ if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
ret = error(_("could not write index"));
free((void *)desc.buffer);
return commit;
}
- static int do_merge(struct commit *commit, const char *arg, int arg_len,
+ static int do_merge(struct repository *r,
+ struct commit *commit,
+ const char *arg, int arg_len,
int flags, struct replay_opts *opts)
{
int run_commit_flags = (flags & TODO_EDIT_MERGE_MSG) ?
ret = error(_("octopus merge cannot be executed on "
"top of a [new root]"));
else
- ret = fast_forward_to(&to_merge->item->object.oid,
+ ret = fast_forward_to(r, &to_merge->item->object.oid,
&head_commit->object.oid, 0,
opts);
goto leave_merge;
write_author_script(message);
find_commit_subject(message, &body);
len = strlen(body);
- ret = write_message(body, len, git_path_merge_msg(the_repository), 0);
+ ret = write_message(body, len, git_path_merge_msg(r), 0);
unuse_commit_buffer(commit, message);
if (ret) {
error_errno(_("could not write '%s'"),
- git_path_merge_msg(the_repository));
+ git_path_merge_msg(r));
goto leave_merge;
}
} else {
len = buf.len;
}
- ret = write_message(p, len, git_path_merge_msg(the_repository), 0);
+ ret = write_message(p, len, git_path_merge_msg(r), 0);
strbuf_release(&buf);
if (ret) {
error_errno(_("could not write '%s'"),
- git_path_merge_msg(the_repository));
+ git_path_merge_msg(r));
goto leave_merge;
}
}
if (can_fast_forward) {
rollback_lock_file(&lock);
- ret = fast_forward_to(&commit->object.oid,
+ ret = fast_forward_to(r, &commit->object.oid,
&head_commit->object.oid, 0, opts);
goto leave_merge;
}
argv_array_push(&cmd.args, "--no-log");
argv_array_push(&cmd.args, "--no-stat");
argv_array_push(&cmd.args, "-F");
- argv_array_push(&cmd.args, git_path_merge_msg(the_repository));
+ argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
oid_to_hex(&j->item->object.oid));
strbuf_release(&ref_name);
- unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_cherry_pick_head(r));
rollback_lock_file(&lock);
rollback_lock_file(&lock);
ret = run_command(&cmd);
/* force re-reading of the cache */
- if (!ret && (discard_cache() < 0 || read_cache() < 0))
+ if (!ret && (discard_index(r->index) < 0 ||
+ read_index(r->index) < 0))
ret = error(_("could not read index"));
goto leave_merge;
}
merge_commit = to_merge->item;
- write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
- git_path_merge_head(r), 0);
- write_message("no-ff", 5, git_path_merge_mode(r), 0);
-
bases = get_merge_bases(head_commit, merge_commit);
if (bases && oideq(&merge_commit->object.oid,
&bases->item->object.oid)) {
goto leave_merge;
}
- git_path_merge_head(the_repository), 0);
- write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
+ write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
++ git_path_merge_head(r), 0);
++ write_message("no-ff", 5, git_path_merge_mode(r), 0);
+
for (j = bases; j; j = j->next)
commit_list_insert(j->item, &reversed);
free_commit_list(bases);
- read_cache();
+ read_index(r->index);
init_merge_options(&o);
o.branch1 = "HEAD";
o.branch2 = ref_name.buf;
*/
ret = !ret;
- if (active_cache_changed &&
- write_locked_index(&the_index, &lock, COMMIT_LOCK)) {
+ if (r->index->cache_changed &&
+ write_locked_index(r->index, &lock, COMMIT_LOCK)) {
ret = error(_("merge: Unable to write new index file"));
goto leave_merge;
}
rollback_lock_file(&lock);
if (ret)
- repo_rerere(the_repository, opts->allow_rerere_auto);
+ repo_rerere(r, opts->allow_rerere_auto);
else
/*
* In case of problems, we now want to return a positive
* value (a negative one would indicate that the `merge`
* command needs to be rescheduled).
*/
- ret = !!run_git_commit(git_path_merge_msg(the_repository), opts,
- run_commit_flags);
+ ret = !!run_git_commit(r, git_path_merge_msg(r), opts,
+ run_commit_flags);
leave_merge:
strbuf_release(&ref_name);
return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
}
- static int stopped_at_head(void)
+ static int stopped_at_head(struct repository *r)
{
struct object_id head;
struct commit *commit;
struct commit_message message;
if (get_oid("HEAD", &head) ||
- !(commit = lookup_commit(the_repository, &head)) ||
+ !(commit = lookup_commit(r, &head)) ||
parse_commit(commit) || get_message(commit, &message))
fprintf(stderr, _("Stopped at HEAD\n"));
else {
" git rebase --edit-todo\n"
" git rebase --continue\n");
- static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
+ static int pick_commits(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts)
{
int res = 0, reschedule = 0;
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit));
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
while (todo_list->current < todo_list->nr) {
unlink(rebase_path_author_script());
unlink(rebase_path_stopped_sha());
unlink(rebase_path_amend());
+ unlink(git_path_merge_head(the_repository));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
if (item->command == TODO_BREAK)
- return stopped_at_head();
+ return stopped_at_head(r);
}
if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts))
setenv("GIT_REFLOG_ACTION", reflog_message(opts,
command_to_string(item->command), NULL),
1);
- res = do_pick_commit(item->command, item->commit,
+ res = do_pick_commit(r, item->command, item->commit,
opts, is_final_fixup(todo_list));
if (is_rebase_i(opts) && res < 0) {
/* Reschedule */
_("Stopped at %s... %.*s\n"),
short_commit_name(commit),
item->arg_len, item->arg);
- return error_with_patch(commit,
+ return error_with_patch(r, commit,
item->arg, item->arg_len, opts, res,
!res);
}
if (res && is_fixup(item->command)) {
if (res == 1)
intend_to_amend();
- return error_failed_squash(item->commit, opts,
+ return error_failed_squash(r, item->commit, opts,
item->arg_len, item->arg);
} else if (res && is_rebase_i(opts) && item->commit) {
int to_amend = 0;
oideq(&opts->squash_onto, &oid))))
to_amend = 1;
- return res | error_with_patch(item->commit,
+ return res | error_with_patch(r, item->commit,
item->arg, item->arg_len, opts,
res, to_amend);
}
struct stat st;
*end_of_arg = '\0';
- res = do_exec(item->arg);
+ res = do_exec(r, item->arg);
*end_of_arg = saved;
/* Reread the todo file if it has changed. */
get_todo_path(opts));
else if (match_stat_data(&todo_list->stat, &st)) {
todo_list_release(todo_list);
- if (read_populate_todo(todo_list, opts))
+ if (read_populate_todo(r, todo_list, opts))
res = -1; /* message was printed */
/* `current` will be incremented below */
todo_list->current = -1;
}
} else if (item->command == TODO_LABEL) {
- if ((res = do_label(item->arg, item->arg_len)))
+ if ((res = do_label(r, item->arg, item->arg_len)))
reschedule = 1;
} else if (item->command == TODO_RESET) {
- if ((res = do_reset(item->arg, item->arg_len, opts)))
+ if ((res = do_reset(r, item->arg, item->arg_len, opts)))
reschedule = 1;
} else if (item->command == TODO_MERGE) {
- if ((res = do_merge(item->commit,
+ if ((res = do_merge(r, item->commit,
item->arg, item->arg_len,
item->flags, opts)) < 0)
reschedule = 1;
peek_command(todo_list, 1));
if (res > 0)
/* failed with merge conflicts */
- return error_with_patch(item->commit,
+ return error_with_patch(r, item->commit,
item->arg,
item->arg_len, opts,
res, 0);
if (save_todo(todo_list, opts))
return -1;
if (item->commit)
- return error_with_patch(item->commit,
+ return error_with_patch(r,
+ item->commit,
item->arg,
item->arg_len, opts,
res, 0);
struct object_id orig, head;
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
- repo_init_revisions(the_repository, &log_tree_opt, NULL);
+ repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.diff = 1;
log_tree_opt.diffopt.output_format =
DIFF_FORMAT_DIFFSTAT;
return sequencer_remove_state(opts);
}
- static int continue_single_pick(void)
+ static int continue_single_pick(struct repository *r)
{
const char *argv[] = { "commit", NULL };
- if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
- !file_exists(git_path_revert_head(the_repository)))
+ if (!file_exists(git_path_cherry_pick_head(r)) &&
+ !file_exists(git_path_revert_head(r)))
return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD);
}
- static int commit_staged_changes(struct replay_opts *opts,
+ static int commit_staged_changes(struct repository *r,
+ struct replay_opts *opts,
struct todo_list *todo_list)
{
unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
unsigned int final_fixup = 0, is_clean;
- if (has_unstaged_changes(1))
+ if (has_unstaged_changes(r, 1))
return error(_("cannot rebase: You have unstaged changes."));
- is_clean = !has_uncommitted_changes(0);
+ is_clean = !has_uncommitted_changes(r, 0);
if (file_exists(rebase_path_amend())) {
struct strbuf rev = STRBUF_INIT;
struct commit *commit;
const char *path = rebase_path_squash_msg();
- if (parse_head(&commit) ||
+ if (parse_head(r, &commit) ||
!(p = get_commit_buffer(commit, NULL)) ||
write_message(p, strlen(p), path, 0)) {
unuse_commit_buffer(commit, p);
}
if (is_clean) {
- const char *cherry_pick_head = git_path_cherry_pick_head(the_repository);
+ const char *cherry_pick_head = git_path_cherry_pick_head(r);
if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
return error(_("could not remove CHERRY_PICK_HEAD"));
return 0;
}
- if (run_git_commit(final_fixup ? NULL : rebase_path_message(),
+ if (run_git_commit(r, final_fixup ? NULL : rebase_path_message(),
opts, flags))
return error(_("could not commit staged changes."));
unlink(rebase_path_amend());
+ unlink(git_path_merge_head(the_repository));
if (final_fixup) {
unlink(rebase_path_fixup_msg());
unlink(rebase_path_squash_msg());
return 0;
}
- int sequencer_continue(struct replay_opts *opts)
+ int sequencer_continue(struct repository *r, struct replay_opts *opts)
{
struct todo_list todo_list = TODO_LIST_INIT;
int res;
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
if (read_populate_opts(opts))
return -1;
if (is_rebase_i(opts)) {
- if ((res = read_populate_todo(&todo_list, opts)))
+ if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
- if (commit_staged_changes(opts, &todo_list))
+ if (commit_staged_changes(r, opts, &todo_list))
return -1;
} else if (!file_exists(get_todo_path(opts)))
- return continue_single_pick();
- else if ((res = read_populate_todo(&todo_list, opts)))
+ return continue_single_pick(r);
+ else if ((res = read_populate_todo(r, &todo_list, opts)))
goto release_todo_list;
if (!is_rebase_i(opts)) {
/* Verify that the conflict has been resolved */
- if (file_exists(git_path_cherry_pick_head(the_repository)) ||
- file_exists(git_path_revert_head(the_repository))) {
- res = continue_single_pick();
+ if (file_exists(git_path_cherry_pick_head(r)) ||
+ file_exists(git_path_revert_head(r))) {
+ res = continue_single_pick(r);
if (res)
goto release_todo_list;
}
- if (index_differs_from("HEAD", NULL, 0)) {
- res = error_dirty_index(opts);
+ if (index_differs_from(r, "HEAD", NULL, 0)) {
+ res = error_dirty_index(r->index, opts);
goto release_todo_list;
}
todo_list.current++;
strbuf_release(&buf);
}
- res = pick_commits(&todo_list, opts);
+ res = pick_commits(r, &todo_list, opts);
release_todo_list:
todo_list_release(&todo_list);
return res;
}
- static int single_pick(struct commit *cmit, struct replay_opts *opts)
+ static int single_pick(struct repository *r,
+ struct commit *cmit,
+ struct replay_opts *opts)
{
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
- return do_pick_commit(opts->action == REPLAY_PICK ?
+ return do_pick_commit(r, opts->action == REPLAY_PICK ?
TODO_PICK : TODO_REVERT, cmit, opts, 0);
}
- int sequencer_pick_revisions(struct replay_opts *opts)
+ int sequencer_pick_revisions(struct repository *r,
+ struct replay_opts *opts)
{
struct todo_list todo_list = TODO_LIST_INIT;
struct object_id oid;
int i, res;
assert(opts->revs);
- if (read_and_refresh_cache(opts))
+ if (read_and_refresh_cache(r, opts))
return -1;
for (i = 0; i < opts->revs->pending.nr; i++) {
continue;
if (!get_oid(name, &oid)) {
- if (!lookup_commit_reference_gently(the_repository, &oid, 1)) {
- enum object_type type = oid_object_info(the_repository,
+ if (!lookup_commit_reference_gently(r, &oid, 1)) {
+ enum object_type type = oid_object_info(r,
&oid,
NULL);
return error(_("%s: can't cherry-pick a %s"),
return error(_("empty commit set passed"));
if (get_revision(opts->revs))
BUG("unexpected extra commit from walk");
- return single_pick(cmit, opts);
+ return single_pick(r, cmit, opts);
}
/*
if (save_opts(opts))
return -1;
update_abort_safety_file();
- res = pick_commits(&todo_list, opts);
+ res = pick_commits(r, &todo_list, opts);
todo_list_release(&todo_list);
return res;
}
return 0;
}
- int sequencer_make_script(FILE *out, int argc, const char **argv,
+ int sequencer_make_script(struct repository *r, FILE *out,
+ int argc, const char **argv,
unsigned flags)
{
char *format = NULL;
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
- repo_init_revisions(the_repository, &revs, NULL);
+ repo_init_revisions(r, &revs, NULL);
revs.verbose_header = 1;
if (!rebase_merges)
revs.max_parents = 1;
* Add commands after pick and (series of) squash/fixup commands
* in the todo list.
*/
- int sequencer_add_exec_commands(const char *commands)
+ int sequencer_add_exec_commands(struct repository *r,
+ const char *commands)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
return i;
}
- int transform_todos(unsigned flags)
+ int transform_todos(struct repository *r, unsigned flags)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list)) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
* Check if there is an unrecognized command or a
* bad SHA-1 in a command.
*/
- int check_todo_list(void)
+ int check_todo_list(struct repository *r)
{
enum missing_commit_check_level check_level = get_missing_commit_check_level();
struct strbuf todo_file = STRBUF_INIT;
goto leave_check;
}
advise_to_edit_todo = res =
- parse_insn_buffer(todo_list.buf.buf, &todo_list);
+ parse_insn_buffer(r, todo_list.buf.buf, &todo_list);
if (res || check_level == MISSING_COMMIT_CHECK_IGNORE)
goto leave_check;
goto leave_check;
}
strbuf_release(&todo_file);
- res = !!parse_insn_buffer(todo_list.buf.buf, &todo_list);
+ res = !!parse_insn_buffer(r, todo_list.buf.buf, &todo_list);
/* Find commits in git-rebase-todo.backup yet unseen */
for (i = todo_list.nr - 1; i >= 0; i--) {
}
/* skip picking commits whose parents are unchanged */
- static int skip_unnecessary_picks(struct object_id *output_oid)
+ static int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid)
{
const char *todo_file = rebase_path_todo();
struct strbuf buf = STRBUF_INIT;
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
return -1;
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
todo_list_release(&todo_list);
return -1;
}
return 0;
}
- int complete_action(struct replay_opts *opts, unsigned flags,
+ int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
const char *onto, const char *orig_head, const char *cmd,
unsigned autosquash)
write_message("noop\n", 5, todo_file, 0))
return -1;
- if (autosquash && rearrange_squash())
+ if (autosquash && rearrange_squash(r))
return -1;
if (cmd && *cmd)
- sequencer_add_exec_commands(cmd);
+ sequencer_add_exec_commands(r, cmd);
if (strbuf_read_file(buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- if (parse_insn_buffer(buf->buf, &todo_list)) {
+ if (parse_insn_buffer(r, buf->buf, &todo_list)) {
todo_list_release(&todo_list);
return error(_("unusable todo list: '%s'"), todo_file);
}
return error(_("could not copy '%s' to '%s'."), todo_file,
rebase_path_todo_backup());
- if (transform_todos(flags | TODO_LIST_SHORTEN_IDS))
+ if (transform_todos(r, flags | TODO_LIST_SHORTEN_IDS))
return error(_("could not transform the todo list"));
strbuf_reset(buf);
todo_list_release(&todo_list);
- if (check_todo_list()) {
+ if (check_todo_list(r)) {
checkout_onto(opts, onto_name, onto, orig_head);
return -1;
}
- if (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))
+ if (transform_todos(r, flags & ~(TODO_LIST_SHORTEN_IDS)))
return error(_("could not transform the todo list"));
- if (opts->allow_ff && skip_unnecessary_picks(&oid))
+ if (opts->allow_ff && skip_unnecessary_picks(r, &oid))
return error(_("could not skip unnecessary pick commands"));
if (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))
return -1;
-;
+
- if (require_clean_work_tree("rebase", "", 1, 1))
+ if (require_clean_work_tree(r, "rebase", "", 1, 1))
return -1;
- return sequencer_continue(opts);
+ return sequencer_continue(r, opts);
}
struct subject2item_entry {
* message will have to be retrieved from the commit (as the oneline in the
* script cannot be trusted) in order to normalize the autosquash arrangement.
*/
- int rearrange_squash(void)
+ int rearrange_squash(struct repository *r)
{
const char *todo_file = rebase_path_todo();
struct todo_list todo_list = TODO_LIST_INIT;
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
return -1;
- if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) {
+ if (parse_insn_buffer(r, todo_list.buf.buf, &todo_list) < 0) {
todo_list_release(&todo_list);
return -1;
}
#include "strbuf.h"
struct commit;
+ struct repository;
const char *git_path_commit_editmsg(void);
const char *git_path_seq_dir(void);
/* Call this to setup defaults before parsing command line options */
void sequencer_init_config(struct replay_opts *opts);
- int sequencer_pick_revisions(struct replay_opts *opts);
- int sequencer_continue(struct replay_opts *opts);
- int sequencer_rollback(struct replay_opts *opts);
+ int sequencer_pick_revisions(struct repository *repo,
+ struct replay_opts *opts);
+ int sequencer_continue(struct repository *repo, struct replay_opts *opts);
+ int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
int sequencer_remove_state(struct replay_opts *opts);
#define TODO_LIST_KEEP_EMPTY (1U << 0)
* commits should be rebased onto the new base, this flag needs to be passed.
*/
#define TODO_LIST_REBASE_COUSINS (1U << 4)
- int sequencer_make_script(FILE *out, int argc, const char **argv,
+ int sequencer_make_script(struct repository *repo, FILE *out,
+ int argc, const char **argv,
unsigned flags);
- int sequencer_add_exec_commands(const char *command);
- int transform_todos(unsigned flags);
+ int sequencer_add_exec_commands(struct repository *r, const char *command);
+ int transform_todos(struct repository *r, unsigned flags);
enum missing_commit_check_level get_missing_commit_check_level(void);
- int check_todo_list(void);
- int complete_action(struct replay_opts *opts, unsigned flags,
+ int check_todo_list(struct repository *r);
+ int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
const char *shortrevisions, const char *onto_name,
const char *onto, const char *orig_head, const char *cmd,
unsigned autosquash);
- int rearrange_squash(void);
+ int rearrange_squash(struct repository *r);
extern const char sign_off_header[];
*/
void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
- void append_conflicts_hint(struct strbuf *msgbuf);
+ void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
int message_is_empty(const struct strbuf *sb,
enum commit_msg_cleanup_mode cleanup_mode);
int template_untouched(const struct strbuf *sb, const char *template_file,
#define SUMMARY_INITIAL_COMMIT (1 << 0)
#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
- void print_commit_summary(const char *prefix, const struct object_id *oid,
+ void print_commit_summary(struct repository *repo,
+ const char *prefix,
+ const struct object_id *oid,
unsigned int flags);
+
+int read_author_script(const char *path, char **name, char **email, char **date,
+ int allow_missing);
#endif
void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
va_end(ap);
}
- void wt_status_prepare(struct wt_status *s)
+ void wt_status_prepare(struct repository *r, struct wt_status *s)
{
memset(s, 0, sizeof(*s));
+ s->repo = r;
memcpy(s->color_palette, default_wt_status_colors,
sizeof(default_wt_status_colors));
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
}
}
- static int unmerged_mask(const char *path)
+ static int unmerged_mask(struct index_state *istate, const char *path)
{
int pos, mask;
const struct cache_entry *ce;
- pos = cache_name_pos(path, strlen(path));
+ pos = index_name_pos(istate, path, strlen(path));
if (0 <= pos)
return 0;
mask = 0;
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
if (strcmp(ce->name, path) || !ce_stage(ce))
break;
mask |= (1 << (ce_stage(ce) - 1));
s->committable = 1;
break;
case DIFF_STATUS_UNMERGED:
- d->stagemask = unmerged_mask(p->two->path);
+ d->stagemask = unmerged_mask(s->repo->index,
+ p->two->path);
/*
* Don't bother setting {mode,oid}_{head,index} since the print
* code will output the stage values directly and not use the
{
struct rev_info rev;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.flags.dirty_submodules = 1;
struct rev_info rev;
struct setup_revision_opt opt;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
memset(&opt, 0, sizeof(opt));
opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
setup_revisions(0, NULL, &rev, &opt);
static void wt_status_collect_changes_initial(struct wt_status *s)
{
+ struct index_state *istate = s->repo->index;
int i;
- for (i = 0; i < active_nr; i++) {
+ for (i = 0; i < istate->cache_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
- const struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = istate->cache[i];
- if (!ce_path_match(&the_index, ce, &s->pathspec, NULL))
+ if (!ce_path_match(istate, ce, &s->pathspec, NULL))
continue;
if (ce_intent_to_add(ce))
continue;
int i;
struct dir_struct dir;
uint64_t t_begin = getnanotime();
+ struct index_state *istate = s->repo->index;
if (!s->show_untracked_files)
return;
if (s->show_ignored_mode == SHOW_MATCHING_IGNORED)
dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
} else {
- dir.untracked = the_index.untracked;
+ dir.untracked = istate->untracked;
}
setup_standard_excludes(&dir);
- fill_directory(&dir, &the_index, &s->pathspec);
+ fill_directory(&dir, istate, &s->pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len) &&
+ dir_path_match(istate, ent, &s->pathspec, 0, NULL))
string_list_insert(&s->untracked, ent->name);
free(ent);
}
for (i = 0; i < dir.ignored_nr; i++) {
struct dir_entry *ent = dir.ignored[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len) &&
+ dir_path_match(istate, ent, &s->pathspec, 0, NULL))
string_list_insert(&s->ignored, ent->name);
free(ent);
}
wt_status_collect_changes_index(s);
wt_status_collect_untracked(s);
- wt_status_get_state(&s->state, s->branch && !strcmp(s->branch, "HEAD"));
+ wt_status_get_state(s->repo, &s->state, s->branch && !strcmp(s->branch, "HEAD"));
if (s->state.merge_in_progress && !has_unmerged(s))
s->committable = 1;
}
int dirty_submodules;
const char *c = color(WT_STATUS_HEADER, s);
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
rev.diffopt.flags.allow_textconv = 1;
rev.diffopt.ita_invisible_in_index = 1;
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
} else if (s->state.rebase_in_progress ||
- !stat(git_path_merge_msg(the_repository), &st)) {
+ !stat(git_path_merge_msg(s->repo), &st)) {
print_rebase_state(s, color);
if (s->hints)
status_printf_ln(s, color,
return 1;
}
- static void wt_status_get_detached_from(struct wt_status_state *state)
+ static void wt_status_get_detached_from(struct repository *r,
+ struct wt_status_state *state)
{
struct grab_1st_switch_cbdata cb;
struct commit *commit;
/* sha1 is a commit? match without further lookup */
(oideq(&cb.noid, &oid) ||
/* perhaps sha1 is a tag, try to dereference to a commit */
- ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL &&
+ ((commit = lookup_commit_reference_gently(r, &oid, 1)) != NULL &&
oideq(&cb.noid, &commit->object.oid)))) {
const char *from = ref;
if (!skip_prefix(from, "refs/tags/", &from))
return 0;
}
- void wt_status_get_state(struct wt_status_state *state,
+ void wt_status_get_state(struct repository *r,
+ struct wt_status_state *state,
int get_detached_from)
{
struct stat st;
struct object_id oid;
- if (!stat(git_path_merge_head(the_repository), &st)) {
+ if (!stat(git_path_merge_head(r), &st)) {
+ wt_status_check_rebase(NULL, state);
state->merge_in_progress = 1;
} else if (wt_status_check_rebase(NULL, state)) {
; /* all set */
- } else if (!stat(git_path_cherry_pick_head(the_repository), &st) &&
+ } else if (!stat(git_path_cherry_pick_head(r), &st) &&
!get_oid("CHERRY_PICK_HEAD", &oid)) {
state->cherry_pick_in_progress = 1;
oidcpy(&state->cherry_pick_head_oid, &oid);
}
wt_status_check_bisect(NULL, state);
- if (!stat(git_path_revert_head(the_repository), &st) &&
+ if (!stat(git_path_revert_head(r), &st) &&
!get_oid("REVERT_HEAD", &oid)) {
state->revert_in_progress = 1;
oidcpy(&state->revert_head_oid, &oid);
}
if (get_detached_from)
- wt_status_get_detached_from(state);
+ wt_status_get_detached_from(r, state);
}
static void wt_longstatus_print_state(struct wt_status *s)
const char *state_color = color(WT_STATUS_HEADER, s);
struct wt_status_state *state = &s->state;
- if (state->merge_in_progress)
+ if (state->merge_in_progress) {
+ if (state->rebase_interactive_in_progress) {
+ show_rebase_information(s, state_color);
+ fputs("\n", s->fp);
+ }
show_merge_in_progress(s, state_color);
- else if (state->am_in_progress)
+ } else if (state->am_in_progress)
show_am_in_progress(s, state_color);
else if (state->rebase_in_progress || state->rebase_interactive_in_progress)
show_rebase_in_progress(s, state_color);
struct wt_status *s)
{
struct wt_status_change_data *d = it->util;
+ struct index_state *istate = s->repo->index;
const struct cache_entry *ce;
struct strbuf buf_index = STRBUF_INIT;
const char *path_index = NULL;
*/
memset(stages, 0, sizeof(stages));
sum = 0;
- pos = cache_name_pos(it->string, strlen(it->string));
+ pos = index_name_pos(istate, it->string, strlen(it->string));
assert(pos < 0);
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
stage = ce_stage(ce);
if (strcmp(ce->name, it->string) || !stage)
break;
/**
* Returns 1 if there are unstaged changes, 0 otherwise.
*/
- int has_unstaged_changes(int ignore_submodules)
+ int has_unstaged_changes(struct repository *r, int ignore_submodules)
{
struct rev_info rev_info;
int result;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules) {
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.override_submodule_config = 1;
/**
* Returns 1 if there are uncommitted changes, 0 otherwise.
*/
- int has_uncommitted_changes(int ignore_submodules)
+ int has_uncommitted_changes(struct repository *r,
+ int ignore_submodules)
{
struct rev_info rev_info;
int result;
- if (is_cache_unborn())
+ if (is_index_unborn(r->index))
return 0;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules)
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.quick = 1;
* We have no head (or it's corrupt); use the empty tree,
* which will complain if the index is non-empty.
*/
- struct tree *tree = lookup_tree(the_repository, the_hash_algo->empty_tree);
+ struct tree *tree = lookup_tree(r, the_hash_algo->empty_tree);
add_pending_object(&rev_info, &tree->object, "");
}
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
- int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently)
+ int require_clean_work_tree(struct repository *r,
+ const char *action,
+ const char *hint,
+ int ignore_submodules,
+ int gently)
{
struct lock_file lock_file = LOCK_INIT;
int err = 0, fd;
fd = hold_locked_index(&lock_file, 0);
- refresh_cache(REFRESH_QUIET);
+ refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
- update_index_if_able(&the_index, &lock_file);
+ update_index_if_able(r->index, &lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(ignore_submodules)) {
+ if (has_unstaged_changes(r, ignore_submodules)) {
/* TRANSLATORS: the action is e.g. "pull with rebase" */
error(_("cannot %s: You have unstaged changes."), _(action));
err = 1;
}
- if (has_uncommitted_changes(ignore_submodules)) {
+ if (has_uncommitted_changes(r, ignore_submodules)) {
if (err)
error(_("additionally, your index contains uncommitted changes."));
else