2006-06-29 13:06:36 +08:00
|
|
|
#include "cache.h"
|
|
|
|
#include "run-command.h"
|
|
|
|
#include "xdiff-interface.h"
|
2010-01-17 13:45:40 +08:00
|
|
|
#include "ll-merge.h"
|
2006-06-29 13:06:36 +08:00
|
|
|
#include "blob.h"
|
2012-12-07 07:08:01 +08:00
|
|
|
#include "merge-blobs.h"
|
2018-05-16 07:42:15 +08:00
|
|
|
#include "object-store.h"
|
2006-06-29 13:06:36 +08:00
|
|
|
|
|
|
|
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
|
|
|
|
{
|
|
|
|
void *buf;
|
|
|
|
unsigned long size;
|
2007-02-27 03:55:59 +08:00
|
|
|
enum object_type type;
|
2006-06-29 13:06:36 +08:00
|
|
|
|
sha1_file: convert read_sha1_file to struct object_id
Convert read_sha1_file to take a pointer to struct object_id and rename
it read_object_file. Do the same for read_sha1_file_extended.
Convert one use in grep.c to use the new function without any other code
change, since the pointer being passed is a void pointer that is already
initialized with a pointer to struct object_id. Update the declaration
and definitions of the modified functions, and apply the following
semantic patch to convert the remaining callers:
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1.hash, E2, E3)
+ read_object_file(&E1, E2, E3)
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1->hash, E2, E3)
+ read_object_file(E1, E2, E3)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1.hash, E2, E3, E4)
+ read_object_file_extended(&E1, E2, E3, E4)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1->hash, E2, E3, E4)
+ read_object_file_extended(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 10:27:53 +08:00
|
|
|
buf = read_object_file(&obj->object.oid, &type, &size);
|
2006-06-29 13:06:36 +08:00
|
|
|
if (!buf)
|
|
|
|
return -1;
|
2015-03-21 08:28:03 +08:00
|
|
|
if (type != OBJ_BLOB) {
|
|
|
|
free(buf);
|
2006-06-29 13:06:36 +08:00
|
|
|
return -1;
|
2015-03-21 08:28:03 +08:00
|
|
|
}
|
2006-06-29 13:06:36 +08:00
|
|
|
f->ptr = buf;
|
|
|
|
f->size = size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_mmfile(mmfile_t *f)
|
|
|
|
{
|
|
|
|
free(f->ptr);
|
|
|
|
}
|
|
|
|
|
2018-09-21 23:57:28 +08:00
|
|
|
static void *three_way_filemerge(struct index_state *istate,
|
|
|
|
const char *path,
|
|
|
|
mmfile_t *base,
|
|
|
|
mmfile_t *our,
|
|
|
|
mmfile_t *their,
|
|
|
|
unsigned long *size)
|
2006-06-29 13:06:36 +08:00
|
|
|
{
|
2022-02-02 10:37:30 +08:00
|
|
|
enum ll_merge_result merge_status;
|
2010-01-17 13:45:40 +08:00
|
|
|
mmbuffer_t res;
|
2006-06-29 13:06:36 +08:00
|
|
|
|
2010-03-21 08:40:53 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2010-03-21 08:38:58 +08:00
|
|
|
merge_status = ll_merge(&res, path, base, NULL,
|
2018-09-21 23:57:27 +08:00
|
|
|
our, ".our", their, ".their",
|
2018-09-21 23:57:28 +08:00
|
|
|
istate, NULL);
|
2006-12-13 07:01:41 +08:00
|
|
|
if (merge_status < 0)
|
|
|
|
return NULL;
|
2022-02-02 10:37:30 +08:00
|
|
|
if (merge_status == LL_MERGE_BINARY_CONFLICT)
|
|
|
|
warning("Cannot merge binary files: %s (%s vs. %s)",
|
|
|
|
path, ".our", ".their");
|
2006-12-13 07:01:41 +08:00
|
|
|
|
|
|
|
*size = res.size;
|
|
|
|
return res.ptr;
|
2006-06-29 13:06:36 +08:00
|
|
|
}
|
|
|
|
|
2018-09-21 23:57:28 +08:00
|
|
|
void *merge_blobs(struct index_state *istate, const char *path,
|
|
|
|
struct blob *base, struct blob *our,
|
|
|
|
struct blob *their, unsigned long *size)
|
2006-06-29 13:06:36 +08:00
|
|
|
{
|
|
|
|
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) {
|
2007-02-27 03:55:59 +08:00
|
|
|
enum object_type type;
|
2006-06-29 13:06:36 +08:00
|
|
|
if (base)
|
|
|
|
return NULL;
|
|
|
|
if (!our)
|
|
|
|
our = their;
|
sha1_file: convert read_sha1_file to struct object_id
Convert read_sha1_file to take a pointer to struct object_id and rename
it read_object_file. Do the same for read_sha1_file_extended.
Convert one use in grep.c to use the new function without any other code
change, since the pointer being passed is a void pointer that is already
initialized with a pointer to struct object_id. Update the declaration
and definitions of the modified functions, and apply the following
semantic patch to convert the remaining callers:
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1.hash, E2, E3)
+ read_object_file(&E1, E2, E3)
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1->hash, E2, E3)
+ read_object_file(E1, E2, E3)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1.hash, E2, E3, E4)
+ read_object_file_extended(&E1, E2, E3, E4)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1->hash, E2, E3, E4)
+ read_object_file_extended(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 10:27:53 +08:00
|
|
|
return read_object_file(&our->object.oid, &type, size);
|
2006-06-29 13:06:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
merge-tree: drop generate_common strategy
When merge_blobs sees an add/add conflict, it tries to
create a virtual base object for the 3-way merge that
consists of the common lines of each file. It inherited this
strategy from merge-one-file in 0c79938 (Improved three-way
blob merging code, 2006-06-28), and the point is to minimize
the size of the conflict hunks. That commit talks about "if
libxdiff were to ever grow a compatible three-way merge, it
could probably be directly plugged in".
That has long since happened. So as with merge-one-file in
the previous commit, this extra step is no longer necessary.
Our 3-way merge code is smart enough to do the minimizing
itself if we simply feed it an empty base, which is what the
more modern merge-recursive strategy already does.
Not only does this let us drop some code, but it removes an
overflow bug in generate_common_file(). We allocate a buffer
as large as the smallest of the two blobs, under the
assumption that there cannot be more common content than
what is in the smaller blob. However, xdiff may feed us
more: if neither file ends in a newline, it feeds us the
"\nNo newline at end of file" marker as common content, and
we write it into the output. If the differences between the
files are small than that string, we overflow the output
buffer. This patch solves it by simply dropping the buggy
code entirely.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-23 14:06:55 +08:00
|
|
|
common.ptr = xstrdup("");
|
|
|
|
common.size = 0;
|
2006-06-29 13:06:36 +08:00
|
|
|
}
|
2018-09-21 23:57:28 +08:00
|
|
|
res = three_way_filemerge(istate, path, &common, &f1, &f2, size);
|
2006-06-29 13:06:36 +08:00
|
|
|
free_mmfile(&common);
|
|
|
|
out_free_f2_f1:
|
|
|
|
free_mmfile(&f2);
|
|
|
|
out_free_f1:
|
|
|
|
free_mmfile(&f1);
|
|
|
|
out_no_mmfile:
|
|
|
|
return res;
|
|
|
|
}
|