2023-02-24 00:09:32 +00:00
|
|
|
#include "git-compat-util.h"
|
2006-06-29 05:06:36 +00:00
|
|
|
#include "run-command.h"
|
|
|
|
#include "xdiff-interface.h"
|
merge-ll: rename from ll-merge
A long term (but rather minor) pet-peeve of mine was the name
ll-merge.[ch]. I thought it made it harder to realize what stuff was
related to merging when I was working on the merge machinery and trying
to improve it.
Further, back in d1cbe1e6d8a ("hash-ll.h: split out of hash.h to remove
dependency on repository.h", 2023-04-22), we have split the portions of
hash.h that do not depend upon repository.h into a "hash-ll.h" (due to
the recommendation to use "ll" for "low-level" in its name[1], but which
I used as a suffix precisely because of my distaste for "ll-merge").
When we discussed adding additional "*-ll.h" files, a request was made
that we use "ll" consistently as either a prefix or a suffix. Since it
is already in use as both a prefix and a suffix, the only way to do so
is to rename some files.
Besides my distaste for the ll-merge.[ch] name, let me also note that
the files
ll-fsmonitor.h, ll-hash.h, ll-merge.h, ll-object-store.h, ll-read-cache.h
would have essentially nothing to do with each other and make no sense
to group. But giving them the common "ll-" prefix would group them. Using
"-ll" as a suffix thus seems just much more logical to me. Rename
ll-merge.[ch] to merge-ll.[ch] to achieve this consistency, and to
ensure we get a more logical grouping of files.
[1] https://lore.kernel.org/git/kl6lsfcu1g8w.fsf@chooglen-macbookpro.roam.corp.google.com/
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-05-16 06:34:04 +00:00
|
|
|
#include "merge-ll.h"
|
2006-06-29 05:06:36 +00:00
|
|
|
#include "blob.h"
|
2012-12-06 23:08:01 +00:00
|
|
|
#include "merge-blobs.h"
|
2023-05-16 06:34:06 +00:00
|
|
|
#include "object-store-ll.h"
|
2006-06-29 05:06:36 +00:00
|
|
|
|
|
|
|
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
|
|
|
|
{
|
|
|
|
void *buf;
|
|
|
|
unsigned long size;
|
2007-02-26 19:55:59 +00:00
|
|
|
enum object_type type;
|
2006-06-29 05:06:36 +00:00
|
|
|
|
2023-03-28 13:58:50 +00:00
|
|
|
buf = repo_read_object_file(the_repository, &obj->object.oid, &type,
|
|
|
|
&size);
|
2006-06-29 05:06:36 +00:00
|
|
|
if (!buf)
|
|
|
|
return -1;
|
2015-03-21 00:28:03 +00:00
|
|
|
if (type != OBJ_BLOB) {
|
|
|
|
free(buf);
|
2006-06-29 05:06:36 +00:00
|
|
|
return -1;
|
2015-03-21 00:28:03 +00:00
|
|
|
}
|
2006-06-29 05:06:36 +00:00
|
|
|
f->ptr = buf;
|
|
|
|
f->size = size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_mmfile(mmfile_t *f)
|
|
|
|
{
|
|
|
|
free(f->ptr);
|
|
|
|
}
|
|
|
|
|
2018-09-21 15:57:28 +00: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 05:06:36 +00:00
|
|
|
{
|
2022-02-02 02:37:30 +00:00
|
|
|
enum ll_merge_result merge_status;
|
2010-01-17 05:45:40 +00:00
|
|
|
mmbuffer_t res;
|
2006-06-29 05:06:36 +00:00
|
|
|
|
2010-03-21 00:40:53 +00: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 00:38:58 +00:00
|
|
|
merge_status = ll_merge(&res, path, base, NULL,
|
2018-09-21 15:57:27 +00:00
|
|
|
our, ".our", their, ".their",
|
2018-09-21 15:57:28 +00:00
|
|
|
istate, NULL);
|
2006-12-12 23:01:41 +00:00
|
|
|
if (merge_status < 0)
|
|
|
|
return NULL;
|
2022-02-02 02:37:30 +00:00
|
|
|
if (merge_status == LL_MERGE_BINARY_CONFLICT)
|
|
|
|
warning("Cannot merge binary files: %s (%s vs. %s)",
|
|
|
|
path, ".our", ".their");
|
2006-12-12 23:01:41 +00:00
|
|
|
|
|
|
|
*size = res.size;
|
|
|
|
return res.ptr;
|
2006-06-29 05:06:36 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 15:57:28 +00: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 05:06:36 +00: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-26 19:55:59 +00:00
|
|
|
enum object_type type;
|
2006-06-29 05:06:36 +00:00
|
|
|
if (base)
|
|
|
|
return NULL;
|
|
|
|
if (!our)
|
|
|
|
our = their;
|
2023-03-28 13:58:50 +00:00
|
|
|
return repo_read_object_file(the_repository, &our->object.oid,
|
|
|
|
&type, size);
|
2006-06-29 05:06:36 +00: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 06:06:55 +00:00
|
|
|
common.ptr = xstrdup("");
|
|
|
|
common.size = 0;
|
2006-06-29 05:06:36 +00:00
|
|
|
}
|
2018-09-21 15:57:28 +00:00
|
|
|
res = three_way_filemerge(istate, path, &common, &f1, &f2, size);
|
2006-06-29 05:06:36 +00:00
|
|
|
free_mmfile(&common);
|
|
|
|
out_free_f2_f1:
|
|
|
|
free_mmfile(&f2);
|
|
|
|
out_free_f1:
|
|
|
|
free_mmfile(&f1);
|
|
|
|
out_no_mmfile:
|
|
|
|
return res;
|
|
|
|
}
|