#include "dir.h"
#include "submodule.h"
+static void flush_output(struct merge_options *o)
+{
+ if (o->buffer_output < 2 && o->obuf.len) {
+ fputs(o->obuf.buf, stdout);
+ strbuf_reset(&o->obuf);
+ }
+}
+
+static int err(struct merge_options *o, const char *err, ...)
+{
+ va_list params;
+
+ if (o->buffer_output < 2)
+ flush_output(o);
+ else {
+ strbuf_complete(&o->obuf, '\n');
+ strbuf_addstr(&o->obuf, "error: ");
+ }
+ va_start(params, err);
+ strbuf_vaddf(&o->obuf, err, params);
+ va_end(params);
+ if (o->buffer_output > 1)
+ strbuf_addch(&o->obuf, '\n');
+ else {
+ error("%s", o->obuf.buf);
+ strbuf_reset(&o->obuf);
+ }
+
+ return -1;
+}
+
static struct tree *shift_tree_object(struct tree *one, struct tree *two,
const char *subtree_shift)
{
static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
{
struct commit *commit = alloc_commit_node();
- struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
- desc->name = comment;
- desc->obj = (struct object *)commit;
+ set_merge_remote_desc(commit, comment, (struct object *)commit);
commit->tree = tree;
- commit->util = desc;
commit->object.parsed = 1;
return commit;
}
return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5;
}
-static void flush_output(struct merge_options *o)
-{
- if (o->obuf.len) {
- fputs(o->obuf.buf, stdout);
- strbuf_reset(&o->obuf);
- }
-}
-
__attribute__((format (printf, 3, 4)))
static void output(struct merge_options *o, int v, const char *fmt, ...)
{
static void output_commit_title(struct merge_options *o, struct commit *commit)
{
- int i;
- flush_output(o);
- for (i = o->call_depth; i--;)
- fputs(" ", stdout);
+ strbuf_addchars(&o->obuf, ' ', o->call_depth * 2);
if (commit->util)
- printf("virtual %s\n", merge_remote_util(commit)->name);
+ strbuf_addf(&o->obuf, "virtual %s\n",
+ merge_remote_util(commit)->name);
else {
- printf("%s ", find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
+ strbuf_addf(&o->obuf, "%s ",
+ find_unique_abbrev(commit->object.oid.hash,
+ DEFAULT_ABBREV));
if (parse_commit(commit) != 0)
- printf(_("(bad commit)\n"));
+ strbuf_addf(&o->obuf, _("(bad commit)\n"));
else {
const char *title;
const char *msg = get_commit_buffer(commit, NULL);
int len = find_commit_subject(msg, &title);
if (len)
- printf("%.*s\n", len, title);
+ strbuf_addf(&o->obuf, "%.*s\n", len, title);
unuse_commit_buffer(commit, msg);
}
}
+ flush_output(o);
}
-static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
+static int add_cacheinfo(struct merge_options *o,
+ unsigned int mode, const struct object_id *oid,
const char *path, int stage, int refresh, int options)
{
struct cache_entry *ce;
ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);
if (!ce)
- return error(_("addinfo_cache failed for path '%s'"), path);
+ return err(o, _("addinfo_cache failed for path '%s'"), path);
ret = add_cache_entry(ce, options);
if (refresh) {
if (!cache_tree_fully_valid(active_cache_tree) &&
cache_tree_update(&the_index, 0) < 0) {
- error(_("error building trees"));
+ err(o, _("error building trees"));
return NULL;
}
* and the file need to be present, then the D/F file will be
* reinstated with a new unique name at the time it is processed.
*/
- struct string_list df_sorted_entries;
+ struct string_list df_sorted_entries = STRING_LIST_INIT_NODUP;
const char *last_file = NULL;
int last_len = 0;
int i;
return;
/* Ensure D/F conflicts are adjacent in the entries list. */
- memset(&df_sorted_entries, 0, sizeof(struct string_list));
for (i = 0; i < entries->nr; i++) {
struct string_list_item *next = &entries->items[i];
string_list_append(&df_sorted_entries, next->string)->util =
return renames;
}
-static int update_stages(const char *path, const struct diff_filespec *o,
+static int update_stages(struct merge_options *opt, const char *path,
+ const struct diff_filespec *o,
const struct diff_filespec *a,
const struct diff_filespec *b)
{
if (remove_file_from_cache(path))
return -1;
if (o)
- if (add_cacheinfo(o->mode, &o->oid, path, 1, 0, options))
+ if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))
return -1;
if (a)
- if (add_cacheinfo(a->mode, &a->oid, path, 2, 0, options))
+ if (add_cacheinfo(opt, a->mode, &a->oid, path, 2, 0, options))
return -1;
if (b)
- if (add_cacheinfo(b->mode, &b->oid, path, 3, 0, options))
+ if (add_cacheinfo(opt, b->mode, &b->oid, path, 3, 0, options))
return -1;
return 0;
}
if (status) {
if (status == SCLD_EXISTS)
/* something else exists */
- return error(msg, path, _(": perhaps a D/F conflict?"));
- return error(msg, path, "");
+ return err(o, msg, path, _(": perhaps a D/F conflict?"));
+ return err(o, msg, path, "");
}
/*
* tracking it.
*/
if (would_lose_untracked(path))
- return error(_("refusing to lose untracked file at '%s'"),
+ return err(o, _("refusing to lose untracked file at '%s'"),
path);
/* Successful unlink is good.. */
if (errno == ENOENT)
return 0;
/* .. but not some other error (who really cares what?) */
- return error(msg, path, _(": perhaps a D/F conflict?"));
+ return err(o, msg, path, _(": perhaps a D/F conflict?"));
}
static int update_file_flags(struct merge_options *o,
buf = read_sha1_file(oid->hash, &type, &size);
if (!buf)
- return error(_("cannot read object %s '%s'"), oid_to_hex(oid), path);
+ return err(o, _("cannot read object %s '%s'"), oid_to_hex(oid), path);
if (type != OBJ_BLOB) {
- ret = error(_("blob expected for %s '%s'"), oid_to_hex(oid), path);
+ ret = err(o, _("blob expected for %s '%s'"), oid_to_hex(oid), path);
goto free_buf;
}
if (S_ISREG(mode)) {
mode = 0666;
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
if (fd < 0) {
- ret = error_errno(_("failed to open '%s'"),
- path);
+ ret = err(o, _("failed to open '%s': %s"),
+ path, strerror(errno));
goto free_buf;
}
write_in_full(fd, buf, size);
safe_create_leading_directories_const(path);
unlink(path);
if (symlink(lnk, path))
- ret = error_errno(_("failed to symlink '%s'"), path);
+ ret = err(o, _("failed to symlink '%s': %s"),
+ path, strerror(errno));
free(lnk);
} else
- ret = error(_("do not know what to do with %06o %s '%s'"),
- mode, oid_to_hex(oid), path);
+ ret = err(o,
+ _("do not know what to do with %06o %s '%s'"),
+ mode, oid_to_hex(oid), path);
free_buf:
free(buf);
}
update_index:
if (!ret && update_cache)
- add_cacheinfo(mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
+ add_cacheinfo(o, mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
return ret;
}
branch1, branch2);
if ((merge_status < 0) || !result_buf.ptr)
- ret = error(_("Failed to execute internal merge"));
+ ret = err(o, _("Failed to execute internal merge"));
if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
blob_type, result->oid.hash))
- ret = error(_("Unable to add %s to database"),
- a->path);
+ ret = err(o, _("Unable to add %s to database"),
+ a->path);
free(result_buf.ptr);
if (ret)
if (o->call_depth)
return remove_file_from_cache(dest->path);
else
- return update_stages(dest->path, NULL,
+ return update_stages(o, dest->path, NULL,
rename_branch == o->branch1 ? dest : NULL,
rename_branch == o->branch1 ? NULL : dest);
}
if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
; /* fall through, do allow dst_name to be released */
else if (stage == 2)
- ret = update_stages(rename->path, NULL, rename, add);
+ ret = update_stages(o, rename->path, NULL, rename, add);
else
- ret = update_stages(rename->path, NULL, add, rename);
+ ret = update_stages(o, rename->path, NULL, add, rename);
if (dst_name != rename->path)
free(dst_name);
return (is_null_oid(oid) || mode == 0) ? NULL: (struct object_id *)oid;
}
-static int read_oid_strbuf(const struct object_id *oid, struct strbuf *dst)
+static int read_oid_strbuf(struct merge_options *o,
+ const struct object_id *oid, struct strbuf *dst)
{
void *buf;
enum object_type type;
unsigned long size;
buf = read_sha1_file(oid->hash, &type, &size);
if (!buf)
- return error(_("cannot read object %s"), oid_to_hex(oid));
+ return err(o, _("cannot read object %s"), oid_to_hex(oid));
if (type != OBJ_BLOB) {
free(buf);
- return error(_("object %s is not a blob"), oid_to_hex(oid));
+ return err(o, _("object %s is not a blob"), oid_to_hex(oid));
}
strbuf_attach(dst, buf, size, size + 1);
return 0;
}
-static int blob_unchanged(const struct object_id *o_oid,
+static int blob_unchanged(struct merge_options *opt,
+ const struct object_id *o_oid,
unsigned o_mode,
const struct object_id *a_oid,
unsigned a_mode,
return 0;
assert(o_oid && a_oid);
- if (read_oid_strbuf(o_oid, &o) || read_oid_strbuf(a_oid, &a))
+ if (read_oid_strbuf(opt, o_oid, &o) || read_oid_strbuf(opt, a_oid, &a))
goto error_return;
/*
* Note: binary | is used so that both renormalizations are
*/
path_renamed_outside_HEAD = !path2 || !strcmp(path, path2);
if (!path_renamed_outside_HEAD) {
- add_cacheinfo(mfi.mode, &mfi.oid, path,
+ add_cacheinfo(o, mfi.mode, &mfi.oid, path,
0, (!o->call_depth), 0);
return mfi.clean;
}
output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
reason, path);
if (rename_conflict_info && !df_conflict_remains)
- if (update_stages(path, &one, &a, &b))
+ if (update_stages(o, path, &one, &a, &b))
return -1;
}
remove_file_from_cache(path);
} else {
if (!mfi.clean) {
- if (update_stages(path, &one, &a, &b))
+ if (update_stages(o, path, &one, &a, &b))
return -1;
} else {
int file_from_stage2 = was_tracked(path);
oidcpy(&merged.oid, &mfi.oid);
merged.mode = mfi.mode;
- if (update_stages(path, NULL,
+ if (update_stages(o, path, NULL,
file_from_stage2 ? &merged : NULL,
file_from_stage2 ? NULL : &merged))
return -1;
} else if (o_oid && (!a_oid || !b_oid)) {
/* Case A: Deleted in one */
if ((!a_oid && !b_oid) ||
- (!b_oid && blob_unchanged(o_oid, o_mode, a_oid, a_mode, normalize, path)) ||
- (!a_oid && blob_unchanged(o_oid, o_mode, b_oid, b_mode, normalize, path))) {
+ (!b_oid && blob_unchanged(o, o_oid, o_mode, a_oid, a_mode, normalize, path)) ||
+ (!a_oid && blob_unchanged(o, o_oid, o_mode, b_oid, b_mode, normalize, path))) {
/* Deleted in both or deleted in one and
* unchanged in the other */
if (a_oid)
if (code != 0) {
if (show(o, 4) || o->call_depth)
- error(_("merging of trees %s and %s failed"),
+ err(o, _("merging of trees %s and %s failed"),
oid_to_hex(&head->object.oid),
oid_to_hex(&merge->object.oid));
return -1;
o->call_depth--;
if (!merged_common_ancestors)
- return error(_("merge returned no commit"));
+ return err(o, _("merge returned no commit"));
}
discard_cache();
o->ancestor = "merged common ancestors";
clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
&mrtree);
- if (clean < 0)
+ if (clean < 0) {
+ flush_output(o);
return clean;
+ }
if (o->call_depth) {
*result = make_virtual_commit(mrtree, "merged tree");
commit_list_insert(h2, &(*result)->parents->next);
}
flush_output(o);
+ if (!o->call_depth && o->buffer_output < 2)
+ strbuf_release(&o->obuf);
if (show(o, 2))
diff_warn_rename_limit("merge.renamelimit",
o->needed_rename_limit, 0);
for (i = 0; i < num_base_list; ++i) {
struct commit *base;
if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
- return error(_("Could not parse object '%s'"),
+ return err(o, _("Could not parse object '%s'"),
oid_to_hex(base_list[i]));
commit_list_insert(base, &ca);
}
if (active_cache_changed &&
write_locked_index(&the_index, lock, COMMIT_LOCK))
- return error(_("Unable to write index."));
+ return err(o, _("Unable to write index."));
return clean ? 0 : 1;
}