* Based on git-merge.sh by Junio C Hamano.
*/
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
#include "parse-options.h"
#include "run-command.h"
#include "diff.h"
#include "refs.h"
+#include "refspec.h"
#include "commit.h"
#include "diffcore.h"
#include "revision.h"
#include "string-list.h"
#include "packfile.h"
#include "tag.h"
+#include "alias.h"
+#include "commit-reach.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
return 0;
}
+static int option_read_message(struct parse_opt_ctx_t *ctx,
+ const struct option *opt, int unset)
+{
+ struct strbuf *buf = opt->value;
+ const char *arg;
+
+ if (unset)
+ BUG("-F cannot be negated");
+
+ if (ctx->opt) {
+ arg = ctx->opt;
+ ctx->opt = NULL;
+ } else if (ctx->argc > 1) {
+ ctx->argc--;
+ arg = *++ctx->argv;
+ } else
+ return error(_("option `%s' requires a value"), opt->long_name);
+
+ if (buf->len)
+ strbuf_addch(buf, '\n');
+ if (ctx->prefix && !is_absolute_path(arg))
+ arg = prefix_filename(ctx->prefix, arg);
+ if (strbuf_read_file(buf, arg, 0) < 0)
+ return error(_("could not read file '%s'"), arg);
+ have_message = 1;
+
+ return 0;
+}
+
static struct strategy *get_strategy(const char *name)
{
int i;
static int option_parse_n(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
show_diffstat = unset;
return 0;
}
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
- { OPTION_SET_INT, 0, "ff-only", &fast_forward, NULL,
- N_("abort if fast-forward is not possible"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
+ OPT_SET_INT_F(0, "ff-only", &fast_forward,
+ N_("abort if fast-forward is not possible"),
+ FF_ONLY, PARSE_OPT_NONEG),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
+ { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
+ N_("read message from file"), PARSE_OPT_NONEG,
+ (parse_opt_cb *) option_read_message },
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "abort", &abort_current_merge,
N_("abort the current in-progress merge")),
return rc;
}
-static void read_empty(unsigned const char *sha1, int verbose)
+static void read_empty(const struct object_id *oid, int verbose)
{
int i = 0;
const char *args[7];
args[i++] = "-v";
args[i++] = "-m";
args[i++] = "-u";
- args[i++] = EMPTY_TREE_SHA1_HEX;
- args[i++] = sha1_to_hex(sha1);
+ args[i++] = empty_tree_oid_hex();
+ args[i++] = oid_to_hex(oid);
args[i] = NULL;
if (run_command_v_opt(args, RUN_GIT_CMD))
die(_("read-tree failed"));
}
-static void reset_hard(unsigned const char *sha1, int verbose)
+static void reset_hard(const struct object_id *oid, int verbose)
{
int i = 0;
const char *args[6];
args[i++] = "-v";
args[i++] = "--reset";
args[i++] = "-u";
- args[i++] = sha1_to_hex(sha1);
+ args[i++] = oid_to_hex(oid);
args[i] = NULL;
if (run_command_v_opt(args, RUN_GIT_CMD))
if (is_null_oid(stash))
return;
- reset_hard(head->hash, 1);
+ reset_hard(head, 1);
args[2] = oid_to_hex(stash);
printf(_("Squash commit -- not updating HEAD\n"));
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
rev.ignore_merges = 1;
rev.commit_format = CMIT_FMT_MEDIUM;
}
if (new_head && show_diffstat) {
struct diff_options opts;
- diff_setup(&opts);
+ repo_diff_setup(the_repository, &opts);
opts.stat_width = -1; /* use full terminal width */
opts.stat_graph_width = -1; /* respect statGraphWidth config */
opts.output_format |=
struct object_id branch_head;
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
+ struct merge_remote_desc *desc;
const char *ptr;
char *found_ref;
int len, early;
strbuf_release(&truname);
}
- if (remote_head->util) {
- struct merge_remote_desc *desc;
- desc = merge_remote_util(remote_head);
- if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
- strbuf_addf(msg, "%s\t\t%s '%s'\n",
- oid_to_hex(&desc->obj->oid),
- type_name(desc->obj->type),
- remote);
- goto cleanup;
- }
+ desc = merge_remote_util(remote_head);
+ if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
+ strbuf_addf(msg, "%s\t\t%s '%s'\n",
+ oid_to_hex(&desc->obj->oid),
+ type_name(desc->obj->type),
+ remote);
+ goto cleanup;
}
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
argc = split_cmdline(bmo, &argv);
if (argc < 0)
die(_("Bad branch.%s.mergeoptions string: %s"), branch,
- split_cmdline_strerror(argc));
+ _(split_cmdline_strerror(argc)));
REALLOC_ARRAY(argv, argc + 2);
MOVE_ARRAY(argv + 1, argv, argc + 1);
argc++;
struct commit_list *remoteheads,
struct commit *head)
{
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
const char *head_arg = "HEAD";
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
return 2;
}
- init_merge_options(&o);
+ init_merge_options(&o, the_repository);
if (!strcmp(strategy, "subtree"))
o.subtree_shift = "";
exit(128);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die (_("unable to write %s"), get_index_file());
+ die(_("unable to write %s"), get_index_file());
return clean ? 0 : 1;
} else {
- return try_merge_command(strategy, xopts_nr, xopts,
- common, head_arg, remoteheads);
+ return try_merge_command(the_repository,
+ strategy, xopts_nr, xopts,
+ common, head_arg, remoteheads);
}
}
{
struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
- static struct lock_file lock;
+ struct lock_file lock = LOCK_INIT;
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
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);
- rerere(allow_rerere_auto);
+ repo_rerere(the_repository, allow_rerere_auto);
printf(_("Automatic merge failed; "
"fix conflicts and then commit the result.\n"));
return 1;
struct rev_info rev;
/* Check how many files differ. */
- init_revisions(&rev, "");
+ repo_init_revisions(the_repository, &rev, "");
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |=
DIFF_FORMAT_CALLBACK;
for (j = remoteheads; j; j = j->next) {
struct object_id *oid;
struct commit *c = j->item;
- if (c->util && merge_remote_util(c)->obj) {
- oid = &merge_remote_util(c)->obj->oid;
+ struct merge_remote_desc *desc;
+
+ desc = merge_remote_util(c);
+ if (desc && desc->obj) {
+ oid = &desc->obj->oid;
} else {
oid = &c->object.oid;
}
const char *filename;
int fd, pos, npos;
struct strbuf fetch_head_file = STRBUF_INIT;
+ const unsigned hexsz = the_hash_algo->hexsz;
if (!merge_names)
merge_names = &fetch_head_file;
else
npos = merge_names->len;
- if (npos - pos < GIT_SHA1_HEXSZ + 2 ||
+ if (npos - pos < hexsz + 2 ||
get_oid_hex(merge_names->buf + pos, &oid))
commit = NULL; /* bad */
- else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2))
+ else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
continue; /* not-for-merge */
else {
- char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ];
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0';
+ char saved = merge_names->buf[pos + hexsz];
+ merge_names->buf[pos + hexsz] = '\0';
commit = get_merge_parent(merge_names->buf + pos);
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved;
+ merge_names->buf[pos + hexsz] = saved;
}
if (!commit) {
if (ptr)
tag_ref = xstrfmt("refs/tags/%s",
((struct tag *)merge_remote_util(commit)->obj)->tag);
if (!read_ref(tag_ref, &oid) &&
- !oidcmp(&oid, &merge_remote_util(commit)->obj->oid))
+ oideq(&oid, &merge_remote_util(commit)->obj->oid))
is_throwaway_tag = 0;
else
is_throwaway_tag = 1;
branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (branch)
skip_prefix(branch, "refs/heads/", &branch);
+
+ init_diff_ui_defaults();
+ git_config(git_merge_config, NULL);
+
if (!branch || is_null_oid(&head_oid))
head_commit = NULL;
else
head_commit = lookup_commit_or_die(&head_oid, "HEAD");
- init_diff_ui_defaults();
- git_config(git_merge_config, NULL);
-
if (branch_mergeoptions)
parse_branch_merge_options(branch_mergeoptions);
argc = parse_options(argc, argv, prefix, builtin_merge_options,
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->hash, 0);
+ read_empty(remote_head_oid, 0);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
goto done;
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);
}
}
goto done;
} else if (fast_forward != FF_NO && !remoteheads->next &&
!common->next &&
- !oidcmp(&common->item->object.oid, &head_commit->object.oid)) {
+ oideq(&common->item->object.oid, &head_commit->object.oid)) {
/* Again the most common case of merging one remote. */
struct strbuf msg = STRBUF_INIT;
struct commit *commit;
goto done;
}
- if (checkout_fast_forward(&head_commit->object.oid,
+ if (checkout_fast_forward(the_repository,
+ &head_commit->object.oid,
&commit->object.oid,
overwrite_ignore)) {
ret = 1;
* HEAD^^" would be missed.
*/
common_one = get_merge_bases(head_commit, j->item);
- if (oidcmp(&common_one->item->object.oid, &j->item->object.oid)) {
+ if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
up_to_date = 0;
break;
}