merge-file: add an option to process object IDs

git merge-file knows how to merge files on the file system already.  It
would be helpful, however, to allow it to also merge single blobs.
Teach it an `--object-id` option which means that its arguments are
object IDs and not files to allow it to do so.

We handle the empty blob specially since read_mmblob doesn't read it
directly and otherwise users cannot specify an empty ancestor.

Signed-off-by: brian m. carlson <bk2204@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
brian m. carlson
2023-11-01 19:24:19 +00:00
committed by Junio C Hamano
parent 8077612ea1
commit e1068f0ad4
3 changed files with 122 additions and 17 deletions

View File

@ -1,5 +1,8 @@
#include "builtin.h"
#include "abspath.h"
#include "hex.h"
#include "object-name.h"
#include "object-store.h"
#include "config.h"
#include "gettext.h"
#include "setup.h"
@ -31,10 +34,11 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
mmfile_t mmfs[3] = { 0 };
mmbuffer_t result = { 0 };
xmparam_t xmp = { 0 };
int ret = 0, i = 0, to_stdout = 0;
int ret = 0, i = 0, to_stdout = 0, object_id = 0;
int quiet = 0;
struct option options[] = {
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
OPT_BOOL(0, "object-id", &object_id, N_("use object IDs instead of filenames")),
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
XDL_MERGE_ZEALOUS_DIFF3),
@ -71,8 +75,12 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
return error_errno("failed to redirect stderr to /dev/null");
}
if (object_id)
setup_git_directory();
for (i = 0; i < 3; i++) {
char *fname;
struct object_id oid;
mmfile_t *mmf = mmfs + i;
if (!names[i])
@ -80,12 +88,22 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
fname = prefix_filename(prefix, argv[i]);
if (read_mmfile(mmf, fname))
if (object_id) {
if (repo_get_oid(the_repository, argv[i], &oid))
ret = error(_("object '%s' does not exist"),
argv[i]);
else if (!oideq(&oid, the_hash_algo->empty_blob))
read_mmblob(mmf, &oid);
else
read_mmfile(mmf, "/dev/null");
} else if (read_mmfile(mmf, fname)) {
ret = -1;
else if (mmf->size > MAX_XDIFF_SIZE ||
buffer_is_binary(mmf->ptr, mmf->size))
}
if (ret != -1 && (mmf->size > MAX_XDIFF_SIZE ||
buffer_is_binary(mmf->ptr, mmf->size))) {
ret = error("Cannot merge binary files: %s",
argv[i]);
}
free(fname);
if (ret)
@ -99,20 +117,32 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
if (ret >= 0) {
const char *filename = argv[0];
char *fpath = prefix_filename(prefix, argv[0]);
FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
if (object_id && !to_stdout) {
struct object_id oid;
if (result.size) {
if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
ret = error(_("Could not write object file"));
} else {
oidcpy(&oid, the_hash_algo->empty_blob);
}
if (ret >= 0)
printf("%s\n", oid_to_hex(&oid));
} else {
const char *filename = argv[0];
char *fpath = prefix_filename(prefix, argv[0]);
FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
if (!f)
ret = error_errno("Could not open %s for writing",
filename);
else if (result.size &&
fwrite(result.ptr, result.size, 1, f) != 1)
ret = error_errno("Could not write to %s", filename);
else if (fclose(f))
ret = error_errno("Could not close %s", filename);
if (!f)
ret = error_errno("Could not open %s for writing",
filename);
else if (result.size &&
fwrite(result.ptr, result.size, 1, f) != 1)
ret = error_errno("Could not write to %s", filename);
else if (fclose(f))
ret = error_errno("Could not close %s", filename);
free(fpath);
}
free(result.ptr);
free(fpath);
}
if (ret > 127)