Files
git/merge-blobs.c
Jeff King a28d2bfe19 xdiff: replace mmbuffer_t with mmfile_t
Our import of xdiff has two identical buffer structures: mmfile_t and
mmbuffer_t. In upstream xdiff these were actually different, but the
import in 3443546f6e (Use a *real* built-in diff generator, 2006-03-24)
simplified mmfile_t to a simple buffer.

In xdiff we usually use mmfile_t for input and mmbuffer_t for output,
but they are really both just a ptr/len pair. I don't think that having
different types is buying us anything in terms of type safety or
semantics, and having two makes it awkward to use the same helpers for
both. In particular, an external merge driver's output is read from a
file, but we can't easily use read_mmfile(), since we want the result in
an mmbuffer_t.

Let's use mmfile_t for both cases and drop mmbuffer_t. The latter is
probably a more descriptive name, but we have many more uses of
mmfile_t (and helpers like read_mmfile). So let's consolidate using that
name; we can always change it to something more sensible later.

There should be no behavior change here; this is just consolidating the
types.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-01 06:38:13 -07:00

107 lines
2.2 KiB
C

#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "merge-ll.h"
#include "blob.h"
#include "merge-blobs.h"
#include "odb.h"
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
{
void *buf;
size_t size;
enum object_type type;
buf = odb_read_object(the_repository->objects, &obj->object.oid,
&type, &size);
if (!buf)
return -1;
if (type != OBJ_BLOB) {
free(buf);
return -1;
}
f->ptr = buf;
f->size = size;
return 0;
}
static void free_mmfile(mmfile_t *f)
{
free(f->ptr);
}
static void *three_way_filemerge(struct index_state *istate,
const char *path,
mmfile_t *base,
mmfile_t *our,
mmfile_t *their,
size_t *size)
{
enum ll_merge_result merge_status;
mmfile_t res;
/*
* This function is only used by cmd_merge_tree, which
* does not respect the merge.conflictstyle option.
* There is no need to worry about a label for the
* common ancestor.
*/
merge_status = ll_merge(&res, path, base, NULL,
our, ".our", their, ".their",
istate, NULL);
if (merge_status < 0)
return NULL;
if (merge_status == LL_MERGE_BINARY_CONFLICT)
warning("Cannot merge binary files: %s (%s vs. %s)",
path, ".our", ".their");
*size = res.size;
return res.ptr;
}
void *merge_blobs(struct index_state *istate, const char *path,
struct blob *base, struct blob *our,
struct blob *their, size_t *size)
{
void *res = NULL;
mmfile_t f1, f2, common;
/*
* Removed in either branch?
*
* NOTE! This depends on the caller having done the
* proper warning about removing a file that got
* modified in the other branch!
*/
if (!our || !their) {
enum object_type type;
if (base)
return NULL;
if (!our)
our = their;
return odb_read_object(the_repository->objects, &our->object.oid,
&type, size);
}
if (fill_mmfile_blob(&f1, our) < 0)
goto out_no_mmfile;
if (fill_mmfile_blob(&f2, their) < 0)
goto out_free_f1;
if (base) {
if (fill_mmfile_blob(&common, base) < 0)
goto out_free_f2_f1;
} else {
common.ptr = xstrdup("");
common.size = 0;
}
res = three_way_filemerge(istate, path, &common, &f1, &f2, size);
free_mmfile(&common);
out_free_f2_f1:
free_mmfile(&f2);
out_free_f1:
free_mmfile(&f1);
out_no_mmfile:
return res;
}