From patchwork Thu Jun 25 12:19:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625157 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 79BF46C1 for ; Thu, 25 Jun 2020 12:49:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 61B3E207E8 for ; Thu, 25 Jun 2020 12:49:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="oW+Yz4nX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404760AbgFYMs5 (ORCPT ); Thu, 25 Jun 2020 08:48:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59286 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404756AbgFYMs4 (ORCPT ); Thu, 25 Jun 2020 08:48:56 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CAEB8C061573 for ; Thu, 25 Jun 2020 05:48:55 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id 17so5804728wmo.1 for ; Thu, 25 Jun 2020 05:48:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7DjiSFN9cempB7IuLRuXJRcuFRVaXGfWq9j9duwvjoM=; b=oW+Yz4nXDRryB16JB5VxPnmcw+gzKPcFvPhO0qwHkejzPRU8b/xiLmgo2qgf0OVTTb N3l2nlGJjEy+a1RBcQOkBXcQLtGxNLhnBUGw7cFR2kFOskRx2oAqVGyzdjjDl75pJIMR +RMDqVtmSCNiJwE+LlQda26KhmaYeJQc62GXM4XURU/HfZwzx+rIucAO8CfwioAaftB+ ITIQ5RQ0dujCp0zEmm39K10rmiHOII4RLWMychEPIzLsXJyUBqO1dkmzcRl2vR679hsN eF0cQIRlxiArQDPHkI8M84na9R7kWx9W9GkY7m1NnjzaNIEGYTR/8SJfOiyNnpkrMWZl YWEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7DjiSFN9cempB7IuLRuXJRcuFRVaXGfWq9j9duwvjoM=; b=GddhgCVlLZ/YKLXaDu5IljfJUay+G4r/k/kFBXPippe14NReV92jgcj95no37Op/RP i9K7UIQr8e0Ah2J4xsUvuO1SZNq964YDWz2/YNmClsNO300rMKzXFtLHysyklpAQXz2O Qx4J6St5DTJ2tukHAa4VY7eZkX6WynRbXHUxryOXzYU34KqrvUM6cZlBwdhvBO1da86w FlSvxogds5Chpt2eECGxA2SQMSxG//P+S8fvPcN+2wglsyiMX+ISmZQ04GjiPvu6+RjB aXTpf6pgEaj7Np+yd/jZWNfxva8UktaBNNEkZENnC7mWfi6nJXztukPN0Bj57mIeR64I 6vJw== X-Gm-Message-State: AOAM53050liuScGKAff8tC5UEzRUb2tVefFxFIwrGB2X0p7kDrEw9Eoj 1g4lqQXOwuwHD2Idm8rh7pOYIbDi X-Google-Smtp-Source: ABdhPJx32UYwB+YBd2iG5g0cX07XOSR2hvFGXU//aOmxfnNODYwWycRqnpCwHgAMAG6fSvsChQmuvQ== X-Received: by 2002:a1c:29c3:: with SMTP id p186mr3210381wmp.122.1593089334256; Thu, 25 Jun 2020 05:48:54 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.48.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:48:53 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 01/17] t6027: modernise tests Date: Thu, 25 Jun 2020 14:19:37 +0200 Message-Id: <20200625121953.16991-2-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Some tests in t6027 uses a if/then/else to check if a command failed or not, but we have the `test_must_fail' function to do it correctly for us nowadays. Signed-off-by: Alban Gruin --- t/t6027-merge-binary.sh | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/t/t6027-merge-binary.sh b/t/t6027-merge-binary.sh index 4e6c7cb77e..071d3f7343 100755 --- a/t/t6027-merge-binary.sh +++ b/t/t6027-merge-binary.sh @@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files' . ./test-lib.sh test_expect_success setup ' - cat "$TEST_DIRECTORY"/test-binary-1.png >m && git add m && git ls-files -s | sed -e "s/ 0 / 1 /" >E1 && @@ -35,33 +34,19 @@ test_expect_success setup ' ' test_expect_success resolve ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s resolve master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s resolve master && + git ls-files -s >current && + test_cmp expect current ' test_expect_success recursive ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s recursive master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s recursive master && + git ls-files -s >current && + test_cmp expect current ' test_done From patchwork Thu Jun 25 12:19:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625163 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9687E138C for ; Thu, 25 Jun 2020 12:49:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6FE0220724 for ; Thu, 25 Jun 2020 12:49:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="trxG6gng" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404774AbgFYMtB (ORCPT ); Thu, 25 Jun 2020 08:49:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59294 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404756AbgFYMs6 (ORCPT ); Thu, 25 Jun 2020 08:48:58 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2BAE5C061573 for ; Thu, 25 Jun 2020 05:48:58 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id s10so5678973wrw.12 for ; Thu, 25 Jun 2020 05:48:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+BK6UN6wyOqrnRpkp3WSNWaaJ4WVCuyL2Qm7pC8oFYo=; b=trxG6gnga1Q39M0drmPvZ0PcCJwaNnUV5eHQsoYoSKJsrNxPXEIUqg3Bykpds0nzK5 pMgKRzNx/gUv6xnSvEMyjOgHd0xo6mG9AfTTiyvZbNvhbH4qu9udOP9iStaKaJQtx2u8 dE54Ag06Kq+HdODvLkVAxjVqliKY0RGk+SXRv5onX8EQ3ORWJ+bsyJJN4CI0W+M3OjIU 4J1j+FGWrfuNuUuUkR0pmCKLpsbhTjhgjvZkXQi/FGOKnRTk8IPr+JujMfWKMidSvwhz T2tDwAmxGBInuotmmZ1WaBDIwXzI1/69YxYrdFSGj7X9PrQpRNfoclb+PWZz9KfeOoMj vvKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+BK6UN6wyOqrnRpkp3WSNWaaJ4WVCuyL2Qm7pC8oFYo=; b=hUWibaRUf7TqtpbCGkAZQHG+Kyt4ma85ZOtIvDOdNSEtivldpAfIvyNUWiOwRw/BUT mBCG0A7k57klH85wrja5jsGMgR70sok15B7MNHqtRaPjxIL/Spti8l9O2Xm6ik6u02Oa 198XRs1iAJO3kN/wazWtFCvrPmuxDfOutPIqKD8L2baBUAOamBgN4DjxMGEqCNFkykMG tZOkPfNOqEmLcl8L987W2VTio3eAec+IYa6q+nEdq2tJQi7ICcTkJkYLoNkUs8FG2Kaq 6c1Glj8ij6ZqIqz/tDIiptAWmNkZcOKu/OmaRbq5XrbtZiw65iB4vLODp5W2Z/YI6fzj l5GA== X-Gm-Message-State: AOAM531BaHnmLFgxAdmbLIdnB9QuLEP4lQL4g4GJ8fdXijNjKXz9lt9x uEdwK/LCe/xeD65+ylRXZF+Rd7/J X-Google-Smtp-Source: ABdhPJxo43zcyWL6OFgfSAKn/Z74IeDUtRsa6qcid9ghQcs4UzDoZCHHynA+VqpEaFnEBi4l95QeRg== X-Received: by 2002:adf:b198:: with SMTP id q24mr36561459wra.368.1593089336271; Thu, 25 Jun 2020 05:48:56 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.48.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:48:55 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 02/17] merge-one-file: rewrite in C Date: Thu, 25 Jun 2020 14:19:38 +0200 Message-Id: <20200625121953.16991-3-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-one-file' from shell to C. This port is very straightforward: it keeps using external processes to edit the index, for instance. Errors are also displayed with fprintf() instead of error(). Both of these will be addressed in the next few commits, leading to its libification so its main function can be used from other commands directly. This also fixes a bug present in the original script: instead of checking if a _regular_ file exists when a file exists in the branch to merge, but not in our branch, the rewritten version checks if a file of any kind (ie. a directory, ...) exists. This fixes the tests t6035.14, where the branch to merge had a new file, `a/b', but our branch had a directory there; it should have failed because a directory exists, but it did not because there was no regular file called `a/b'. This test is now marked as successful. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-one-file.c | 275 ++++++++++++++++++++++++++++++++ git-merge-one-file.sh | 167 ------------------- git.c | 1 + t/t6035-merge-dir-to-symlink.sh | 2 +- 6 files changed, 279 insertions(+), 169 deletions(-) create mode 100644 builtin/merge-one-file.c delete mode 100755 git-merge-one-file.sh diff --git a/Makefile b/Makefile index 372139f1f2..19574f5133 100644 --- a/Makefile +++ b/Makefile @@ -596,7 +596,6 @@ SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-merge-octopus.sh -SCRIPT_SH += git-merge-one-file.sh SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh @@ -1089,6 +1088,7 @@ BUILTIN_OBJS += builtin/mailsplit.o BUILTIN_OBJS += builtin/merge-base.o BUILTIN_OBJS += builtin/merge-file.o BUILTIN_OBJS += builtin/merge-index.o +BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o BUILTIN_OBJS += builtin/merge-tree.o diff --git a/builtin.h b/builtin.h index a5ae15bfe5..9205d5ecdc 100644 --- a/builtin.h +++ b/builtin.h @@ -172,6 +172,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix); int cmd_merge_index(int argc, const char **argv, const char *prefix); int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); +int cmd_merge_one_file(int argc, const char **argv, const char *prefix); int cmd_merge_recursive(int argc, const char **argv, const char *prefix); int cmd_merge_tree(int argc, const char **argv, const char *prefix); int cmd_mktag(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c new file mode 100644 index 0000000000..4992a6cd30 --- /dev/null +++ b/builtin/merge-one-file.c @@ -0,0 +1,275 @@ +/* + * Builtin "git merge-one-file" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-one-file.sh, written by Linus Torvalds. + * + * This is the git per-file merge script, called with + * + * $1 - original file SHA1 (or empty) + * $2 - file in branch1 SHA1 (or empty) + * $3 - file in branch2 SHA1 (or empty) + * $4 - pathname in repository + * $5 - original file mode (or empty) + * $6 - file in branch1 mode (or empty) + * $7 - file in branch2 mode (or empty) + * + * Handle some trivial cases.. The _really_ trivial cases have + * been handled already by git read-tree, but that one doesn't + * do any merges that might change the tree layout. + */ + +#define USE_THE_INDEX_COMPATIBILITY_MACROS +#include "cache.h" +#include "builtin.h" +#include "commit.h" +#include "dir.h" +#include "lockfile.h" +#include "object-store.h" +#include "run-command.h" +#include "xdiff-interface.h" + +static int create_temp_file(const struct object_id *oid, struct strbuf *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + struct strbuf err = STRBUF_INIT; + int ret; + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "unpack-file", oid_to_hex(oid), NULL); + ret = pipe_command(&cp, NULL, 0, path, 0, &err, 0); + if (!ret && path->len > 0) + strbuf_trim_trailing_newline(path); + + fprintf(stderr, "%.*s", (int) err.len, err.buf); + strbuf_release(&err); + + return ret; +} + +static int add_to_index_cacheinfo(unsigned int mode, + const struct object_id *oid, const char *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "update-index", "--add", "--cacheinfo", NULL); + argv_array_pushf(&cp.args, "%o,%s,%s", mode, oid_to_hex(oid), path); + return run_command(&cp); +} + +static int remove_from_index(const char *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "update-index", "--remove", "--", path, NULL); + return run_command(&cp); +} + +static int checkout_from_index(const char *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "checkout-index", "-u", "-f", "--", path, NULL); + return run_command(&cp); +} + +static int merge_one_file_deleted(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + if ((our_blob && orig_mode != our_mode) || + (their_blob && orig_mode != their_mode)) { + fprintf(stderr, "ERROR: File %s deleted on one branch but had its\n", path); + fprintf(stderr, "ERROR: permissions changed on the other.\n"); + return 1; + } + + if (our_blob) { + printf("Removing %s\n", path); + + if (file_exists(path)) + remove_path(path); + } + + return remove_from_index(path); +} + +static int do_merge_one_file(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + int ret, source, dest; + struct strbuf src1 = STRBUF_INIT, src2 = STRBUF_INIT, orig = STRBUF_INIT; + struct child_process cp_merge = CHILD_PROCESS_INIT, + cp_checkout = CHILD_PROCESS_INIT, + cp_update = CHILD_PROCESS_INIT; + + if (our_mode == S_IFLNK || their_mode == S_IFLNK) { + fprintf(stderr, "ERROR: %s: Not merging symbolic link changes.\n", path); + return 1; + } else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) { + fprintf(stderr, "ERROR: %s: Not merging conflicting submodule changes.\n", + path); + return 1; + } + + create_temp_file(our_blob, &src1); + create_temp_file(their_blob, &src2); + + if (orig_blob) { + printf("Auto-merging %s\n", path); + create_temp_file(orig_blob, &orig); + } else { + printf("Added %s in both, but differently.\n", path); + create_temp_file(the_hash_algo->empty_blob, &orig); + } + + cp_merge.git_cmd = 1; + argv_array_pushl(&cp_merge.args, "merge-file", src1.buf, orig.buf, src2.buf, + NULL); + ret = run_command(&cp_merge); + + if (ret != 0) + ret = 1; + + cp_checkout.git_cmd = 1; + argv_array_pushl(&cp_checkout.args, "checkout-index", "-f", "--stage=2", + "--", path, NULL); + if (run_command(&cp_checkout)) + return 1; + + source = open(src1.buf, O_RDONLY); + dest = open(path, O_WRONLY | O_TRUNC); + + copy_fd(source, dest); + + close(source); + close(dest); + + unlink(orig.buf); + unlink(src1.buf); + unlink(src2.buf); + + strbuf_release(&src1); + strbuf_release(&src2); + strbuf_release(&orig); + + if (ret) { + fprintf(stderr, "ERROR: "); + + if (!orig_blob) { + fprintf(stderr, "content conflict"); + if (our_mode != their_mode) + fprintf(stderr, ", "); + } + + if (our_mode != their_mode) + fprintf(stderr, "permissions conflict: %o->%o,%o", + orig_mode, our_mode, their_mode); + + fprintf(stderr, " in %s\n", path); + + return 1; + } + + cp_update.git_cmd = 1; + argv_array_pushl(&cp_update.args, "update-index", "--", path, NULL); + return run_command(&cp_update); +} + +static int merge_one_file(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + if (orig_blob && + ((our_blob && oideq(orig_blob, our_blob)) || + (their_blob && oideq(orig_blob, their_blob)))) + return merge_one_file_deleted(orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else if (!orig_blob && our_blob && !their_blob) { + return add_to_index_cacheinfo(our_mode, our_blob, path); + } else if (!orig_blob && !our_blob && their_blob) { + printf("Adding %s\n", path); + + if (file_exists(path)) { + fprintf(stderr, "ERROR: untracked %s is overwritten by the merge.\n", path); + return 1; + } + + if (add_to_index_cacheinfo(their_mode, their_blob, path)) + return 1; + return checkout_from_index(path); + } else if (!orig_blob && our_blob && their_blob && + oideq(our_blob, their_blob)) { + if (our_mode != their_mode) { + fprintf(stderr, "ERROR: File %s added identically in both branches,", path); + fprintf(stderr, "ERROR: but permissions conflict %o->%o.\n", + our_mode, their_mode); + return 1; + } + + printf("Adding %s\n", path); + + if (add_to_index_cacheinfo(our_mode, our_blob, path)) + return 1; + return checkout_from_index(path); + } else if (our_blob && their_blob) + return do_merge_one_file(orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else { + char *orig_hex = "", *our_hex = "", *their_hex = ""; + + if (orig_blob) + orig_hex = oid_to_hex(orig_blob); + if (our_blob) + our_hex = oid_to_hex(our_blob); + if (their_blob) + their_hex = oid_to_hex(their_blob); + + fprintf(stderr, "ERROR: %s: Not handling case %s -> %s -> %s\n", + path, orig_hex, our_hex, their_hex); + return 1; + } + + return 0; +} + +static const char builtin_merge_one_file_usage[] = + "git merge-one-file " + " \n\n" + "Blob ids and modes should be empty for missing files."; + +int cmd_merge_one_file(int argc, const char **argv, const char *prefix) +{ + struct object_id orig_blob, our_blob, their_blob, + *p_orig_blob = NULL, *p_our_blob = NULL, *p_their_blob = NULL; + unsigned int orig_mode = 0, our_mode = 0, their_mode = 0; + + if (argc != 8) + usage(builtin_merge_one_file_usage); + + if (!get_oid(argv[1], &orig_blob)) { + p_orig_blob = &orig_blob; + orig_mode = strtol(argv[5], NULL, 8); + } + + if (!get_oid(argv[2], &our_blob)) { + p_our_blob = &our_blob; + our_mode = strtol(argv[6], NULL, 8); + } + + if (!get_oid(argv[3], &their_blob)) { + p_their_blob = &their_blob; + their_mode = strtol(argv[7], NULL, 8); + } + + return merge_one_file(p_orig_blob, p_our_blob, p_their_blob, argv[4], + orig_mode, our_mode, their_mode); +} diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh deleted file mode 100755 index f6d9852d2f..0000000000 --- a/git-merge-one-file.sh +++ /dev/null @@ -1,167 +0,0 @@ -#!/bin/sh -# -# Copyright (c) Linus Torvalds, 2005 -# -# This is the git per-file merge script, called with -# -# $1 - original file SHA1 (or empty) -# $2 - file in branch1 SHA1 (or empty) -# $3 - file in branch2 SHA1 (or empty) -# $4 - pathname in repository -# $5 - original file mode (or empty) -# $6 - file in branch1 mode (or empty) -# $7 - file in branch2 mode (or empty) -# -# Handle some trivial cases.. The _really_ trivial cases have -# been handled already by git read-tree, but that one doesn't -# do any merges that might change the tree layout. - -USAGE=' ' -USAGE="$USAGE " -LONG_USAGE="usage: git merge-one-file $USAGE - -Blob ids and modes should be empty for missing files." - -SUBDIRECTORY_OK=Yes -. git-sh-setup -cd_to_toplevel -require_work_tree - -if test $# != 7 -then - echo "$LONG_USAGE" - exit 1 -fi - -case "${1:-.}${2:-.}${3:-.}" in -# -# Deleted in both or deleted in one and unchanged in the other -# -"$1.." | "$1.$1" | "$1$1.") - if { test -z "$6" && test "$5" != "$7"; } || - { test -z "$7" && test "$5" != "$6"; } - then - echo "ERROR: File $4 deleted on one branch but had its" >&2 - echo "ERROR: permissions changed on the other." >&2 - exit 1 - fi - - if test -n "$2" - then - echo "Removing $4" - else - # read-tree checked that index matches HEAD already, - # so we know we do not have this path tracked. - # there may be an unrelated working tree file here, - # which we should just leave unmolested. Make sure - # we do not have it in the index, though. - exec git update-index --remove -- "$4" - fi - if test -f "$4" - then - rm -f -- "$4" && - rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || : - fi && - exec git update-index --remove -- "$4" - ;; - -# -# Added in one. -# -".$2.") - # the other side did not add and we added so there is nothing - # to be done, except making the path merged. - exec git update-index --add --cacheinfo "$6" "$2" "$4" - ;; -"..$3") - echo "Adding $4" - if test -f "$4" - then - echo "ERROR: untracked $4 is overwritten by the merge." >&2 - exit 1 - fi - git update-index --add --cacheinfo "$7" "$3" "$4" && - exec git checkout-index -u -f -- "$4" - ;; - -# -# Added in both, identically (check for same permissions). -# -".$3$2") - if test "$6" != "$7" - then - echo "ERROR: File $4 added identically in both branches," >&2 - echo "ERROR: but permissions conflict $6->$7." >&2 - exit 1 - fi - echo "Adding $4" - git update-index --add --cacheinfo "$6" "$2" "$4" && - exec git checkout-index -u -f -- "$4" - ;; - -# -# Modified in both, but differently. -# -"$1$2$3" | ".$2$3") - - case ",$6,$7," in - *,120000,*) - echo "ERROR: $4: Not merging symbolic link changes." >&2 - exit 1 - ;; - *,160000,*) - echo "ERROR: $4: Not merging conflicting submodule changes." >&2 - exit 1 - ;; - esac - - src1=$(git unpack-file $2) - src2=$(git unpack-file $3) - case "$1" in - '') - echo "Added $4 in both, but differently." - orig=$(git unpack-file $(git hash-object /dev/null)) - ;; - *) - echo "Auto-merging $4" - orig=$(git unpack-file $1) - ;; - esac - - git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if test $ret != 0 || test -z "$1" - then - msg='content conflict' - ret=1 - fi - - # Create the working tree file, using "our tree" version from the - # index, and then store the result of the merge. - git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1 - rm -f -- "$orig" "$src1" "$src2" - - if test "$6" != "$7" - then - if test -n "$msg" - then - msg="$msg, " - fi - msg="${msg}permissions conflict: $5->$6,$7" - ret=1 - fi - - if test $ret != 0 - then - echo "ERROR: $msg in $4" >&2 - exit 1 - fi - exec git update-index -- "$4" - ;; - -*) - echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2 - ;; -esac -exit 1 diff --git a/git.c b/git.c index a2d337eed7..058d91a2a5 100644 --- a/git.c +++ b/git.c @@ -532,6 +532,7 @@ static struct cmd_struct commands[] = { { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, + { "merge-one-file", cmd_merge_one_file, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index 2eddcc7664..5fb74e39a0 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -94,7 +94,7 @@ test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test -h a/b ' -test_expect_failure 'do not lose untracked in merge (resolve)' ' +test_expect_success 'do not lose untracked in merge (resolve)' ' git reset --hard && git checkout baseline^0 && >a/b/c/e && From patchwork Thu Jun 25 12:19:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625159 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2EABA6C1 for ; Thu, 25 Jun 2020 12:49:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0E9A32072E for ; Thu, 25 Jun 2020 12:49:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iKl0ybEX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404777AbgFYMtC (ORCPT ); Thu, 25 Jun 2020 08:49:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59300 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404761AbgFYMtA (ORCPT ); Thu, 25 Jun 2020 08:49:00 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 36E4AC0613ED for ; Thu, 25 Jun 2020 05:48:59 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id j18so5421986wmi.3 for ; Thu, 25 Jun 2020 05:48:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kAvHl/JhnYRaMUMuiirHrgwuklbVky8tI/TBNJJKK+M=; b=iKl0ybEXbk4MoOR+diED94GptRGIYNP6EI5xVR3pOlNaIzy0wizYWkXZvkRjjYH6EW NdmkDmRRQ1zmK2DlLFKhuf5oRE5mSH6nPL4GCwIrLOWJMpe/tEw8c0FfLqfN8JEdwa7c T84dFnbTqLuU7KyxABeyYxmgaBuIsSdk64TmQyppT6HtpICtBN1R5Wbl+hsu9qNmgFqi yORhK/LjGxTkAgYFmMt1qhVq6vwLv/V6myAA718aGNB2QRzXSJ4Xoc03vapdWEtyctZ9 BnVYNTX1/DBTDLCMhVbGkOSB6bTdWubq4h5+w0XlMOaLqqX2JHxM718SHGRneODFX1YX BnnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kAvHl/JhnYRaMUMuiirHrgwuklbVky8tI/TBNJJKK+M=; b=CgJUQtMbIJGbOFFNNRCtfuJd+xe7VqhFWbugBzV3D4KBYRYW6BOSHA7hHkEAyY2WjL v4VRPxGLggLl+uroOccvskFVMV3OPNjWQ35MNAx0T8MqVECRnYFt+y6AO8QQFObFSz72 DnLwgBF+09/gE5wK5lQskG4arr0qAtbVRkAa2VupfBTV5LqNkFQpDyO+j/AnPl2rEmvx It1n5VWefrGtcrjeMd9bmaDbFO4wEjNpHNBJhkIl9GjMbs7CvNY3vc9j27LoNgz7pi1T RT5wCQl6mlKo5YJ1isqMpvlMgTB9icuULqKjO7KcKq4ovkYaqxpJUvr7AaUTUYsp4erY uEVA== X-Gm-Message-State: AOAM532BDY09YTp1ES113hWSuNBG1g/QCnG9QwSN1aV0k/qYHffgl8NV aWDRoIa/kzo4XappltByi/urvDUD X-Google-Smtp-Source: ABdhPJxYam6lMPRIQKoa0n6wRXEwOs2fY2xZW/pJut9HDWrd7rp1DGtLyt4uBGut25972eAetOV4pw== X-Received: by 2002:a1c:4d05:: with SMTP id o5mr3224037wmh.130.1593089337465; Thu, 25 Jun 2020 05:48:57 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.48.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:48:56 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 03/17] merge-one-file: remove calls to external processes Date: Thu, 25 Jun 2020 14:19:39 +0200 Message-Id: <20200625121953.16991-4-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org To save precious cycles by avoiding reading and flushing the index repeatedly, or write temporary files when an operation can be performed in-memory, this removes call to external processes: - calls to `update-index --add --cacheinfo' are replaced by calls to add_cache_entry(); - calls to `update-index --remove' are replaced by calls to remove_file_from_cache(); - calls to `checkout-index -u -f' are replaced by calls to checkout_entry(); - calls to `unpack-file' and `merge-files' are replaced by calls to read_mmblob() and xdl_merge(), respectively, to merge files in-memory; - calls to `checkout-index -f --stage=2' are replaced by calls to cache_file_exists(); - calls to `update-index' are replaced by calls to add_file_to_cache(). To enable these changes, the index is read and written back in cmd_merge_one_file(). Signed-off-by: Alban Gruin --- builtin/merge-one-file.c | 160 +++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 82 deletions(-) diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c index 4992a6cd30..d9ebd820cb 100644 --- a/builtin/merge-one-file.c +++ b/builtin/merge-one-file.c @@ -27,54 +27,48 @@ #include "dir.h" #include "lockfile.h" #include "object-store.h" -#include "run-command.h" #include "xdiff-interface.h" -static int create_temp_file(const struct object_id *oid, struct strbuf *path) -{ - struct child_process cp = CHILD_PROCESS_INIT; - struct strbuf err = STRBUF_INIT; - int ret; - - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "unpack-file", oid_to_hex(oid), NULL); - ret = pipe_command(&cp, NULL, 0, path, 0, &err, 0); - if (!ret && path->len > 0) - strbuf_trim_trailing_newline(path); - - fprintf(stderr, "%.*s", (int) err.len, err.buf); - strbuf_release(&err); - - return ret; -} - static int add_to_index_cacheinfo(unsigned int mode, const struct object_id *oid, const char *path) { - struct child_process cp = CHILD_PROCESS_INIT; + struct cache_entry *ce; + int len, option; - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "update-index", "--add", "--cacheinfo", NULL); - argv_array_pushf(&cp.args, "%o,%s,%s", mode, oid_to_hex(oid), path); - return run_command(&cp); -} + if (!verify_path(path, mode)) + return error("Invalid path '%s'", path); -static int remove_from_index(const char *path) -{ - struct child_process cp = CHILD_PROCESS_INIT; + len = strlen(path); + ce = make_empty_cache_entry(&the_index, len); - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "update-index", "--remove", "--", path, NULL); - return run_command(&cp); + oidcpy(&ce->oid, oid); + memcpy(ce->name, path, len); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; + ce->ce_mode = create_ce_mode(mode); + if (assume_unchanged) + ce->ce_flags |= CE_VALID; + option = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; + if (add_cache_entry(ce, option)) + return error("%s: cannot add to the index", path); + + return 0; } static int checkout_from_index(const char *path) { - struct child_process cp = CHILD_PROCESS_INIT; + struct checkout state; + struct cache_entry *ce; - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "checkout-index", "-u", "-f", "--", path, NULL); - return run_command(&cp); + state.istate = &the_index; + state.force = 1; + state.base_dir = ""; + state.base_dir_len = 0; + + ce = cache_file_exists(path, strlen(path), 0); + if (checkout_entry(ce, &state, NULL, NULL) < 0) + return error("%s: cannot checkout file", path); + return 0; } static int merge_one_file_deleted(const struct object_id *orig_blob, @@ -96,7 +90,9 @@ static int merge_one_file_deleted(const struct object_id *orig_blob, remove_path(path); } - return remove_from_index(path); + if (remove_file_from_cache(path)) + return error("%s: cannot remove from the index", path); + return 0; } static int do_merge_one_file(const struct object_id *orig_blob, @@ -104,61 +100,50 @@ static int do_merge_one_file(const struct object_id *orig_blob, const struct object_id *their_blob, const char *path, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) { - int ret, source, dest; - struct strbuf src1 = STRBUF_INIT, src2 = STRBUF_INIT, orig = STRBUF_INIT; - struct child_process cp_merge = CHILD_PROCESS_INIT, - cp_checkout = CHILD_PROCESS_INIT, - cp_update = CHILD_PROCESS_INIT; + int ret, i, dest; + mmbuffer_t result = {NULL, 0}; + mmfile_t mmfs[3]; + xmparam_t xmp = {{0}}; + struct cache_entry *ce; - if (our_mode == S_IFLNK || their_mode == S_IFLNK) { - fprintf(stderr, "ERROR: %s: Not merging symbolic link changes.\n", path); - return 1; - } else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) { - fprintf(stderr, "ERROR: %s: Not merging conflicting submodule changes.\n", - path); - return 1; - } + if (our_mode == S_IFLNK || their_mode == S_IFLNK) + return error(_("%s: Not merging symbolic link changes."), path); + else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) + return error(_("%s: Not merging conflicting submodule changes."), path); - create_temp_file(our_blob, &src1); - create_temp_file(their_blob, &src2); + read_mmblob(mmfs + 0, our_blob); + read_mmblob(mmfs + 2, their_blob); if (orig_blob) { printf("Auto-merging %s\n", path); - create_temp_file(orig_blob, &orig); + read_mmblob(mmfs + 1, orig_blob); } else { printf("Added %s in both, but differently.\n", path); - create_temp_file(the_hash_algo->empty_blob, &orig); + read_mmblob(mmfs + 1, the_hash_algo->empty_blob); } - cp_merge.git_cmd = 1; - argv_array_pushl(&cp_merge.args, "merge-file", src1.buf, orig.buf, src2.buf, - NULL); - ret = run_command(&cp_merge); + xmp.level = XDL_MERGE_ZEALOUS_ALNUM; + xmp.style = 0; + xmp.favor = 0; - if (ret != 0) + ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result); + + for (i = 0; i < 3; i++) + free(mmfs[i].ptr); + + if (ret > 127) ret = 1; - cp_checkout.git_cmd = 1; - argv_array_pushl(&cp_checkout.args, "checkout-index", "-f", "--stage=2", - "--", path, NULL); - if (run_command(&cp_checkout)) - return 1; + ce = cache_file_exists(path, strlen(path), 0); + if (!ce) + BUG("file is not present in the cache?"); - source = open(src1.buf, O_RDONLY); - dest = open(path, O_WRONLY | O_TRUNC); - - copy_fd(source, dest); - - close(source); + unlink(path); + dest = open(path, O_WRONLY | O_CREAT, ce->ce_mode); + write_in_full(dest, result.ptr, result.size); close(dest); - unlink(orig.buf); - unlink(src1.buf); - unlink(src2.buf); - - strbuf_release(&src1); - strbuf_release(&src2); - strbuf_release(&orig); + free(result.ptr); if (ret) { fprintf(stderr, "ERROR: "); @@ -178,9 +163,7 @@ static int do_merge_one_file(const struct object_id *orig_blob, return 1; } - cp_update.git_cmd = 1; - argv_array_pushl(&cp_update.args, "update-index", "--", path, NULL); - return run_command(&cp_update); + return add_file_to_cache(path, 0); } static int merge_one_file(const struct object_id *orig_blob, @@ -250,11 +233,17 @@ int cmd_merge_one_file(int argc, const char **argv, const char *prefix) { struct object_id orig_blob, our_blob, their_blob, *p_orig_blob = NULL, *p_our_blob = NULL, *p_their_blob = NULL; - unsigned int orig_mode = 0, our_mode = 0, their_mode = 0; + unsigned int orig_mode = 0, our_mode = 0, their_mode = 0, ret; + struct lock_file lock = LOCK_INIT; if (argc != 8) usage(builtin_merge_one_file_usage); + if (read_cache() < 0) + die("invalid index"); + + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); + if (!get_oid(argv[1], &orig_blob)) { p_orig_blob = &orig_blob; orig_mode = strtol(argv[5], NULL, 8); @@ -270,6 +259,13 @@ int cmd_merge_one_file(int argc, const char **argv, const char *prefix) their_mode = strtol(argv[7], NULL, 8); } - return merge_one_file(p_orig_blob, p_our_blob, p_their_blob, argv[4], - orig_mode, our_mode, their_mode); + ret = merge_one_file(p_orig_blob, p_our_blob, p_their_blob, argv[4], + orig_mode, our_mode, their_mode); + + if (ret) { + rollback_lock_file(&lock); + return ret; + } + + return write_locked_index(&the_index, &lock, COMMIT_LOCK); } From patchwork Thu Jun 25 12:19:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625161 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 78F6C138C for ; Thu, 25 Jun 2020 12:49:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5E36B20724 for ; Thu, 25 Jun 2020 12:49:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OoTr+Uqb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404799AbgFYMtC (ORCPT ); Thu, 25 Jun 2020 08:49:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59306 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404764AbgFYMtB (ORCPT ); Thu, 25 Jun 2020 08:49:01 -0400 Received: from mail-wr1-x443.google.com (mail-wr1-x443.google.com [IPv6:2a00:1450:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6091DC061573 for ; Thu, 25 Jun 2020 05:49:01 -0700 (PDT) Received: by mail-wr1-x443.google.com with SMTP id a6so5713910wrm.4 for ; Thu, 25 Jun 2020 05:49:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=9sooaKVhXSrJT5mgEU6o4Adku7L6SEhIg0nBV8aETOk=; b=OoTr+UqblIYiGOr5Rx1TBKfdRFcEos5ZaQwSOXLu30/UvsFS34sOds65j3Sfik9rKW T8Z+MZTwHfef4hEwiFS8uQJboFhJ8dbZS8ospcIhiJEFDWK7q549AH2iETgSHOjkZuM5 hiWoctJxgEflQPh6ZPFufvn7e+1NzVJsNENvpkLE1GxXnela4dpRtLJij185i+E0vxBt rXB4qbakCnIvyiKn4OkwUMjuRd4j9xGcmEwzb9vQYd6gEiWSnCTGcPD8Lk18ceGAaQAA QwofEuzYHKdKcKgf2d5Fy60ecGWN4gqqcMROyCdtpM5TPKiE6O0/qqWSXOtqrUsnyIRW aFEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9sooaKVhXSrJT5mgEU6o4Adku7L6SEhIg0nBV8aETOk=; b=S1FdYttO9x66rkJL+ert94czPEbQv7gT+HdLkwDqvYwiujQbIbY3qTL116OO6Dqfe2 2PKsAmcNOnpRMVwO5fKcAkmINoPjr+GWu8U132Zp3Xvp0szGqp0SmwZD2/BsER5Plxnc FqM3MQj47UC7DBU1Du2QhopI26Pfd7lX3VjU6g5Ab/7PF/t1ny+bm3L632B3SzbeBV0l BTF2E2PtKg0lnOlavgXP3FYpuZ/OpIEgQb5kkN1DjxB2qhy1yARXUuqqVYJt/CLExYOu 1fWZEr681K4s51mqsTK2IQmlgaJVqPTGJFd/2nb/IUr6c08zMQRsO0h19JUWROhFLh6h +p3w== X-Gm-Message-State: AOAM530zlALE8zHSGvxCcX4Hq0MgVQE+yQ7wkgwQ8MF9ZKuOmu3+ylPu qMKLN/rfx7ZWRHAED+cblguxFd1Z X-Google-Smtp-Source: ABdhPJyiT4AiSIutscbXScwxiRKvnyPfvtuMkQwIJkJR6xVsWslV0IFcCfJoYVUl8bBz2EXchUCFbQ== X-Received: by 2002:a5d:4607:: with SMTP id t7mr29238716wrq.251.1593089338574; Thu, 25 Jun 2020 05:48:58 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.48.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:48:58 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 04/17] merge-one-file: use error() instead of fprintf(stderr, ...) Date: Thu, 25 Jun 2020 14:19:40 +0200 Message-Id: <20200625121953.16991-5-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We have a handy helper function to display errors and return a value. Use it instead of fprintf(stderr, ...). Signed-off-by: Alban Gruin --- builtin/merge-one-file.c | 43 +++++++++++++--------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c index d9ebd820cb..d612885723 100644 --- a/builtin/merge-one-file.c +++ b/builtin/merge-one-file.c @@ -77,11 +77,9 @@ static int merge_one_file_deleted(const struct object_id *orig_blob, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) { if ((our_blob && orig_mode != our_mode) || - (their_blob && orig_mode != their_mode)) { - fprintf(stderr, "ERROR: File %s deleted on one branch but had its\n", path); - fprintf(stderr, "ERROR: permissions changed on the other.\n"); - return 1; - } + (their_blob && orig_mode != their_mode)) + return error(_("File %s deleted on one branch but had its " + "permissions changed on the other."), path); if (our_blob) { printf("Removing %s\n", path); @@ -146,19 +144,11 @@ static int do_merge_one_file(const struct object_id *orig_blob, free(result.ptr); if (ret) { - fprintf(stderr, "ERROR: "); - - if (!orig_blob) { - fprintf(stderr, "content conflict"); - if (our_mode != their_mode) - fprintf(stderr, ", "); - } - + if (!orig_blob) + error(_("content conflict in %s"), path); if (our_mode != their_mode) - fprintf(stderr, "permissions conflict: %o->%o,%o", - orig_mode, our_mode, their_mode); - - fprintf(stderr, " in %s\n", path); + error(_("permission conflict: %o->%o,%o in %s"), + orig_mode, our_mode, their_mode, path); return 1; } @@ -181,22 +171,18 @@ static int merge_one_file(const struct object_id *orig_blob, } else if (!orig_blob && !our_blob && their_blob) { printf("Adding %s\n", path); - if (file_exists(path)) { - fprintf(stderr, "ERROR: untracked %s is overwritten by the merge.\n", path); - return 1; - } + if (file_exists(path)) + return error(_("untracked %s is overwritten by the merge."), path); if (add_to_index_cacheinfo(their_mode, their_blob, path)) return 1; return checkout_from_index(path); } else if (!orig_blob && our_blob && their_blob && oideq(our_blob, their_blob)) { - if (our_mode != their_mode) { - fprintf(stderr, "ERROR: File %s added identically in both branches,", path); - fprintf(stderr, "ERROR: but permissions conflict %o->%o.\n", - our_mode, their_mode); - return 1; - } + if (our_mode != their_mode) + return error(_("File %s added identically in both branches, " + "but permissions conflict %o->%o."), + path, our_mode, their_mode); printf("Adding %s\n", path); @@ -216,9 +202,8 @@ static int merge_one_file(const struct object_id *orig_blob, if (their_blob) their_hex = oid_to_hex(their_blob); - fprintf(stderr, "ERROR: %s: Not handling case %s -> %s -> %s\n", + return error(_("%s: Not handling case %s -> %s -> %s"), path, orig_hex, our_hex, their_hex); - return 1; } return 0; From patchwork Thu Jun 25 12:19:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625165 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D4F8138C for ; Thu, 25 Jun 2020 12:49:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EB8422072E for ; Thu, 25 Jun 2020 12:49:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lbuWKByV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404806AbgFYMtG (ORCPT ); Thu, 25 Jun 2020 08:49:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404764AbgFYMtD (ORCPT ); Thu, 25 Jun 2020 08:49:03 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5193FC061573 for ; Thu, 25 Jun 2020 05:49:02 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id a6so6667164wmm.0 for ; Thu, 25 Jun 2020 05:49:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XMoEEopApLD1TvKM4EE4u4Zq4iE+6s/yqAo5OCEk7bY=; b=lbuWKByVaV3dqXnnNxF6+Gk3WQ4nhGcDSA+S9eQtVWV3kSfkVLNx5jew/QgwyFW3iW lNnxt93gOma/dX3QtpZUueR+NaFdKzwyCkmn9qDQbvQ8hAKqWYU9Rnuc8DjHAFczXEMp KZt6zRKedvrnfMIE6ANdzQ7Myt1M89nz0jI4TSyLA8Pzbzxm4kLCbgqiHlRtt2OJo7XU 0p4scb4UmPAHhGEOZTahx5ucyjamqzclo6h1h6Uk8vUI/Rsu9PShRG8Ikdnd1BtdBmPF FAZucXR1O1/SSg8OW8WjKpPGl4YEqiNVDShgQ44MgHDAAG8AWSh7oKpJbrECb9VfXHnw QAdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XMoEEopApLD1TvKM4EE4u4Zq4iE+6s/yqAo5OCEk7bY=; b=AZ+Oc19rpYtKdnaMhZQ79tgp1ZRUP79tLlFIYvXQzaK7Q6Y2sJaCNmfc3txOkvjZ5a XTbYORiWALA2UvGCoZgCC4bTobsnPtde3hsmip7dYG3kVmn8vZQ3dF32QAej+uKrqjXU 77jjVMvagv+Bvru0DvEjaoaUn4NhH05LgRMWxiK4ZV6eGN/GGRrv3yGLtaNRB3vHU/eQ 90+bLK4ZNCG0Oq830wkzt9CivFMZtE0gdUfO2PXM5KJiGdja3DrfMJ5reYUjrr/p9phk sXsPx285lzB8J94KJK7GdxhyrNd9gnq16suz/TRZlkgqoh6a5iQm3Epak/y5oOSKgaPR P39w== X-Gm-Message-State: AOAM531aPC9c0WfeI2izcMj9XpqZfnlK/dh0aI0aqr5AbrNTjipfGSrM IrJhgY3sGKRHo8zcyoxJ8+IYQ5Sb X-Google-Smtp-Source: ABdhPJyYjB69uCM3LWEg1lHqBsouOVXO9PrYk1Q2uLArKakMvD/ahHapS648fSZ3j+Ph+Uc7nLZ9GA== X-Received: by 2002:a1c:f00a:: with SMTP id a10mr3295678wmb.61.1593089340103; Thu, 25 Jun 2020 05:49:00 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.48.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:48:59 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 05/17] merge-one-file: libify merge_one_file() Date: Thu, 25 Jun 2020 14:19:41 +0200 Message-Id: <20200625121953.16991-6-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This moves merge_one_file() (and its helper functions) to a new file, merge-strategies.c. This will enable the resolve and octopus strategies to directly call it instead of forking. It is also renamed merge_strategies_one_file(). This is not a faithful copy-and-paste; in the builtin versions, merge_one_file() operated on `the_repository' and `the_index', something we cannot allow a function part of libgit.a to do. Hence, it now takes a pointer to a repository as its first argument (and helper functions takes a pointer to an `index_state'). Signed-off-by: Alban Gruin --- Notes: This patch is best viewed with `--color-moved'. Makefile | 1 + builtin/merge-one-file.c | 190 +------------------------------------- merge-strategies.c | 191 +++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 13 +++ 4 files changed, 209 insertions(+), 186 deletions(-) create mode 100644 merge-strategies.c create mode 100644 merge-strategies.h diff --git a/Makefile b/Makefile index 19574f5133..1ab4d160cb 100644 --- a/Makefile +++ b/Makefile @@ -911,6 +911,7 @@ LIB_OBJS += match-trees.o LIB_OBJS += mem-pool.o LIB_OBJS += merge-blobs.o LIB_OBJS += merge-recursive.o +LIB_OBJS += merge-strategies.o LIB_OBJS += merge.o LIB_OBJS += mergesort.o LIB_OBJS += midx.o diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c index d612885723..2f7a3e1db2 100644 --- a/builtin/merge-one-file.c +++ b/builtin/merge-one-file.c @@ -23,191 +23,8 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "builtin.h" -#include "commit.h" -#include "dir.h" #include "lockfile.h" -#include "object-store.h" -#include "xdiff-interface.h" - -static int add_to_index_cacheinfo(unsigned int mode, - const struct object_id *oid, const char *path) -{ - struct cache_entry *ce; - int len, option; - - if (!verify_path(path, mode)) - return error("Invalid path '%s'", path); - - len = strlen(path); - ce = make_empty_cache_entry(&the_index, len); - - oidcpy(&ce->oid, oid); - memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(0); - ce->ce_namelen = len; - ce->ce_mode = create_ce_mode(mode); - if (assume_unchanged) - ce->ce_flags |= CE_VALID; - option = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; - if (add_cache_entry(ce, option)) - return error("%s: cannot add to the index", path); - - return 0; -} - -static int checkout_from_index(const char *path) -{ - struct checkout state; - struct cache_entry *ce; - - state.istate = &the_index; - state.force = 1; - state.base_dir = ""; - state.base_dir_len = 0; - - ce = cache_file_exists(path, strlen(path), 0); - if (checkout_entry(ce, &state, NULL, NULL) < 0) - return error("%s: cannot checkout file", path); - return 0; -} - -static int merge_one_file_deleted(const struct object_id *orig_blob, - const struct object_id *our_blob, - const struct object_id *their_blob, const char *path, - unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) -{ - if ((our_blob && orig_mode != our_mode) || - (their_blob && orig_mode != their_mode)) - return error(_("File %s deleted on one branch but had its " - "permissions changed on the other."), path); - - if (our_blob) { - printf("Removing %s\n", path); - - if (file_exists(path)) - remove_path(path); - } - - if (remove_file_from_cache(path)) - return error("%s: cannot remove from the index", path); - return 0; -} - -static int do_merge_one_file(const struct object_id *orig_blob, - const struct object_id *our_blob, - const struct object_id *their_blob, const char *path, - unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) -{ - int ret, i, dest; - mmbuffer_t result = {NULL, 0}; - mmfile_t mmfs[3]; - xmparam_t xmp = {{0}}; - struct cache_entry *ce; - - if (our_mode == S_IFLNK || their_mode == S_IFLNK) - return error(_("%s: Not merging symbolic link changes."), path); - else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) - return error(_("%s: Not merging conflicting submodule changes."), path); - - read_mmblob(mmfs + 0, our_blob); - read_mmblob(mmfs + 2, their_blob); - - if (orig_blob) { - printf("Auto-merging %s\n", path); - read_mmblob(mmfs + 1, orig_blob); - } else { - printf("Added %s in both, but differently.\n", path); - read_mmblob(mmfs + 1, the_hash_algo->empty_blob); - } - - xmp.level = XDL_MERGE_ZEALOUS_ALNUM; - xmp.style = 0; - xmp.favor = 0; - - ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result); - - for (i = 0; i < 3; i++) - free(mmfs[i].ptr); - - if (ret > 127) - ret = 1; - - ce = cache_file_exists(path, strlen(path), 0); - if (!ce) - BUG("file is not present in the cache?"); - - unlink(path); - dest = open(path, O_WRONLY | O_CREAT, ce->ce_mode); - write_in_full(dest, result.ptr, result.size); - close(dest); - - free(result.ptr); - - if (ret) { - if (!orig_blob) - error(_("content conflict in %s"), path); - if (our_mode != their_mode) - error(_("permission conflict: %o->%o,%o in %s"), - orig_mode, our_mode, their_mode, path); - - return 1; - } - - return add_file_to_cache(path, 0); -} - -static int merge_one_file(const struct object_id *orig_blob, - const struct object_id *our_blob, - const struct object_id *their_blob, const char *path, - unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) -{ - if (orig_blob && - ((our_blob && oideq(orig_blob, our_blob)) || - (their_blob && oideq(orig_blob, their_blob)))) - return merge_one_file_deleted(orig_blob, our_blob, their_blob, path, - orig_mode, our_mode, their_mode); - else if (!orig_blob && our_blob && !their_blob) { - return add_to_index_cacheinfo(our_mode, our_blob, path); - } else if (!orig_blob && !our_blob && their_blob) { - printf("Adding %s\n", path); - - if (file_exists(path)) - return error(_("untracked %s is overwritten by the merge."), path); - - if (add_to_index_cacheinfo(their_mode, their_blob, path)) - return 1; - return checkout_from_index(path); - } else if (!orig_blob && our_blob && their_blob && - oideq(our_blob, their_blob)) { - if (our_mode != their_mode) - return error(_("File %s added identically in both branches, " - "but permissions conflict %o->%o."), - path, our_mode, their_mode); - - printf("Adding %s\n", path); - - if (add_to_index_cacheinfo(our_mode, our_blob, path)) - return 1; - return checkout_from_index(path); - } else if (our_blob && their_blob) - return do_merge_one_file(orig_blob, our_blob, their_blob, path, - orig_mode, our_mode, their_mode); - else { - char *orig_hex = "", *our_hex = "", *their_hex = ""; - - if (orig_blob) - orig_hex = oid_to_hex(orig_blob); - if (our_blob) - our_hex = oid_to_hex(our_blob); - if (their_blob) - their_hex = oid_to_hex(their_blob); - - return error(_("%s: Not handling case %s -> %s -> %s"), - path, orig_hex, our_hex, their_hex); - } - - return 0; -} +#include "merge-strategies.h" static const char builtin_merge_one_file_usage[] = "git merge-one-file " @@ -244,8 +61,9 @@ int cmd_merge_one_file(int argc, const char **argv, const char *prefix) their_mode = strtol(argv[7], NULL, 8); } - ret = merge_one_file(p_orig_blob, p_our_blob, p_their_blob, argv[4], - orig_mode, our_mode, their_mode); + ret = merge_strategies_one_file(the_repository, + p_orig_blob, p_our_blob, p_their_blob, argv[4], + orig_mode, our_mode, their_mode); if (ret) { rollback_lock_file(&lock); diff --git a/merge-strategies.c b/merge-strategies.c new file mode 100644 index 0000000000..3a9fce9f22 --- /dev/null +++ b/merge-strategies.c @@ -0,0 +1,191 @@ +#include "cache.h" +#include "dir.h" +#include "merge-strategies.h" +#include "xdiff-interface.h" + +static int add_to_index_cacheinfo(struct index_state *istate, + unsigned int mode, + const struct object_id *oid, const char *path) +{ + struct cache_entry *ce; + int len, option; + + if (!verify_path(path, mode)) + return error(_("Invalid path '%s'"), path); + + len = strlen(path); + ce = make_empty_cache_entry(istate, len); + + oidcpy(&ce->oid, oid); + memcpy(ce->name, path, len); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; + ce->ce_mode = create_ce_mode(mode); + if (assume_unchanged) + ce->ce_flags |= CE_VALID; + option = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; + if (add_index_entry(istate, ce, option)) + return error(_("%s: cannot add to the index"), path); + + return 0; +} + +static int checkout_from_index(struct index_state *istate, const char *path) +{ + struct checkout state = CHECKOUT_INIT; + struct cache_entry *ce; + + state.istate = istate; + state.force = 1; + state.base_dir = ""; + state.base_dir_len = 0; + + ce = index_file_exists(istate, path, strlen(path), 0); + if (checkout_entry(ce, &state, NULL, NULL) < 0) + return error(_("%s: cannot checkout file"), path); + return 0; +} + +static int merge_one_file_deleted(struct index_state *istate, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + if ((our_blob && orig_mode != our_mode) || + (their_blob && orig_mode != their_mode)) + return error(_("File %s deleted on one branch but had its " + "permissions changed on the other."), path); + + if (our_blob) { + printf("Removing %s\n", path); + + if (file_exists(path)) + remove_path(path); + } + + if (remove_file_from_index(istate, path)) + return error("%s: cannot remove from the index", path); + return 0; +} + +static int do_merge_one_file(struct index_state *istate, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + int ret, i, dest; + mmbuffer_t result = {NULL, 0}; + mmfile_t mmfs[3]; + xmparam_t xmp = {{0}}; + struct cache_entry *ce; + + if (our_mode == S_IFLNK || their_mode == S_IFLNK) + return error(_("%s: Not merging symbolic link changes."), path); + else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) + return error(_("%s: Not merging conflicting submodule changes."), path); + + read_mmblob(mmfs + 0, our_blob); + read_mmblob(mmfs + 2, their_blob); + + if (orig_blob) { + printf("Auto-merging %s\n", path); + read_mmblob(mmfs + 1, orig_blob); + } else { + printf("Added %s in both, but differently.\n", path); + read_mmblob(mmfs + 1, &null_oid); + } + + xmp.level = XDL_MERGE_ZEALOUS_ALNUM; + xmp.style = 0; + xmp.favor = 0; + + ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result); + + for (i = 0; i < 3; i++) + free(mmfs[i].ptr); + + if (ret > 127) + ret = 1; + + ce = index_file_exists(istate, path, strlen(path), 0); + if (!ce) + BUG("file is not present in the cache?"); + + unlink(path); + dest = open(path, O_WRONLY | O_CREAT, ce->ce_mode); + write_in_full(dest, result.ptr, result.size); + close(dest); + + free(result.ptr); + + if (ret) { + if (!orig_blob) + error(_("content conflict in %s"), path); + if (our_mode != their_mode) + error(_("permission conflict: %o->%o,%o in %s"), + orig_mode, our_mode, their_mode, path); + + return 1; + } + + return add_file_to_index(istate, path, 0); +} + +int merge_strategies_one_file(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, + unsigned int their_mode) +{ + if (orig_blob && + ((our_blob && oideq(orig_blob, our_blob)) || + (their_blob && oideq(orig_blob, their_blob)))) + return merge_one_file_deleted(r->index, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else if (!orig_blob && our_blob && !their_blob) { + return add_to_index_cacheinfo(r->index, our_mode, our_blob, path); + } else if (!orig_blob && !our_blob && their_blob) { + printf("Adding %s\n", path); + + if (file_exists(path)) + return error(_("untracked %s is overwritten by the merge."), path); + + if (add_to_index_cacheinfo(r->index, their_mode, their_blob, path)) + return 1; + return checkout_from_index(r->index, path); + } else if (!orig_blob && our_blob && their_blob && + oideq(our_blob, their_blob)) { + if (our_mode != their_mode) + return error(_("File %s added identically in both branches, " + "but permissions conflict %o->%o."), + path, our_mode, their_mode); + + printf("Adding %s\n", path); + + if (add_to_index_cacheinfo(r->index, our_mode, our_blob, path)) + return 1; + return checkout_from_index(r->index, path); + } else if (our_blob && their_blob) + return do_merge_one_file(r->index, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else { + char *orig_hex = "", *our_hex = "", *their_hex = ""; + + if (orig_blob) + orig_hex = oid_to_hex(orig_blob); + if (our_blob) + our_hex = oid_to_hex(our_blob); + if (their_blob) + their_hex = oid_to_hex(their_blob); + + return error(_("%s: Not handling case %s -> %s -> %s"), + path, orig_hex, our_hex, their_hex); + } + + return 0; +} diff --git a/merge-strategies.h b/merge-strategies.h new file mode 100644 index 0000000000..b527d145c7 --- /dev/null +++ b/merge-strategies.h @@ -0,0 +1,13 @@ +#ifndef MERGE_STRATEGIES_H +#define MERGE_STRATEGIES_H + +#include "object.h" + +int merge_strategies_one_file(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, + unsigned int their_mode); + +#endif /* MERGE_STRATEGIES_H */ From patchwork Thu Jun 25 12:19:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625167 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1E3926C1 for ; Thu, 25 Jun 2020 12:49:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F301A2072E for ; Thu, 25 Jun 2020 12:49:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="h4MDQ5hH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404813AbgFYMtH (ORCPT ); Thu, 25 Jun 2020 08:49:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404800AbgFYMtE (ORCPT ); Thu, 25 Jun 2020 08:49:04 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC740C0613ED for ; Thu, 25 Jun 2020 05:49:02 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id g75so5411620wme.5 for ; Thu, 25 Jun 2020 05:49:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=J7i8/kL9gIgWQQaUI1ZRXUK2V1w/DeNPWkP/9+CrIzU=; b=h4MDQ5hHTcbWLpyQfXDb3WrRLDxOBdLneDDS3At5Ni2ayOhhLSvQZQypuujD6ohNb2 S/2ahEBQNMhXsxcLmJ7AHver4EVDj3KVTvyOn25vcRx6V9+ExWe9GLD462vgXqer/3kU nCi/BWqO1ej3hXs9mvwVPz/HSww2zzWoB+KQi3vh5Kp0BVAAOeDqySOKlUQ1vt++bwWo 7j7/4Toze4YKXtq+inXZHEmmrSHWCzPXSJ4KS72lrfVCO/icaooTScDtHXsm7qDbnqHj kej3aHOGzoJeOERHcT2/AkdDqNhDvtzfoTDPgG/a9cDUZLzLZbY0pnNTQkIFzGNz4ssj 71EA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=J7i8/kL9gIgWQQaUI1ZRXUK2V1w/DeNPWkP/9+CrIzU=; b=tzi28xkbQWPiK5P5Anto5BhLBLlPqMrVOMqhO8u85nvnOKtFD6l1/hTu61k7ZZB2UU cqB0PhrbPVN75V4at3t9BTr+VHIGq31YnihXeO6nZ84rOfMc61P/kHNjrU9ZIIqeIcmf ozu/4mwjWDvHkG3SUMSJDvRb3UrEEUVIVYM5ONpBAx92rx6/0jlxZnKv4S5zbkqKYERI XoZrlLEopvGTz/MFkER8gvCs6EvLFe25bxb2KFJ0rIMhhuIO9UevI6n2osW7WI6Yd0YE CW04XwdAgSgYc8B0cHoydMrolLG+Uirvhbt7VRFIw9e5+/ORanjDh+TzV526aC2ailCH +JsA== X-Gm-Message-State: AOAM530AfGLxIeOMTVSwUsmRbNq3moBz6q1zPJh5DnvJnCECuYbI3zGW Fgk0pPwb67vlcnxcGlZjzhV6gb/P X-Google-Smtp-Source: ABdhPJy9L2KKl+cDSY7GYdYxo9ZTJf9w3PobsVvJIGR8TNcuy0nxX9Yr+1Hv321qf6BF3hliOgAT5A== X-Received: by 2002:a1c:80d3:: with SMTP id b202mr3300566wmd.111.1593089341167; Thu, 25 Jun 2020 05:49:01 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:00 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 06/17] merge-index: libify merge_one_path() and merge_all() Date: Thu, 25 Jun 2020 14:19:42 +0200 Message-Id: <20200625121953.16991-7-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The "resolve" and "octopus" merge strategies do not call directly `git merge-one-file', they delegate the work to another git command, `git merge-index', that will loop over files in the index and call the specified command. Unfortunately, these functions are not part of libgit.a, which means that once rewritten, the strategies would still have to invoke `merge-one-file' by spawning a new process first. To avoid this, this moves merge_one_path(), merge_all(), and their helpers to merge-strategies.c. They also take a callback to dictate what they should do for each file. For now, only one launching a new process is defined to preserve the behaviour of the builtin version. Signed-off-by: Alban Gruin --- Notes: This patch is best viewed with `--color-moved'. builtin/merge-index.c | 77 +++------------------------------ merge-strategies.c | 99 +++++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 17 ++++++++ 3 files changed, 123 insertions(+), 70 deletions(-) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 38ea6ad6ca..6cb666cc78 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,74 +1,11 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" -#include "run-command.h" - -static const char *pgm; -static int one_shot, quiet; -static int err; - -static int merge_entry(int pos, const char *path) -{ - int found; - const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL }; - char hexbuf[4][GIT_MAX_HEXSZ + 1]; - char ownbuf[4][60]; - - if (pos >= active_nr) - die("git merge-index: %s not in the cache", path); - found = 0; - do { - const struct cache_entry *ce = active_cache[pos]; - int stage = ce_stage(ce); - - if (strcmp(ce->name, path)) - break; - found++; - oid_to_hex_r(hexbuf[stage], &ce->oid); - xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); - arguments[stage] = hexbuf[stage]; - arguments[stage + 4] = ownbuf[stage]; - } while (++pos < active_nr); - if (!found) - die("git merge-index: %s not in the cache", path); - - if (run_command_v_opt(arguments, 0)) { - if (one_shot) - err++; - else { - if (!quiet) - die("merge program failed"); - exit(1); - } - } - return found; -} - -static void merge_one_path(const char *path) -{ - int pos = cache_name_pos(path, strlen(path)); - - /* - * If it already exists in the cache as stage0, it's - * already merged and there is nothing to do. - */ - if (pos < 0) - merge_entry(-pos-1, path); -} - -static void merge_all(void) -{ - int i; - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - i += merge_entry(i, ce->name)-1; - } -} +#include "merge-strategies.h" int cmd_merge_index(int argc, const char **argv, const char *prefix) { - int i, force_file = 0; + int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; + const char *pgm; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -98,14 +35,14 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-a")) { - merge_all(); + err |= merge_all(&the_index, one_shot, quiet, + merge_program_cb, (void *)pgm); continue; } die("git merge-index: unknown option %s", arg); } - merge_one_path(arg); + err |= merge_one_path(&the_index, one_shot, quiet, arg, + merge_program_cb, (void *)pgm); } - if (err && !quiet) - die("merge program failed"); return err; } diff --git a/merge-strategies.c b/merge-strategies.c index 3a9fce9f22..f4c0b4acd6 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,6 +1,7 @@ #include "cache.h" #include "dir.h" #include "merge-strategies.h" +#include "run-command.h" #include "xdiff-interface.h" static int add_to_index_cacheinfo(struct index_state *istate, @@ -189,3 +190,101 @@ int merge_strategies_one_file(struct repository *r, return 0; } + +int merge_program_cb(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data) +{ + char ownbuf[3][60] = {{0}}; + const char *arguments[] = { (char *)data, "", "", "", path, + ownbuf[0], ownbuf[1], ownbuf[2], + NULL }; + + if (orig_blob) + arguments[1] = oid_to_hex(orig_blob); + if (our_blob) + arguments[2] = oid_to_hex(our_blob); + if (their_blob) + arguments[3] = oid_to_hex(their_blob); + + xsnprintf(ownbuf[0], sizeof(ownbuf[0]), "%o", orig_mode); + xsnprintf(ownbuf[1], sizeof(ownbuf[1]), "%o", our_mode); + xsnprintf(ownbuf[2], sizeof(ownbuf[2]), "%o", their_mode); + + return run_command_v_opt(arguments, 0); +} + +static int merge_entry(struct index_state *istate, int quiet, int pos, + const char *path, merge_cb cb, void *data) +{ + int found = 0; + const struct object_id *oids[3] = {NULL}; + unsigned int modes[3] = {0}; + + do { + const struct cache_entry *ce = istate->cache[pos]; + int stage = ce_stage(ce); + + if (strcmp(ce->name, path)) + break; + found++; + oids[stage - 1] = &ce->oid; + modes[stage - 1] = ce->ce_mode; + } while (++pos < istate->cache_nr); + if (!found) + return error(_("%s is not in the cache"), path); + + if (cb(oids[0], oids[1], oids[2], path, modes[0], modes[1], modes[2], data)) { + if (!quiet) + error(_("Merge program failed")); + return -2; + } + + return found; +} + +int merge_one_path(struct index_state *istate, int oneshot, int quiet, + const char *path, merge_cb cb, void *data) +{ + int pos = index_name_pos(istate, path, strlen(path)), ret; + + /* + * If it already exists in the cache as stage0, it's + * already merged and there is nothing to do. + */ + if (pos < 0) { + ret = merge_entry(istate, quiet, -pos - 1, path, cb, data); + if (ret == -1) + return -1; + else if (ret == -2) + return 1; + } + return 0; +} + +int merge_all(struct index_state *istate, int oneshot, int quiet, + merge_cb cb, void *data) +{ + int err = 0, i, ret; + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; + if (!ce_stage(ce)) + continue; + + ret = merge_entry(istate, quiet, i, ce->name, cb, data); + if (ret > 0) + i += ret - 1; + else if (ret == -1) + return -1; + else if (ret == -2) { + if (oneshot) + err++; + else + return 1; + } + } + + return err; +} diff --git a/merge-strategies.h b/merge-strategies.h index b527d145c7..cf78d7eaf4 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -10,4 +10,21 @@ int merge_strategies_one_file(struct repository *r, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode); +typedef int (*merge_cb)(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data); + +int merge_program_cb(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data); + +int merge_one_path(struct index_state *istate, int oneshot, int quiet, + const char *path, merge_cb cb, void *data); +int merge_all(struct index_state *istate, int oneshot, int quiet, + merge_cb cb, void *data); + #endif /* MERGE_STRATEGIES_H */ From patchwork Thu Jun 25 12:19:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625173 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2441B6C1 for ; Thu, 25 Jun 2020 12:49:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 01F502072E for ; Thu, 25 Jun 2020 12:49:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MkjQb9EJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404829AbgFYMtN (ORCPT ); Thu, 25 Jun 2020 08:49:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59320 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404801AbgFYMtE (ORCPT ); Thu, 25 Jun 2020 08:49:04 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A889C061795 for ; Thu, 25 Jun 2020 05:49:04 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id t194so5794020wmt.4 for ; Thu, 25 Jun 2020 05:49:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1E+2npJRgqglnF1txGs5ji9IXN0R4z5sFf/stpPXp7k=; b=MkjQb9EJiW2LsUa4uD45+OgeIUULZuJHYEgLxDJ+gzV23UdRBjTGC2XKw8YncUpE7c qJH9Lr3k22pXWMSLG/4HqGMTeLBleoIF2QR+mhynXE78KUWYV++4RZXpyHNI45iabzxM sksulbejOpHwpeC2b5J4LN+dTyJn5+UhTPp1jsQ0Qvc/gD8kaCzq6TLhrddabTTK9LNf hXEfMRFO2/+kPVM2wmS/2AsDeaaVPbG6PTLwaF6LHmSa1PXIeFv76iL6giOo41FU9n/m 1qX5Q1GpeT/jU94ew7oRTg7lGsTqd728QCp4lUy6GMjSOlkfu/tqHe8CT5scLzSO/FM8 g6Dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1E+2npJRgqglnF1txGs5ji9IXN0R4z5sFf/stpPXp7k=; b=uedWtilX/NUWeVmsqvS0t9tdDgW4ximFjzmpJ7UAWYnuLx60ekcgSNvtPitvngLFSV WmVSKEcS/vNaqCxeEAAsNP87e1w8IaWUT/C9XPTjoIkhikK1QcFvjQWjc1MKTuaOgGAQ 1muWX2KRBwq74YeARxUZkH4wHz5LuE/iswUS96bw0I24811cL6fc9igf5xhD1yaEDYsy P8GswW8+vaXmY9wMQV14/KIHpymcEHD0ZuskE8WanTMdCcIMbpbhDSDusaDoZ3Ic8TUQ FiSJj4XP0lex2uWq3FfQ7bxa81jHlenS1qHqxLq5xn43Gav1Oxi5Md4W+Ihi4EVC8QJX Anyg== X-Gm-Message-State: AOAM531t1PXQLnYuje39Ao4U3mDo0FzNyDOQsqTcRdqC6zYzY/CC6H9i oYjcvibH6ya9gZtwTH0K/clxLS4r X-Google-Smtp-Source: ABdhPJz/k63D815JnJSkycoDvyEMl57iXiK9S/AJ73vEKMCd5uHI1Znj+Ak7TaGWjtTTTDAoxV8OcQ== X-Received: by 2002:a7b:c185:: with SMTP id y5mr3291091wmi.85.1593089342647; Thu, 25 Jun 2020 05:49:02 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:02 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 07/17] merge-resolve: rewrite in C Date: Thu, 25 Jun 2020 14:19:43 +0200 Message-Id: <20200625121953.16991-8-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-resolve' from shell to C. As for `git merge-one-file', this port keeps using external processes for operations on the index, or to call `git merge-one-file'. This will be addressed in the next two commits. The parameters of merge_resolve() will be surprising at first glance: why using a commit list for `bases' and `remote', where we could use an oid array, and a pointer to an oid? Because, in a later commit, try_merge_strategy() will be able to call merge_resolve() directly, and it already uses a commit list for `bases' (`common') and `remote' (`remoteheads'), and a string for `head_arg'. To reduce frictions later, merge_resolve() takes the same types of parameters. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-resolve.c | 112 ++++++++++++++++++++++++++++++++++++++++ git-merge-resolve.sh | 54 ------------------- git.c | 1 + 5 files changed, 115 insertions(+), 55 deletions(-) create mode 100644 builtin/merge-resolve.c delete mode 100755 git-merge-resolve.sh diff --git a/Makefile b/Makefile index 1ab4d160cb..ccea651ac8 100644 --- a/Makefile +++ b/Makefile @@ -596,7 +596,6 @@ SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-merge-octopus.sh -SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-request-pull.sh @@ -1092,6 +1091,7 @@ BUILTIN_OBJS += builtin/merge-index.o BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o +BUILTIN_OBJS += builtin/merge-resolve.o BUILTIN_OBJS += builtin/merge-tree.o BUILTIN_OBJS += builtin/merge.o BUILTIN_OBJS += builtin/mktag.o diff --git a/builtin.h b/builtin.h index 9205d5ecdc..6ea207c9fd 100644 --- a/builtin.h +++ b/builtin.h @@ -174,6 +174,7 @@ int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); int cmd_merge_one_file(int argc, const char **argv, const char *prefix); int cmd_merge_recursive(int argc, const char **argv, const char *prefix); +int cmd_merge_resolve(int argc, const char **argv, const char *prefix); int cmd_merge_tree(int argc, const char **argv, const char *prefix); int cmd_mktag(int argc, const char **argv, const char *prefix); int cmd_mktree(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-resolve.c b/builtin/merge-resolve.c new file mode 100644 index 0000000000..c66fef7b7f --- /dev/null +++ b/builtin/merge-resolve.c @@ -0,0 +1,112 @@ +/* + * Builtin "git merge-resolve" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-resolve.sh, written by Linus Torvalds and Junio C + * Hamano. + * + * Resolve two trees, using enhanced multi-base read-tree. + */ + +#include "cache.h" +#include "builtin.h" +#include "run-command.h" + +static int merge_resolve(struct commit_list *bases, const char *head_arg, + struct commit_list *remote) +{ + struct commit_list *j; + struct child_process cp_update = CHILD_PROCESS_INIT, + cp_read = CHILD_PROCESS_INIT, + cp_write = CHILD_PROCESS_INIT; + + cp_update.git_cmd = 1; + argv_array_pushl(&cp_update.args, "update-index", "-q", "--refresh", NULL); + run_command(&cp_update); + + cp_read.git_cmd = 1; + argv_array_pushl(&cp_read.args, "read-tree", "-u", "-m", "--aggressive", NULL); + + for (j = bases; j && j->item; j = j->next) + argv_array_push(&cp_read.args, oid_to_hex(&j->item->object.oid)); + + if (head_arg) + argv_array_push(&cp_read.args, head_arg); + if (remote && remote->item) + argv_array_push(&cp_read.args, oid_to_hex(&remote->item->object.oid)); + + if (run_command(&cp_read)) + return 2; + + puts("Trying simple merge."); + + cp_write.git_cmd = 1; + cp_write.no_stdout = 1; + cp_write.no_stderr = 1; + argv_array_push(&cp_write.args, "write-tree"); + if (run_command(&cp_write)) { + struct child_process cp_merge = CHILD_PROCESS_INIT; + + puts("Simple merge failed, trying Automatic merge."); + + cp_merge.git_cmd = 1; + argv_array_pushl(&cp_merge.args, "merge-index", "-o", + "git-merge-one-file", "-a", NULL); + if (run_command(&cp_merge)) + return 1; + } + + return 0; +} + +static const char builtin_merge_resolve_usage[] = + "git merge-resolve ... -- "; + +int cmd_merge_resolve(int argc, const char **argv, const char *prefix) +{ + int i, is_baseless = 1, sep_seen = 0; + const char *head = NULL; + struct commit_list *bases = NULL, *remote = NULL; + struct commit_list **next_base = &bases; + + if (argc < 5) + usage(builtin_merge_resolve_usage); + + /* The first parameters up to -- are merge bases; the rest are + * heads. */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--") == 0) + sep_seen = 1; + else if (strcmp(argv[i], "-h") == 0) + usage(builtin_merge_resolve_usage); + else if (sep_seen && !head) + head = argv[i]; + else if (remote) { + /* Give up if we are given two or more remotes. + * Not handling octopus. */ + return 2; + } else { + struct object_id oid; + + get_oid(argv[i], &oid); + is_baseless &= sep_seen; + + if (!oideq(&oid, the_hash_algo->empty_tree)) { + struct commit *commit; + commit = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + commit_list_append(commit, &remote); + else + next_base = commit_list_append(commit, next_base); + } + } + } + + /* Give up if this is a baseless merge. */ + if (is_baseless) + return 2; + + return merge_resolve(bases, head, remote); +} diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh deleted file mode 100755 index 343fe7bccd..0000000000 --- a/git-merge-resolve.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two trees, using enhanced multi-base read-tree. - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Give up if we are given two or more remotes -- not handling octopus. -case "$remotes" in -?*' '?*) - exit 2 ;; -esac - -# Give up if this is a baseless merge. -if test '' = "$bases" -then - exit 2 -fi - -git update-index -q --refresh -git read-tree -u -m --aggressive $bases $head $remotes || exit 2 -echo "Trying simple merge." -if result_tree=$(git write-tree 2>/dev/null) -then - exit 0 -else - echo "Simple merge failed, trying Automatic merge." - if git merge-index -o git-merge-one-file -a - then - exit 0 - else - exit 1 - fi -fi diff --git a/git.c b/git.c index 058d91a2a5..2e92019493 100644 --- a/git.c +++ b/git.c @@ -536,6 +536,7 @@ static struct cmd_struct commands[] = { { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-resolve", cmd_merge_resolve, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT }, { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, From patchwork Thu Jun 25 12:19:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625171 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D16EE6C1 for ; Thu, 25 Jun 2020 12:49:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ADBD82072E for ; Thu, 25 Jun 2020 12:49:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hMzHyVCQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404825AbgFYMtM (ORCPT ); Thu, 25 Jun 2020 08:49:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59324 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404803AbgFYMtF (ORCPT ); Thu, 25 Jun 2020 08:49:05 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E3A7C061796 for ; Thu, 25 Jun 2020 05:49:05 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id a6so5714144wrm.4 for ; Thu, 25 Jun 2020 05:49:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CN6fUU7/hu7NvBTxy4af5w0M00mlHTF4zQlGrg0jgpc=; b=hMzHyVCQTGzYhs8K3ajhiV2vA8czEfwfX2MR5Xp912JVnm1xco7z6gLumZKb0Gdwnz bNSv5Pu+enlIW56uPS3jIfl6LokyEI+YPoauNQ4twRqfxnXXTzDIOkUcg/Cuk5UjpqFb oj48InpWuVli9rGPzfMczdL48HHJYETZ36K8Ytql/ocPip7HMMc6ahUWN7g/XXGp7m7w H1J0qRVA+QzRPYam+ELVTKrjZ37wt65FUIv94oTp4LR4Gux9QVQZBn37LV09b6xGRgJz 2A2zxsESe0PtC0vRv+ycLJBKIPMDKyOV3aPX683ItDByJZdO1Vpk4uVEJ26ChkThTwrT TgdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CN6fUU7/hu7NvBTxy4af5w0M00mlHTF4zQlGrg0jgpc=; b=mF76GFpfbQnKcVSM+Y0SAgRYnFmax9Gk3POv4UctDgO1DiLg5eslxp3V+AcF5oPNBC Gq+HWCDY97jlHkqaJ/zxAphZd3b0Cvc5lpVCqwSJV48CZD/iap7B1UTpkc0iYRLqK+BC +goyBIDE1ryRPbF+PtnFzLVD2AvWxtg06MvnqUhO9EvzEbyoLinc0RSdCFJC289pV7Do FEpVRY4mkKp2oI7XitHM2h4w2jR2Uy4meWhIgOMY+R+hDs+Dw/ouvIkkPs1hKDo0A7ew 1e4o2VBULKqwKyn6IeLxabfY6tZiNED1hPQOMSESp75AAzJjpWh0Se6RYef02bNWWwuc GEgw== X-Gm-Message-State: AOAM531fPDJ+54mobQ5MnTCDsgCfgB+8YGqJFm9eH0wLcj6H3nvBHnDJ QeNdlRnoGR4ae1Q4Qm+13wFsoFJ4 X-Google-Smtp-Source: ABdhPJwUKSnstKH9aMrEPWenj7B+3xaseQwKicmVZE5jAl4je2ZXY1+AmPnXQ8kI1yjCsSYeC0q2+Q== X-Received: by 2002:adf:ec8c:: with SMTP id z12mr34699910wrn.281.1593089343732; Thu, 25 Jun 2020 05:49:03 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:03 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 08/17] merge-resolve: remove calls to external processes Date: Thu, 25 Jun 2020 14:19:44 +0200 Message-Id: <20200625121953.16991-9-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This removes calls to external processes to avoid reading and writing the index over and over again. - The call to `update-index -q --refresh' is replaced by a call to refresh_index(). - The call to `read-tree' is replaced by a call to unpack_trees() (and all the setup needed). - The call to `write-tree' is replaced by a call to write_index_as_tree(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to the new merge_all() function. A callback function, merge_one_file_cb(), is added to allow it to call merge_one_file() without forking. Here too, the index is read in cmd_merge_resolve(), but merge_resolve() takes care of writing it back to the disk. Signed-off-by: Alban Gruin --- builtin/merge-resolve.c | 103 ++++++++++++++++++++++++++++------------ merge-strategies.c | 11 +++++ merge-strategies.h | 6 +++ 3 files changed, 89 insertions(+), 31 deletions(-) diff --git a/builtin/merge-resolve.c b/builtin/merge-resolve.c index c66fef7b7f..2c364fcdb0 100644 --- a/builtin/merge-resolve.c +++ b/builtin/merge-resolve.c @@ -10,54 +10,91 @@ */ #include "cache.h" +#include "cache-tree.h" #include "builtin.h" -#include "run-command.h" +#include "lockfile.h" +#include "merge-strategies.h" +#include "unpack-trees.h" + +static int add_tree(const struct object_id *oid, struct tree_desc *t) +{ + struct tree *tree; + + tree = parse_tree_indirect(oid); + if (parse_tree(tree)) + return -1; + + init_tree_desc(t, tree->buffer, tree->size); + return 0; +} static int merge_resolve(struct commit_list *bases, const char *head_arg, struct commit_list *remote) { + int i = 0; + struct lock_file lock = LOCK_INIT; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct object_id head, oid; struct commit_list *j; - struct child_process cp_update = CHILD_PROCESS_INIT, - cp_read = CHILD_PROCESS_INIT, - cp_write = CHILD_PROCESS_INIT; - - cp_update.git_cmd = 1; - argv_array_pushl(&cp_update.args, "update-index", "-q", "--refresh", NULL); - run_command(&cp_update); - - cp_read.git_cmd = 1; - argv_array_pushl(&cp_read.args, "read-tree", "-u", "-m", "--aggressive", NULL); - - for (j = bases; j && j->item; j = j->next) - argv_array_push(&cp_read.args, oid_to_hex(&j->item->object.oid)); if (head_arg) - argv_array_push(&cp_read.args, head_arg); - if (remote && remote->item) - argv_array_push(&cp_read.args, oid_to_hex(&remote->item->object.oid)); + get_oid(head_arg, &head); - if (run_command(&cp_read)) - return 2; + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); + refresh_index(the_repository->index, 0, NULL, NULL, NULL); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; + opts.update = 1; + opts.merge = 1; + opts.aggressive = 1; + + for (j = bases; j; j = j->next) { + if (add_tree(&j->item->object.oid, t + (i++))) + goto out; + } + + if (head_arg && add_tree(&head, t + (i++))) + goto out; + if (remote && add_tree(&remote->item->object.oid, t + (i++))) + goto out; + + if (i == 1) + opts.fn = oneway_merge; + else if (i == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(the_repository->index); + } else if (i >= 3) { + opts.fn = threeway_merge; + opts.head_idx = i - 1; + } + + if (unpack_trees(i, t, &opts)) + goto out; puts("Trying simple merge."); + write_locked_index(the_repository->index, &lock, COMMIT_LOCK); - cp_write.git_cmd = 1; - cp_write.no_stdout = 1; - cp_write.no_stderr = 1; - argv_array_push(&cp_write.args, "write-tree"); - if (run_command(&cp_write)) { - struct child_process cp_merge = CHILD_PROCESS_INIT; + if (write_index_as_tree(&oid, the_repository->index, + the_repository->index_file, 0, NULL)) { + int ret; - puts("Simple merge failed, trying Automatic merge."); + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); + ret = merge_all(the_repository->index, 0, 0, + merge_one_file_cb, the_repository); - cp_merge.git_cmd = 1; - argv_array_pushl(&cp_merge.args, "merge-index", "-o", - "git-merge-one-file", "-a", NULL); - if (run_command(&cp_merge)) - return 1; + write_locked_index(the_repository->index, &lock, COMMIT_LOCK); + return !!ret; } return 0; + + out: + rollback_lock_file(&lock); + return 2; } static const char builtin_merge_resolve_usage[] = @@ -73,6 +110,10 @@ int cmd_merge_resolve(int argc, const char **argv, const char *prefix) if (argc < 5) usage(builtin_merge_resolve_usage); + setup_work_tree(); + if (repo_read_index(the_repository) < 0) + die("invalid index"); + /* The first parameters up to -- are merge bases; the rest are * heads. */ for (i = 1; i < argc; i++) { diff --git a/merge-strategies.c b/merge-strategies.c index f4c0b4acd6..39bfa1af7b 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -191,6 +191,17 @@ int merge_strategies_one_file(struct repository *r, return 0; } +int merge_one_file_cb(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data) +{ + return merge_strategies_one_file((struct repository *)data, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); +} + int merge_program_cb(const struct object_id *orig_blob, const struct object_id *our_blob, const struct object_id *their_blob, const char *path, diff --git a/merge-strategies.h b/merge-strategies.h index cf78d7eaf4..40e175ca39 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -16,6 +16,12 @@ typedef int (*merge_cb)(const struct object_id *orig_blob, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, void *data); +int merge_one_file_cb(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data); + int merge_program_cb(const struct object_id *orig_blob, const struct object_id *our_blob, const struct object_id *their_blob, const char *path, From patchwork Thu Jun 25 12:19:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625169 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E4F9B138C for ; Thu, 25 Jun 2020 12:49:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C54DB20724 for ; Thu, 25 Jun 2020 12:49:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a6vyiCS8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404819AbgFYMtJ (ORCPT ); Thu, 25 Jun 2020 08:49:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59328 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404764AbgFYMtH (ORCPT ); Thu, 25 Jun 2020 08:49:07 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B4DB2C061573 for ; Thu, 25 Jun 2020 05:49:06 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id g75so5411836wme.5 for ; Thu, 25 Jun 2020 05:49:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8uWs8OBZ7TKTQ9bYiyxTNF1gqLcJ/CRc+feKkElRyM0=; b=a6vyiCS8efjVJRm8n9Rop9/F8XzMf7atBUkSkrNp4X851E2kb1i+l08WkB725VIZJo LW4JBSnR8rI77BwPVJW8+IyfOB5j1I+BjdPehUqs2glkKOyyaiQgFWpNWBX35xaOWAen PevAUTl9inE5rTCj11WrybwG8mnR73IyoY7/W/CUYuTzcuSpLfljJYfhb01ePpD4proV 7KhPb4AVpY2NoDeI5CzfEOZapzrnFkvSp5Ii4+omDX94UopV97u9ilb7uVEetpc24RDX c2ljz+bAUmrSpIODN/TNqSpKxhJy1i7R4l1mO4cX5qQugN+PZjr9JuXCe6UBVP6GCO6M 3nGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8uWs8OBZ7TKTQ9bYiyxTNF1gqLcJ/CRc+feKkElRyM0=; b=cDK7StQLzHYagS2izQTdTkj112YxKWLkPX6PqlJx/hJjqyUcV1QdnzFU94/CoIbLLE Hj+Ck7QRfpIonnKqzBzJ4N9VbsEPO/lImzHKoVirAxvqMmw2VODHYOhdRY9N3xLi4nMy KYL3EIhaOWcpdI6M2yWDl1qUo3WYgXyswo0v6mdSzJU6NsMlX69m7+zPwyqk8PLGDIAn O+OH+Z/ky54+P/vpntgBjTkhICJPOvemkbcfKNGO9jWcRxN2zuwGnnhCQzhYPFwFqJG/ E0dUzrcc4f7XG8Gq7Vou5ho7aX6vtX8ah7fwpDWWxbOl4XA9UCDD4f71xauzeN0+H9zF R0DQ== X-Gm-Message-State: AOAM533aeFeKr0NjK/z9n+oIeNRlN6TC39+vE+xSH9uefZX61ApHAxlQ nBO7VufXuBAl3viIWZtqhV+5/zzI X-Google-Smtp-Source: ABdhPJzQcFG24dCLy8kaWR+TP27zDIVP4cM1KQqDqA99ySADCoKigmsH2WupbbHZxvKbU3atGBKATg== X-Received: by 2002:a1c:4d05:: with SMTP id o5mr3224625wmh.130.1593089345012; Thu, 25 Jun 2020 05:49:05 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:04 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 09/17] merge-resolve: libify merge_resolve() Date: Thu, 25 Jun 2020 14:19:45 +0200 Message-Id: <20200625121953.16991-10-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This moves merge_resolve() (and its helper functions) to merge-strategies.c. This will enable `git merge' and the sequencer to directly call it instead of forking. Here too, this is not a faithful copy-and-paste; the new merge_resolve() (renamed merge_strategies_resolve()) takes a pointer to the repository, instead of using `the_repository'. Signed-off-by: Alban Gruin --- Notes: This patch is best viewed with `--color-moved'. builtin/merge-resolve.c | 86 +---------------------------------------- merge-strategies.c | 85 ++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 5 +++ 3 files changed, 91 insertions(+), 85 deletions(-) diff --git a/builtin/merge-resolve.c b/builtin/merge-resolve.c index 2c364fcdb0..59f734473b 100644 --- a/builtin/merge-resolve.c +++ b/builtin/merge-resolve.c @@ -10,92 +10,8 @@ */ #include "cache.h" -#include "cache-tree.h" #include "builtin.h" -#include "lockfile.h" #include "merge-strategies.h" -#include "unpack-trees.h" - -static int add_tree(const struct object_id *oid, struct tree_desc *t) -{ - struct tree *tree; - - tree = parse_tree_indirect(oid); - if (parse_tree(tree)) - return -1; - - init_tree_desc(t, tree->buffer, tree->size); - return 0; -} - -static int merge_resolve(struct commit_list *bases, const char *head_arg, - struct commit_list *remote) -{ - int i = 0; - struct lock_file lock = LOCK_INIT; - struct tree_desc t[MAX_UNPACK_TREES]; - struct unpack_trees_options opts; - struct object_id head, oid; - struct commit_list *j; - - if (head_arg) - get_oid(head_arg, &head); - - repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - refresh_index(the_repository->index, 0, NULL, NULL, NULL); - - memset(&opts, 0, sizeof(opts)); - opts.head_idx = 1; - opts.src_index = the_repository->index; - opts.dst_index = the_repository->index; - opts.update = 1; - opts.merge = 1; - opts.aggressive = 1; - - for (j = bases; j; j = j->next) { - if (add_tree(&j->item->object.oid, t + (i++))) - goto out; - } - - if (head_arg && add_tree(&head, t + (i++))) - goto out; - if (remote && add_tree(&remote->item->object.oid, t + (i++))) - goto out; - - if (i == 1) - opts.fn = oneway_merge; - else if (i == 2) { - opts.fn = twoway_merge; - opts.initial_checkout = is_index_unborn(the_repository->index); - } else if (i >= 3) { - opts.fn = threeway_merge; - opts.head_idx = i - 1; - } - - if (unpack_trees(i, t, &opts)) - goto out; - - puts("Trying simple merge."); - write_locked_index(the_repository->index, &lock, COMMIT_LOCK); - - if (write_index_as_tree(&oid, the_repository->index, - the_repository->index_file, 0, NULL)) { - int ret; - - repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - ret = merge_all(the_repository->index, 0, 0, - merge_one_file_cb, the_repository); - - write_locked_index(the_repository->index, &lock, COMMIT_LOCK); - return !!ret; - } - - return 0; - - out: - rollback_lock_file(&lock); - return 2; -} static const char builtin_merge_resolve_usage[] = "git merge-resolve ... -- "; @@ -149,5 +65,5 @@ int cmd_merge_resolve(int argc, const char **argv, const char *prefix) if (is_baseless) return 2; - return merge_resolve(bases, head, remote); + return merge_strategies_resolve(the_repository, bases, head, remote); } diff --git a/merge-strategies.c b/merge-strategies.c index 39bfa1af7b..a12c575590 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,7 +1,10 @@ #include "cache.h" +#include "cache-tree.h" #include "dir.h" +#include "lockfile.h" #include "merge-strategies.h" #include "run-command.h" +#include "unpack-trees.h" #include "xdiff-interface.h" static int add_to_index_cacheinfo(struct index_state *istate, @@ -299,3 +302,85 @@ int merge_all(struct index_state *istate, int oneshot, int quiet, return err; } + +static int add_tree(const struct object_id *oid, struct tree_desc *t) +{ + struct tree *tree; + + tree = parse_tree_indirect(oid); + if (parse_tree(tree)) + return -1; + + init_tree_desc(t, tree->buffer, tree->size); + return 0; +} + +int merge_strategies_resolve(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote) +{ + int i = 0; + struct lock_file lock = LOCK_INIT; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct object_id head, oid; + struct commit_list *j; + + if (head_arg) + get_oid(head_arg, &head); + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + refresh_index(r->index, 0, NULL, NULL, NULL); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = r->index; + opts.dst_index = r->index; + opts.update = 1; + opts.merge = 1; + opts.aggressive = 1; + + for (j = bases; j && j->item; j = j->next) { + if (add_tree(&j->item->object.oid, t + (i++))) + goto out; + } + + if (head_arg && add_tree(&head, t + (i++))) + goto out; + if (remote && add_tree(&remote->item->object.oid, t + (i++))) + goto out; + + if (i == 1) + opts.fn = oneway_merge; + else if (i == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(r->index); + } else if (i >= 3) { + opts.fn = threeway_merge; + opts.head_idx = i - 1; + } + + if (unpack_trees(i, t, &opts)) + goto out; + + puts("Trying simple merge."); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + if (write_index_as_tree(&oid, r->index, r->index_file, + WRITE_TREE_SILENT, NULL)) { + int ret; + + puts("Simple merge failed, trying Automatic merge."); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = merge_all(r->index, 0, 0, merge_one_file_cb, r); + + write_locked_index(r->index, &lock, COMMIT_LOCK); + return !!ret; + } + + return 0; + + out: + rollback_lock_file(&lock); + return 2; +} diff --git a/merge-strategies.h b/merge-strategies.h index 40e175ca39..778f8ce9d6 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -1,6 +1,7 @@ #ifndef MERGE_STRATEGIES_H #define MERGE_STRATEGIES_H +#include "commit.h" #include "object.h" int merge_strategies_one_file(struct repository *r, @@ -33,4 +34,8 @@ int merge_one_path(struct index_state *istate, int oneshot, int quiet, int merge_all(struct index_state *istate, int oneshot, int quiet, merge_cb cb, void *data); +int merge_strategies_resolve(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote); + #endif /* MERGE_STRATEGIES_H */ From patchwork Thu Jun 25 12:19:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625175 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6CBC56C1 for ; Thu, 25 Jun 2020 12:49:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 53D532072E for ; Thu, 25 Jun 2020 12:49:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CDoTlC1c" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404832AbgFYMtO (ORCPT ); Thu, 25 Jun 2020 08:49:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404800AbgFYMtI (ORCPT ); Thu, 25 Jun 2020 08:49:08 -0400 Received: from mail-wr1-x443.google.com (mail-wr1-x443.google.com [IPv6:2a00:1450:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D9748C0613ED for ; Thu, 25 Jun 2020 05:49:07 -0700 (PDT) Received: by mail-wr1-x443.google.com with SMTP id b6so5682154wrs.11 for ; Thu, 25 Jun 2020 05:49:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=u3q6LT8tzjTrVZzU8OLU0WIXhGYdhNBcBuI6j0C3xTI=; b=CDoTlC1c3pwuFasfu0N6G2KQNRM/XeLC87MoPvSMw8iGPr9QH/TYlPUluCI6Yky8Nd ls/5YDPFuo0xpr6sjLjcnQVr+pfe0q2kOqJ9M/Fi5u9oOoWc8C/gfQo44sWYVx5OQJf7 OkMue0S8PE4fD8WXdSKOZwqPl9urTRiuw5PSUpFsq/enfJLBvdiSf+ssh2OZu8VhhS1x qmWymxUmRwK7gzaVHjE+aR67hvpSx723uLZYi084RIXWDFJG4hAT+tgr1f7Y6xk2xHro WWudUIsiGlPlXBoNZEep+ySpsz7L+1O0hMZ0yFPmpK+I0vO9CEveqvmunuJcC4SrStsY LRaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=u3q6LT8tzjTrVZzU8OLU0WIXhGYdhNBcBuI6j0C3xTI=; b=CachlVBZODZn/BGaBB7VWNhoWZH9u7oSMg/YnOY8UZU8nllrhRuDFHZjUZbttrGmlK Z4NLwuhbeGTsQiByspk0WI+wDfiI7lR1xvGfzfRslS/+N0CIUK+LTXSfz0cpAv0J/XO3 nGlyr8zBTTqKsRh8FBbjcLx+n2MdUerG+uCHAZqQF8EnSLaUhCTvF0mPRr1wNSRbVwuH AVi1ny02x17dPohkkrksWw9yp2eI89rCjK+DpvcS/YWaJcNkFCydqKCVkaueFvxKxNuf qXl1UlGfH8FSL7GGTGw6zQpiTvT2t5eplNGowz9kyXKUMks/5JreXaos/n3oNLqR7brY gBkQ== X-Gm-Message-State: AOAM531eI4xM2ulEYCxxzm7svq7x7PZU9UV9Y3uZml0tagE7m7ziDfyE Uad9sQUdw12g6f7AbnyrwchPfk2r X-Google-Smtp-Source: ABdhPJzCza06lHXrRfXBr+lTUGUt/nsJ+Q0iNtk5N5lTMrrwKG0Y+ag9etE/MeGiqLRgzSlQQk0VVw== X-Received: by 2002:a5d:40c9:: with SMTP id b9mr5380389wrq.425.1593089346352; Thu, 25 Jun 2020 05:49:06 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:05 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 10/17] merge-recursive: move better_branch_name() to merge.c Date: Thu, 25 Jun 2020 14:19:46 +0200 Message-Id: <20200625121953.16991-11-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org get_better_branch_name() will be used by rebase-octopus once it is rewritten in C, so instead of duplicating it, this moves this function preventively inside an appropriate file in libgit.a. This function is also renamed to reflect its usage by merge strategies. Signed-off-by: Alban Gruin --- Notes: This patch is best viewed with `--color-moved'. builtin/merge-recursive.c | 16 ++-------------- cache.h | 2 +- merge.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index a4bfd8fc51..972243b5e9 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -8,18 +8,6 @@ static const char builtin_merge_recursive_usage[] = "git %s ... -- ..."; -static char *better_branch_name(const char *branch) -{ - static char githead_env[8 + GIT_MAX_HEXSZ + 1]; - char *name; - - if (strlen(branch) != the_hash_algo->hexsz) - return xstrdup(branch); - xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); - name = getenv(githead_env); - return xstrdup(name ? name : branch); -} - int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { const struct object_id *bases[21]; @@ -75,8 +63,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (get_oid(o.branch2, &h2)) die(_("could not resolve ref '%s'"), o.branch2); - o.branch1 = better1 = better_branch_name(o.branch1); - o.branch2 = better2 = better_branch_name(o.branch2); + o.branch1 = better1 = merge_get_better_branch_name(o.branch1); + o.branch2 = better2 = merge_get_better_branch_name(o.branch2); if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); diff --git a/cache.h b/cache.h index 0f0485ecfe..bbbd8e352d 100644 --- a/cache.h +++ b/cache.h @@ -1915,7 +1915,7 @@ int checkout_fast_forward(struct repository *r, const struct object_id *from, const struct object_id *to, int overwrite_ignore); - +char *merge_get_better_branch_name(const char *branch); int sane_execvp(const char *file, char *const argv[]); diff --git a/merge.c b/merge.c index aa36de2f64..5f3d05268f 100644 --- a/merge.c +++ b/merge.c @@ -108,3 +108,15 @@ int checkout_fast_forward(struct repository *r, return error(_("unable to write new index file")); return 0; } + +char *merge_get_better_branch_name(const char *branch) +{ + static char githead_env[8 + GIT_MAX_HEXSZ + 1]; + char *name; + + if (strlen(branch) != the_hash_algo->hexsz) + return xstrdup(branch); + xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); + name = getenv(githead_env); + return xstrdup(name ? name : branch); +} From patchwork Thu Jun 25 12:19:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625185 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A9B55138C for ; Thu, 25 Jun 2020 12:49:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 87DE82072E for ; Thu, 25 Jun 2020 12:49:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="j9g9pr4G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404858AbgFYMtY (ORCPT ); Thu, 25 Jun 2020 08:49:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404764AbgFYMtK (ORCPT ); Thu, 25 Jun 2020 08:49:10 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BB55C061573 for ; Thu, 25 Jun 2020 05:49:09 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id j18so5422503wmi.3 for ; Thu, 25 Jun 2020 05:49:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=h6LNQR8TLUF5w20Nq3bDxlRZqG2adjZzp/V+fgGaBDs=; b=j9g9pr4GDE2qk2U9RmoOTvEIBa2hAIL10HsrlRF2z8rG+XcpWe5cPJFvb7cdzRsw26 jc+I1FGyt8cwDMrcMwi7mKvIU07bhKHR5JXL+RXUiP62dG8Y7sMMQxizBT81npf04/AW iUImvy3RvyTV84QL6hIChA0ecvnTUsdUiYFYthwKxWouKhqqyHiuToThnZICYosO171e +uaObi8AuD8LcqRiG9mVAYFvWZlXK5VkGP1PYPft/aboRrzq6JcliY0lpuSWl3JT4JHf I9RSoPzL6daPw/9ThKVBu/k6CiuD2+BCPicAoEdAaL9ivQYLY/w/5Urdxum1IydRVYpD BO/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=h6LNQR8TLUF5w20Nq3bDxlRZqG2adjZzp/V+fgGaBDs=; b=hskLi6wXcX9iwW6zeFkMWY3BSvKix/W1cNHNmHrZCF80mapcmln5kn/ShCwheneXPT gQBufhN9+Ux46IyFrWbxW6fQPF/UdySACajEb0JlF+jU+E9s0IYmFgvwgNReVnZulSnu 4E7npS9KPhKkIRV3HfGTCVV13mj6QhuPt/ezU9wZHqNNWFj1uwuUWYUv8DMl9COhRYIV CTTvTZ+AaijevWxxBDmO2CBuTXj6JxQRl/795E3qmcbYwR9xvA8vW1nGLdI0OdKfrZ2V WKpta2c5n2cLNApRtdrQxGXulHk9MAjmfzl3AtfS62Ax6l48VihbVeCgvAWnxgYAl5Nc rBWA== X-Gm-Message-State: AOAM531gqFJJKRYLm5wSq2QYThux9KQt6QmH5NTWIopNpbI61e3rOHId xZi8Z8lq8HXK4IBPTwqQee4lMnLB X-Google-Smtp-Source: ABdhPJyMh/4t32+VlzZWhVMRmN7nq9KVQQa/kTvE7h+AVYyHGPMXWLoCVMVX7cfCIn30Xfji4Bb7KA== X-Received: by 2002:a1c:80d3:: with SMTP id b202mr3301090wmd.111.1593089347627; Thu, 25 Jun 2020 05:49:07 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:07 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 11/17] merge-octopus: rewrite in C Date: Thu, 25 Jun 2020 14:19:47 +0200 Message-Id: <20200625121953.16991-12-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-octopus' from shell to C. As for the two last conversions, this port keeps using external processes for operations on the index, or to call `git merge-one-file'. This will be addressed in the next two commits. Here to, merge_octopus() takes two commit lists and a string to reduce frictions when try_merge_strategies() will be modified to call it directly. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-octopus.c | 241 ++++++++++++++++++++++++++++++++++++++++ git-merge-octopus.sh | 112 ------------------- git.c | 1 + 5 files changed, 244 insertions(+), 113 deletions(-) create mode 100644 builtin/merge-octopus.c delete mode 100755 git-merge-octopus.sh diff --git a/Makefile b/Makefile index ccea651ac8..8f45a3ec03 100644 --- a/Makefile +++ b/Makefile @@ -595,7 +595,6 @@ unexport CDPATH SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh -SCRIPT_SH += git-merge-octopus.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-request-pull.sh @@ -1088,6 +1087,7 @@ BUILTIN_OBJS += builtin/mailsplit.o BUILTIN_OBJS += builtin/merge-base.o BUILTIN_OBJS += builtin/merge-file.o BUILTIN_OBJS += builtin/merge-index.o +BUILTIN_OBJS += builtin/merge-octopus.o BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o diff --git a/builtin.h b/builtin.h index 6ea207c9fd..5a587ab70c 100644 --- a/builtin.h +++ b/builtin.h @@ -170,6 +170,7 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix); int cmd_merge(int argc, const char **argv, const char *prefix); int cmd_merge_base(int argc, const char **argv, const char *prefix); int cmd_merge_index(int argc, const char **argv, const char *prefix); +int cmd_merge_octopus(int argc, const char **argv, const char *prefix); int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); int cmd_merge_one_file(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-octopus.c b/builtin/merge-octopus.c new file mode 100644 index 0000000000..6216beaa2b --- /dev/null +++ b/builtin/merge-octopus.c @@ -0,0 +1,241 @@ +/* + * Builtin "git merge-octopus" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-octopus.sh, written by Junio C Hamano. + * + * Resolve two or more trees. + */ + +#include "cache.h" +#include "builtin.h" +#include "commit-reach.h" +#include "lockfile.h" +#include "run-command.h" +#include "unpack-trees.h" + +static int write_tree(struct tree **reference_tree) +{ + struct child_process cp = CHILD_PROCESS_INIT; + struct strbuf read_tree = STRBUF_INIT, err = STRBUF_INIT; + struct object_id oid; + int ret; + + cp.git_cmd = 1; + argv_array_push(&cp.args, "write-tree"); + ret = pipe_command(&cp, NULL, 0, &read_tree, 0, &err, 0); + if (err.len > 0) + fputs(err.buf, stderr); + + strbuf_trim_trailing_newline(&read_tree); + get_oid(read_tree.buf, &oid); + + *reference_tree = lookup_tree(the_repository, &oid); + + strbuf_release(&read_tree); + strbuf_release(&err); + child_process_clear(&cp); + + return ret; +} + +static int merge_octopus(struct commit_list *bases, const char *head_arg, + struct commit_list *remotes) +{ + int non_ff_merge = 0, ret = 0, references = 1; + struct commit **reference_commit; + struct tree *reference_tree; + struct commit_list *j; + struct object_id head; + + get_oid(head_arg, &head); + reference_commit = xcalloc(commit_list_count(remotes) + 1, sizeof(struct commit *)); + reference_commit[0] = lookup_commit_reference(the_repository, &head); + reference_tree = get_commit_tree(reference_commit[0]); + + for (j = remotes; j; j = j->next) { + struct commit *c = j->item; + struct object_id *oid = &c->object.oid; + struct commit_list *common, *k; + char *branch_name; + int can_ff = 1; + + if (ret) { + puts(_("Automated merge did not work.")); + puts(_("Should not be doing an octopus.")); + + ret = 2; + goto out; + } + + branch_name = merge_get_better_branch_name(oid_to_hex(oid)); + common = get_merge_bases_many(c, references, reference_commit); + + if (!common) + die(_("Unable to find common commit with %s"), branch_name); + + for (k = common; k && !oideq(&k->item->object.oid, oid); k = k->next); + + if (k) { + printf(_("Already up to date with %s\n"), branch_name); + free(branch_name); + free_commit_list(common); + continue; + } + + if (!non_ff_merge) { + int i; + + for (i = 0, k = common; k && i < references && can_ff; k = k->next, i++) { + can_ff = oideq(&k->item->object.oid, + &reference_commit[i]->object.oid); + } + } + + if (!non_ff_merge && can_ff) { + struct child_process cp = CHILD_PROCESS_INIT; + + printf(_("Fast-forwarding to: %s\n"), branch_name); + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "read-tree", "-u", "-m", NULL); + argv_array_push(&cp.args, oid_to_hex(&head)); + argv_array_push(&cp.args, oid_to_hex(oid)); + + ret = run_command(&cp); + if (ret) { + free(branch_name); + free_commit_list(common); + goto out; + } + + child_process_clear(&cp); + references = 0; + write_tree(&reference_tree); + } else { + struct commit_list *l; + struct tree *next = NULL; + struct child_process cp = CHILD_PROCESS_INIT; + + non_ff_merge = 1; + printf(_("Trying simple merge with %s\n"), branch_name); + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "read-tree", "-u", "-m", "--aggressive", NULL); + + for (l = common; l; l = l->next) + argv_array_push(&cp.args, oid_to_hex(&l->item->object.oid)); + + argv_array_push(&cp.args, oid_to_hex(&reference_tree->object.oid)); + argv_array_push(&cp.args, oid_to_hex(oid)); + + if (run_command(&cp)) { + ret = 2; + + free(branch_name); + free_commit_list(common); + + goto out; + } + + child_process_clear(&cp); + + if (write_tree(&next)) { + struct child_process cp = CHILD_PROCESS_INIT; + puts(_("Simple merge did not work, trying automatic merge.")); + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "merge-index", "-o", + "git-merge-one-file", "-a", NULL); + if (run_command(&cp)) + ret = 1; + + child_process_clear(&cp); + write_tree(&next); + } + + reference_tree = next; + } + + reference_commit[references++] = c; + + free(branch_name); + free_commit_list(common); + } + +out: + free(reference_commit); + return ret; +} + +static const char builtin_merge_octopus_usage[] = + "git merge-octopus [...] -- [...]"; + +int cmd_merge_octopus(int argc, const char **argv, const char *prefix) +{ + int i, sep_seen = 0; + struct commit_list *bases = NULL, *remotes = NULL; + struct commit_list **next_base = &bases, **next_remote = &remotes; + const char *head_arg = NULL; + struct child_process cp = CHILD_PROCESS_INIT; + struct strbuf files = STRBUF_INIT; + + if (argc < 5) + usage(builtin_merge_octopus_usage); + + /* The first parameters up to -- are merge bases; the rest are + * heads. */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--") == 0) + sep_seen = 1; + else if (strcmp(argv[i], "-h") == 0) + usage(builtin_merge_octopus_usage); + else if (sep_seen && !head_arg) + head_arg = argv[i]; + else { + struct object_id oid; + + get_oid(argv[i], &oid); + + if (!oideq(&oid, the_hash_algo->empty_tree)) { + struct commit *commit; + commit = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + next_remote = commit_list_append(commit, next_remote); + else + next_base = commit_list_append(commit, next_base); + } + } + } + + /* Reject if this is not an octopus -- resolve should be used + * instead. */ + if (commit_list_count(remotes) < 2) + return 2; + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "diff-index", "--cached", + "--name-only", "HEAD", "--", NULL); + pipe_command(&cp, NULL, 0, &files, 0, NULL, 0); + child_process_clear(&cp); + + if (files.len > 0) { + struct strbuf **s, **b; + + s = strbuf_split(&files, '\n'); + + fprintf(stderr, _("Error: Your local changes to the following " + "files would be overwritten by merge\n")); + + for (b = s; *b; b++) + fprintf(stderr, " %.*s", (int)(*b)->len, (*b)->buf); + + strbuf_list_free(s); + strbuf_release(&files); + return 2; + } + + return merge_octopus(bases, head_arg, remotes); +} diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh deleted file mode 100755 index 7d19d37951..0000000000 --- a/git-merge-octopus.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two or more trees. -# - -. git-sh-setup - -LF=' -' - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Reject if this is not an octopus -- resolve should be used instead. -case "$remotes" in -?*' '?*) - ;; -*) - exit 2 ;; -esac - -# MRC is the current "merge reference commit" -# MRT is the current "merge result tree" - -if ! git diff-index --quiet --cached HEAD -- -then - gettextln "Error: Your local changes to the following files would be overwritten by merge" - git diff-index --cached --name-only HEAD -- | sed -e 's/^/ /' - exit 2 -fi -MRC=$(git rev-parse --verify -q $head) -MRT=$(git write-tree) -NON_FF_MERGE=0 -OCTOPUS_FAILURE=0 -for SHA1 in $remotes -do - case "$OCTOPUS_FAILURE" in - 1) - # We allow only last one to have a hand-resolvable - # conflicts. Last round failed and we still had - # a head to merge. - gettextln "Automated merge did not work." - gettextln "Should not be doing an octopus." - exit 2 - esac - - eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} - if test "$SHA1" = "$pretty_name" - then - SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)" - eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} - fi - common=$(git merge-base --all $SHA1 $MRC) || - die "$(eval_gettext "Unable to find common commit with \$pretty_name")" - - case "$LF$common$LF" in - *"$LF$SHA1$LF"*) - eval_gettextln "Already up to date with \$pretty_name" - continue - ;; - esac - - if test "$common,$NON_FF_MERGE" = "$MRC,0" - then - # The first head being merged was a fast-forward. - # Advance MRC to the head being merged, and use that - # tree as the intermediate result of the merge. - # We still need to count this as part of the parent set. - - eval_gettextln "Fast-forwarding to: \$pretty_name" - git read-tree -u -m $head $SHA1 || exit - MRC=$SHA1 MRT=$(git write-tree) - continue - fi - - NON_FF_MERGE=1 - - eval_gettextln "Trying simple merge with \$pretty_name" - git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2 - next=$(git write-tree 2>/dev/null) - if test $? -ne 0 - then - gettextln "Simple merge did not work, trying automatic merge." - git merge-index -o git-merge-one-file -a || - OCTOPUS_FAILURE=1 - next=$(git write-tree 2>/dev/null) - fi - - MRC="$MRC $SHA1" - MRT=$next -done - -exit "$OCTOPUS_FAILURE" diff --git a/git.c b/git.c index 2e92019493..28634cf61f 100644 --- a/git.c +++ b/git.c @@ -531,6 +531,7 @@ static struct cmd_struct commands[] = { { "merge-base", cmd_merge_base, RUN_SETUP }, { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, + { "merge-octopus", cmd_merge_octopus, RUN_SETUP | NO_PARSEOPT }, { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, { "merge-one-file", cmd_merge_one_file, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, From patchwork Thu Jun 25 12:19:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625187 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7C8DB6C1 for ; Thu, 25 Jun 2020 12:49:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5CF99207E8 for ; Thu, 25 Jun 2020 12:49:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DySU+eav" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404861AbgFYMtZ (ORCPT ); Thu, 25 Jun 2020 08:49:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59344 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404821AbgFYMtK (ORCPT ); Thu, 25 Jun 2020 08:49:10 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B85FFC061795 for ; Thu, 25 Jun 2020 05:49:10 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id h5so5707226wrc.7 for ; Thu, 25 Jun 2020 05:49:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wZna7OhEKhzpo1wAeUZXoNM3XN2M7ox9MYwbTh4qYC4=; b=DySU+eav+Gx+KG64tM8im28yheR0BiT8bfWn6W6iZdf5KR8eMuaycdN1TL4H6lHQ5C ilTGomw0H4rDsofuONRQzw4A1eDPU+OCZ/7ixqjw6aML6Tjm3okUtMVnpKurP6EbpgYu VLNHbngeWJfKMdc/XzSLNoaeYsRWeefoajqzKSvtteNlguAz84IeZANlAgPegs25JdZA ws9EJl1daX2SqUtRN7OFyNIIB2CDGPqkXy0jUc5M8xIr76JKO04owkYobHXlmvNDAcZo u4/TYBPLGKJm654pz/iNeZb+lfKQy3UVsQrHn1SeC03PJR8QhSPLGvEbRDA1yx4sB5T0 327w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wZna7OhEKhzpo1wAeUZXoNM3XN2M7ox9MYwbTh4qYC4=; b=fMoR1OBJGV/7Xx0N03XcyHzocfAWy5LiMJwbXDJASbj0LtM4YXuGuu4Uc4Xwl28Q8a xzEg7eyhv/gXXvX2L5sRxFu38tfQDlqRoV/3iklkDrLTh54dPZ8lJk3kB/F/E4p3XtiG IkLQIyI9otaAGjLV8nRIW8c5c2fHhcbsxbMilUurYzdKXjk8uEqQJrmHMIg42aRQmo2U WU2MpLh7RCz/8arAWhFN8+pQScxt/KUeUg+bjYOoahugZKVexpewx+K6dpLw4W9ecUR3 CvAIxndsipJK8AdX9iMIbbCScntFB1oCdZ2Xxcuce2OCWn6je2EescggtYhT8RJ56oZc ZBCg== X-Gm-Message-State: AOAM531flRLxjxTMnauIdfojm3ll6cYWpnDs605I32StlXVps/M9fXcv Nw7jWUjKrsRP7tXL2Q1bvNq3lmV1 X-Google-Smtp-Source: ABdhPJx+ZLeHxG7we1qsQE2BhkqZevaCp1fddZ8k1jDpP+0NRG5CTwiQp3GEdAgtvHsa7XwPvTFVEw== X-Received: by 2002:a05:6000:1107:: with SMTP id z7mr2519504wrw.355.1593089348900; Thu, 25 Jun 2020 05:49:08 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:08 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 12/17] merge-octopus: remove calls to external processes Date: Thu, 25 Jun 2020 14:19:48 +0200 Message-Id: <20200625121953.16991-13-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This removes calls to external processes to avoid reading and writing the index over and over again. - Calls to `read-tree -u -m (--aggressive)?' are replaced by calls to unpack_trees(). - The call to `write-tree' is replaced by a call to write_index_as_tree(). - The call to `diff-index ...' is replaced by a call to repo_index_has_changes(), and is moved from cmd_merge_octopus() to merge_octopus(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to merge_all(). The index is read in cmd_merge_octopus(), and is wrote back by merge_octopus(). Signed-off-by: Alban Gruin --- builtin/merge-octopus.c | 155 ++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 69 deletions(-) diff --git a/builtin/merge-octopus.c b/builtin/merge-octopus.c index 6216beaa2b..14310a4eb1 100644 --- a/builtin/merge-octopus.c +++ b/builtin/merge-octopus.c @@ -9,33 +9,70 @@ */ #include "cache.h" +#include "cache-tree.h" #include "builtin.h" #include "commit-reach.h" #include "lockfile.h" -#include "run-command.h" +#include "merge-strategies.h" #include "unpack-trees.h" +static int fast_forward(const struct object_id *oids, int nr, int aggressive) +{ + int i; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct lock_file lock = LOCK_INIT; + + repo_read_index_preload(the_repository, NULL, 0); + if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL)) + return -1; + + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = the_repository->index; + opts.dst_index = the_repository->index; + opts.merge = 1; + opts.update = 1; + opts.aggressive = aggressive; + + for (i = 0; i < nr; i++) { + struct tree *tree; + tree = parse_tree_indirect(oids + i); + if (parse_tree(tree)) + return -1; + init_tree_desc(t + i, tree->buffer, tree->size); + } + + if (nr == 1) + opts.fn = oneway_merge; + else if (nr == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(the_repository->index); + } else if (nr >= 3) { + opts.fn = threeway_merge; + opts.head_idx = nr - 1; + } + + if (unpack_trees(nr, t, &opts)) + return -1; + + if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK)) + return error(_("unable to write new index file")); + + return 0; +} + static int write_tree(struct tree **reference_tree) { - struct child_process cp = CHILD_PROCESS_INIT; - struct strbuf read_tree = STRBUF_INIT, err = STRBUF_INIT; struct object_id oid; int ret; - cp.git_cmd = 1; - argv_array_push(&cp.args, "write-tree"); - ret = pipe_command(&cp, NULL, 0, &read_tree, 0, &err, 0); - if (err.len > 0) - fputs(err.buf, stderr); - - strbuf_trim_trailing_newline(&read_tree); - get_oid(read_tree.buf, &oid); - - *reference_tree = lookup_tree(the_repository, &oid); - - strbuf_release(&read_tree); - strbuf_release(&err); - child_process_clear(&cp); + ret = write_index_as_tree(&oid, the_repository->index, + the_repository->index_file, 0, NULL); + if (!ret) + *reference_tree = lookup_tree(the_repository, &oid); return ret; } @@ -48,12 +85,23 @@ static int merge_octopus(struct commit_list *bases, const char *head_arg, struct tree *reference_tree; struct commit_list *j; struct object_id head; + struct strbuf sb = STRBUF_INIT; get_oid(head_arg, &head); + reference_commit = xcalloc(commit_list_count(remotes) + 1, sizeof(struct commit *)); reference_commit[0] = lookup_commit_reference(the_repository, &head); reference_tree = get_commit_tree(reference_commit[0]); + if (repo_index_has_changes(the_repository, reference_tree, &sb)) { + error(_("Your local changes to the following files " + "would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + ret = 2; + goto out; + } + for (j = remotes; j; j = j->next) { struct commit *c = j->item; struct object_id *oid = &c->object.oid; @@ -94,43 +142,36 @@ static int merge_octopus(struct commit_list *bases, const char *head_arg, } if (!non_ff_merge && can_ff) { - struct child_process cp = CHILD_PROCESS_INIT; - + struct object_id oids[2]; printf(_("Fast-forwarding to: %s\n"), branch_name); - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "read-tree", "-u", "-m", NULL); - argv_array_push(&cp.args, oid_to_hex(&head)); - argv_array_push(&cp.args, oid_to_hex(oid)); + oidcpy(oids, &head); + oidcpy(oids + 1, oid); - ret = run_command(&cp); + ret = fast_forward(oids, 2, 0); if (ret) { free(branch_name); free_commit_list(common); goto out; } - child_process_clear(&cp); references = 0; write_tree(&reference_tree); } else { - struct commit_list *l; + int i = 0; struct tree *next = NULL; - struct child_process cp = CHILD_PROCESS_INIT; + struct object_id oids[MAX_UNPACK_TREES]; non_ff_merge = 1; printf(_("Trying simple merge with %s\n"), branch_name); - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "read-tree", "-u", "-m", "--aggressive", NULL); + for (k = common; k; k = k->next) + oidcpy(oids + (i++), &k->item->object.oid); - for (l = common; l; l = l->next) - argv_array_push(&cp.args, oid_to_hex(&l->item->object.oid)); + oidcpy(oids + (i++), &reference_tree->object.oid); + oidcpy(oids + (i++), oid); - argv_array_push(&cp.args, oid_to_hex(&reference_tree->object.oid)); - argv_array_push(&cp.args, oid_to_hex(oid)); - - if (run_command(&cp)) { + if (fast_forward(oids, i, 1)) { ret = 2; free(branch_name); @@ -139,19 +180,15 @@ static int merge_octopus(struct commit_list *bases, const char *head_arg, goto out; } - child_process_clear(&cp); - if (write_tree(&next)) { - struct child_process cp = CHILD_PROCESS_INIT; + struct lock_file lock = LOCK_INIT; + puts(_("Simple merge did not work, trying automatic merge.")); + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); + ret = !!merge_all(the_repository->index, 0, 0, + merge_one_file_cb, the_repository); + write_locked_index(the_repository->index, &lock, COMMIT_LOCK); - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "merge-index", "-o", - "git-merge-one-file", "-a", NULL); - if (run_command(&cp)) - ret = 1; - - child_process_clear(&cp); write_tree(&next); } @@ -178,12 +215,14 @@ int cmd_merge_octopus(int argc, const char **argv, const char *prefix) struct commit_list *bases = NULL, *remotes = NULL; struct commit_list **next_base = &bases, **next_remote = &remotes; const char *head_arg = NULL; - struct child_process cp = CHILD_PROCESS_INIT; - struct strbuf files = STRBUF_INIT; if (argc < 5) usage(builtin_merge_octopus_usage); + setup_work_tree(); + if (repo_read_index(the_repository) < 0) + die("corrupted cache"); + /* The first parameters up to -- are merge bases; the rest are * heads. */ for (i = 1; i < argc; i++) { @@ -215,27 +254,5 @@ int cmd_merge_octopus(int argc, const char **argv, const char *prefix) if (commit_list_count(remotes) < 2) return 2; - cp.git_cmd = 1; - argv_array_pushl(&cp.args, "diff-index", "--cached", - "--name-only", "HEAD", "--", NULL); - pipe_command(&cp, NULL, 0, &files, 0, NULL, 0); - child_process_clear(&cp); - - if (files.len > 0) { - struct strbuf **s, **b; - - s = strbuf_split(&files, '\n'); - - fprintf(stderr, _("Error: Your local changes to the following " - "files would be overwritten by merge\n")); - - for (b = s; *b; b++) - fprintf(stderr, " %.*s", (int)(*b)->len, (*b)->buf); - - strbuf_list_free(s); - strbuf_release(&files); - return 2; - } - return merge_octopus(bases, head_arg, remotes); } From patchwork Thu Jun 25 12:19:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625177 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6AFA9138C for ; Thu, 25 Jun 2020 12:49:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B9382072E for ; Thu, 25 Jun 2020 12:49:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pxlmPwiV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404838AbgFYMtP (ORCPT ); Thu, 25 Jun 2020 08:49:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59352 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404824AbgFYMtM (ORCPT ); Thu, 25 Jun 2020 08:49:12 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B741C061796 for ; Thu, 25 Jun 2020 05:49:12 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id f7so2716277wrw.1 for ; Thu, 25 Jun 2020 05:49:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=P8GWl9cTGQrdzNrHSGCqWybQf/w9pKToCmVncpH0OCI=; b=pxlmPwiVFT/8b9Tpd+QSrzAzr2a5oC2ixf26iB8JdJCtr0PFBd7h0+SX46mhFaLmcp kj45W99RMJHlf4vq4ZPeLqHCAwQDe0YiK+hF3iLN4IGkUYi8WhXURGn180S9kyuZc0L8 XpS758G21gZWwXmKWr4f5042yV95SwRBreeDzaKoEuH3SKq4XfkmWQY1aNMKvJAhvtCD /tS/LEpYF6gZq7v6cxX5se68avbQoYnE3nG5dh3FYoJINg4w1B8E259pO+qntgQ6HBYm wt1YB/2DWNz96YDswMkvfpLvwnLtNidAMId1HVnVuSYY/egZXpUnQ19o6yGsym1t/McD r9wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=P8GWl9cTGQrdzNrHSGCqWybQf/w9pKToCmVncpH0OCI=; b=sHaiCefRFwkbTriZR+0fRNjueR60YZDBJQuJBtU1TOgWN5nVidbmh+p+c+tXeppkHL oMh+Oy803WDD9PsMLMvMyh70RxMjiGSBTXmyxDU72i1a2X0VrGrlkpilRU6tJtaFUcvI haXoo1/o2Jw04hsXnV1qiXt0fEvSxsfJYU+DfzqMUffAvWAmRm9OBenpc9JB6lXgT8g8 XMepcy34ZYod9b6cvSBq30nS2U/Ms+bk5oloygXJumstXhNl2eWdmUOYm6kIjAJqJMhn jus0CfQzUAjkva/m93zOJDEbnhywdMGkHQSVzzy3UGhpQVD1iAq1MSdqhvjegfbsnXCM v1+Q== X-Gm-Message-State: AOAM532/ozctt1P9wo2vRfN51XHqMd+jl43kr0Dcwj5w1r7lNFN06RGI nmaLPQrZGBqTPMLaSKsA2I7g2iS7 X-Google-Smtp-Source: ABdhPJwnctqzHMPCOuY8j3V0RELQWgTRXl3MlkBpMP/HWrwStUE6423EwPRlj+oMqrkx/b5kXfGP6g== X-Received: by 2002:adf:f784:: with SMTP id q4mr11393126wrp.397.1593089350374; Thu, 25 Jun 2020 05:49:10 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:09 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 13/17] merge-octopus: libify merge_octopus() Date: Thu, 25 Jun 2020 14:19:49 +0200 Message-Id: <20200625121953.16991-14-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This moves merge_octopus() (and its helper functions) to merge-strategies.c. This will enable `git merge' and the sequencer to directly call it instead of forking. Once again, this is not a faithful copy-and-paste; the new merge_octopus() (renamed merge_strategies_octopus()) takes a pointer to the repository, instead of using `the_repository'. Signed-off-by: Alban Gruin --- Notes: This patch is best viewed with `--color-moved'. builtin/merge-octopus.c | 197 +--------------------------------------- merge-strategies.c | 191 ++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 3 + 3 files changed, 196 insertions(+), 195 deletions(-) diff --git a/builtin/merge-octopus.c b/builtin/merge-octopus.c index 14310a4eb1..37bbdf11cc 100644 --- a/builtin/merge-octopus.c +++ b/builtin/merge-octopus.c @@ -9,202 +9,9 @@ */ #include "cache.h" -#include "cache-tree.h" #include "builtin.h" -#include "commit-reach.h" -#include "lockfile.h" +#include "commit.h" #include "merge-strategies.h" -#include "unpack-trees.h" - -static int fast_forward(const struct object_id *oids, int nr, int aggressive) -{ - int i; - struct tree_desc t[MAX_UNPACK_TREES]; - struct unpack_trees_options opts; - struct lock_file lock = LOCK_INIT; - - repo_read_index_preload(the_repository, NULL, 0); - if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL)) - return -1; - - repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - - memset(&opts, 0, sizeof(opts)); - opts.head_idx = 1; - opts.src_index = the_repository->index; - opts.dst_index = the_repository->index; - opts.merge = 1; - opts.update = 1; - opts.aggressive = aggressive; - - for (i = 0; i < nr; i++) { - struct tree *tree; - tree = parse_tree_indirect(oids + i); - if (parse_tree(tree)) - return -1; - init_tree_desc(t + i, tree->buffer, tree->size); - } - - if (nr == 1) - opts.fn = oneway_merge; - else if (nr == 2) { - opts.fn = twoway_merge; - opts.initial_checkout = is_index_unborn(the_repository->index); - } else if (nr >= 3) { - opts.fn = threeway_merge; - opts.head_idx = nr - 1; - } - - if (unpack_trees(nr, t, &opts)) - return -1; - - if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK)) - return error(_("unable to write new index file")); - - return 0; -} - -static int write_tree(struct tree **reference_tree) -{ - struct object_id oid; - int ret; - - ret = write_index_as_tree(&oid, the_repository->index, - the_repository->index_file, 0, NULL); - if (!ret) - *reference_tree = lookup_tree(the_repository, &oid); - - return ret; -} - -static int merge_octopus(struct commit_list *bases, const char *head_arg, - struct commit_list *remotes) -{ - int non_ff_merge = 0, ret = 0, references = 1; - struct commit **reference_commit; - struct tree *reference_tree; - struct commit_list *j; - struct object_id head; - struct strbuf sb = STRBUF_INIT; - - get_oid(head_arg, &head); - - reference_commit = xcalloc(commit_list_count(remotes) + 1, sizeof(struct commit *)); - reference_commit[0] = lookup_commit_reference(the_repository, &head); - reference_tree = get_commit_tree(reference_commit[0]); - - if (repo_index_has_changes(the_repository, reference_tree, &sb)) { - error(_("Your local changes to the following files " - "would be overwritten by merge:\n %s"), - sb.buf); - strbuf_release(&sb); - ret = 2; - goto out; - } - - for (j = remotes; j; j = j->next) { - struct commit *c = j->item; - struct object_id *oid = &c->object.oid; - struct commit_list *common, *k; - char *branch_name; - int can_ff = 1; - - if (ret) { - puts(_("Automated merge did not work.")); - puts(_("Should not be doing an octopus.")); - - ret = 2; - goto out; - } - - branch_name = merge_get_better_branch_name(oid_to_hex(oid)); - common = get_merge_bases_many(c, references, reference_commit); - - if (!common) - die(_("Unable to find common commit with %s"), branch_name); - - for (k = common; k && !oideq(&k->item->object.oid, oid); k = k->next); - - if (k) { - printf(_("Already up to date with %s\n"), branch_name); - free(branch_name); - free_commit_list(common); - continue; - } - - if (!non_ff_merge) { - int i; - - for (i = 0, k = common; k && i < references && can_ff; k = k->next, i++) { - can_ff = oideq(&k->item->object.oid, - &reference_commit[i]->object.oid); - } - } - - if (!non_ff_merge && can_ff) { - struct object_id oids[2]; - printf(_("Fast-forwarding to: %s\n"), branch_name); - - oidcpy(oids, &head); - oidcpy(oids + 1, oid); - - ret = fast_forward(oids, 2, 0); - if (ret) { - free(branch_name); - free_commit_list(common); - goto out; - } - - references = 0; - write_tree(&reference_tree); - } else { - int i = 0; - struct tree *next = NULL; - struct object_id oids[MAX_UNPACK_TREES]; - - non_ff_merge = 1; - printf(_("Trying simple merge with %s\n"), branch_name); - - for (k = common; k; k = k->next) - oidcpy(oids + (i++), &k->item->object.oid); - - oidcpy(oids + (i++), &reference_tree->object.oid); - oidcpy(oids + (i++), oid); - - if (fast_forward(oids, i, 1)) { - ret = 2; - - free(branch_name); - free_commit_list(common); - - goto out; - } - - if (write_tree(&next)) { - struct lock_file lock = LOCK_INIT; - - puts(_("Simple merge did not work, trying automatic merge.")); - repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - ret = !!merge_all(the_repository->index, 0, 0, - merge_one_file_cb, the_repository); - write_locked_index(the_repository->index, &lock, COMMIT_LOCK); - - write_tree(&next); - } - - reference_tree = next; - } - - reference_commit[references++] = c; - - free(branch_name); - free_commit_list(common); - } - -out: - free(reference_commit); - return ret; -} static const char builtin_merge_octopus_usage[] = "git merge-octopus [...] -- [...]"; @@ -254,5 +61,5 @@ int cmd_merge_octopus(int argc, const char **argv, const char *prefix) if (commit_list_count(remotes) < 2) return 2; - return merge_octopus(bases, head_arg, remotes); + return merge_strategies_octopus(the_repository, bases, head_arg, remotes); } diff --git a/merge-strategies.c b/merge-strategies.c index a12c575590..8395c4c787 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,5 +1,6 @@ #include "cache.h" #include "cache-tree.h" +#include "commit-reach.h" #include "dir.h" #include "lockfile.h" #include "merge-strategies.h" @@ -384,3 +385,193 @@ int merge_strategies_resolve(struct repository *r, rollback_lock_file(&lock); return 2; } + +static int fast_forward(struct repository *r, const struct object_id *oids, + int nr, int aggressive) +{ + int i; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct lock_file lock = LOCK_INIT; + + repo_read_index_preload(r, NULL, 0); + if (refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL)) + return -1; + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = r->index; + opts.dst_index = r->index; + opts.merge = 1; + opts.update = 1; + opts.aggressive = aggressive; + + for (i = 0; i < nr; i++) { + struct tree *tree; + tree = parse_tree_indirect(oids + i); + if (parse_tree(tree)) + return -1; + init_tree_desc(t + i, tree->buffer, tree->size); + } + + if (nr == 1) + opts.fn = oneway_merge; + else if (nr == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(r->index); + } else if (nr >= 3) { + opts.fn = threeway_merge; + opts.head_idx = nr - 1; + } + + if (unpack_trees(nr, t, &opts)) + return -1; + + if (write_locked_index(r->index, &lock, COMMIT_LOCK)) + return error(_("unable to write new index file")); + + return 0; +} + +static int write_tree(struct repository *r, struct tree **reference_tree) +{ + struct object_id oid; + int ret; + + ret = write_index_as_tree(&oid, r->index, r->index_file, 0, NULL); + if (!ret) + *reference_tree = lookup_tree(r, &oid); + + return ret; +} + +int merge_strategies_octopus(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remotes) +{ + int non_ff_merge = 0, ret = 0, references = 1; + struct commit **reference_commit; + struct tree *reference_tree; + struct commit_list *j; + struct object_id head; + struct strbuf sb = STRBUF_INIT; + + get_oid(head_arg, &head); + + reference_commit = xcalloc(commit_list_count(remotes) + 1, sizeof(struct commit *)); + reference_commit[0] = lookup_commit_reference(r, &head); + reference_tree = repo_get_commit_tree(r, reference_commit[0]); + + if (repo_index_has_changes(r, reference_tree, &sb)) { + error(_("Your local changes to the following files " + "would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + ret = 2; + goto out; + } + + for (j = remotes; j && j->item; j = j->next) { + struct commit *c = j->item; + struct object_id *oid = &c->object.oid; + struct commit_list *common, *k; + char *branch_name; + int can_ff = 1; + + if (ret) { + puts(_("Automated merge did not work.")); + puts(_("Should not be doing an octopus.")); + + ret = 2; + goto out; + } + + branch_name = merge_get_better_branch_name(oid_to_hex(oid)); + common = get_merge_bases_many(c, references, reference_commit); + + if (!common) + die(_("Unable to find common commit with %s"), branch_name); + + for (k = common; k && !oideq(&k->item->object.oid, oid); k = k->next); + + if (k) { + printf(_("Already up to date with %s\n"), branch_name); + free(branch_name); + free_commit_list(common); + continue; + } + + if (!non_ff_merge) { + int i; + + for (i = 0, k = common; k && i < references && can_ff; k = k->next, i++) { + can_ff = oideq(&k->item->object.oid, + &reference_commit[i]->object.oid); + } + } + + if (!non_ff_merge && can_ff) { + struct object_id oids[2]; + printf(_("Fast-forwarding to: %s\n"), branch_name); + + oidcpy(oids, &head); + oidcpy(oids + 1, oid); + + ret = fast_forward(r, oids, 2, 0); + if (ret) { + free(branch_name); + free_commit_list(common); + goto out; + } + + references = 0; + write_tree(r, &reference_tree); + } else { + int i = 0; + struct tree *next = NULL; + struct object_id oids[MAX_UNPACK_TREES]; + + non_ff_merge = 1; + printf(_("Trying simple merge with %s\n"), branch_name); + + for (k = common; k; k = k->next) + oidcpy(oids + (i++), &k->item->object.oid); + + oidcpy(oids + (i++), &reference_tree->object.oid); + oidcpy(oids + (i++), oid); + + if (fast_forward(r, oids, i, 1)) { + ret = 2; + + free(branch_name); + free_commit_list(common); + + goto out; + } + + if (write_tree(r, &next)) { + struct lock_file lock = LOCK_INIT; + + puts(_("Simple merge did not work, trying automatic merge.")); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = !!merge_all(r->index, 0, 0, merge_one_file_cb, r); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + write_tree(r, &next); + } + + reference_tree = next; + } + + reference_commit[references++] = c; + + free(branch_name); + free_commit_list(common); + } + +out: + free(reference_commit); + return ret; +} diff --git a/merge-strategies.h b/merge-strategies.h index 778f8ce9d6..938411a04e 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -37,5 +37,8 @@ int merge_all(struct index_state *istate, int oneshot, int quiet, int merge_strategies_resolve(struct repository *r, struct commit_list *bases, const char *head_arg, struct commit_list *remote); +int merge_strategies_octopus(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote); #endif /* MERGE_STRATEGIES_H */ From patchwork Thu Jun 25 12:19:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625183 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2EA166C1 for ; Thu, 25 Jun 2020 12:49:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1631A20724 for ; Thu, 25 Jun 2020 12:49:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EvL7zUba" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404854AbgFYMtV (ORCPT ); Thu, 25 Jun 2020 08:49:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59354 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404828AbgFYMtN (ORCPT ); Thu, 25 Jun 2020 08:49:13 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED9DAC0613ED for ; Thu, 25 Jun 2020 05:49:12 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id j94so5739252wrj.0 for ; Thu, 25 Jun 2020 05:49:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ErI2OlJ5F+BITkR+n1dtdGRWwDA6IqCxbOTgA+Hvcyc=; b=EvL7zUba2W88nYipflEsLdAEdnBLn5tTUAHyM2ChQmNTkhifqp3pjHDg1Vdd6Lsr6v Dd3OG6GF89p1BV6U3gev2+KvSWuO0pXqCgCLhR7SaewKp+4+BiZ3oxPD9g7cZiOLyI68 hGOoS5mpRO3yOpM8V/hy+aSCIjmxqsMekfi+mkZ79phOGZ60BEtN/CQISKXbXg5TARke RoYLTR9QFdPGVAFJil21bdfd7IaEodB+nkqcaOmQ9Ihr9vgl9LrHwDqVWE4JnFxhTJb7 FTniE+/qfKNZMZTlOW7U02xRY6cbgrLNRVIg31JSPBTHY93JJLJ7KRQZhiai8kUOJHKz 6r/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ErI2OlJ5F+BITkR+n1dtdGRWwDA6IqCxbOTgA+Hvcyc=; b=djrtVD9DOUxSmXENY6GL/XTMELYbhzcYz5by5s77a84jaWfsrswCLBGfsk4qKvdmDU F2Ys0VMoj9Ww3cQSrkjJAd0udEniUoSMKeXTx+vuxGxxSLhKyN35aL3z2IUHHvztb7uV U2WFTuNs+IZTTAyhbhXYp0m0s4NhUcskJ2qmy0E5f1PUo1pPmSP7QoRYNUFkrPDygy+W aq+kNOzYwqlusGo99d9j7QoDygKOxp5DvBGC9Wu70OHXBzyVgfCCcCkuHYSwpJKGRpDH DSTFz1zuFikL36B9YNQDIWTbdLIe+QEcCHL1Is+UN0A16GsTWtb7L+WBYAS3kSS0xVma oeig== X-Gm-Message-State: AOAM532xzLkYcrRjr/CAESBvgInKChJqpZ0CC9Dm+mXEnUBYjEWTxm1b VONXkYbXDDUmEr74rML0S4+3pZqL X-Google-Smtp-Source: ABdhPJzg6G+RULFOL6HxhkMQ3+jZdCJM/eQ17WOtBGpbWE43Psuo05wfTMoLLtiYcQZic3qai5uTwQ== X-Received: by 2002:adf:f311:: with SMTP id i17mr22418542wro.237.1593089351487; Thu, 25 Jun 2020 05:49:11 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:11 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 14/17] merge: use the "resolve" strategy without forking Date: Thu, 25 Jun 2020 14:19:50 +0200 Message-Id: <20200625121953.16991-15-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches `git merge' to invoke the "resolve" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- builtin/merge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/builtin/merge.c b/builtin/merge.c index 7da707bf55..d50b4ad6ad 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -41,6 +41,7 @@ #include "commit-reach.h" #include "wt-status.h" #include "commit-graph.h" +#include "merge-strategies.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -744,7 +745,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write %s"), get_index_file()); return clean ? 0 : 1; - } else { + } else if (!strcmp(strategy, "resolve")) + return merge_strategies_resolve(the_repository, common, + head_arg, remoteheads); + else { return try_merge_command(the_repository, strategy, xopts_nr, xopts, common, head_arg, remoteheads); From patchwork Thu Jun 25 12:19:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625179 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7EF05138C for ; Thu, 25 Jun 2020 12:49:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6483D2072E for ; Thu, 25 Jun 2020 12:49:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="p5I3Q/xd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404840AbgFYMtR (ORCPT ); Thu, 25 Jun 2020 08:49:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59360 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404830AbgFYMtO (ORCPT ); Thu, 25 Jun 2020 08:49:14 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0917BC061573 for ; Thu, 25 Jun 2020 05:49:14 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id o2so5806235wmh.2 for ; Thu, 25 Jun 2020 05:49:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=YwmDkC6KWOkGoFDqvDEsZ4rzjef99/I/e3iXH4kN0Uc=; b=p5I3Q/xdyU/dXrn2Et9VMwPUYAGPYaQlAmUZDLUIGCYzRgbBCzhRBUB7P0JR1jtgNW omz5le87EbRYMYcVIWv7XR38qQMcVvqjJN6CxlGsbl4k8acA1A56uoCpMHnsayGFjmrw tAOjmjZ1noC0VhbN+xiC+Z2QKTpyukFhWGDgqYlIPQ4oHTwX6L2a2GZ339viTeee525v fOD/dN3chP/DIxJxpzog7iM/KDzJVDlTVNhQYspgvFvoexKr3w/janCC/1Z4W9XJmnM2 jJUh6xFYaZzmgdRumSsX8E0SGPSv5v6iFLnpixZLwgcIGjKMyTgxyb2iqFARqUtXSt0G erHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=YwmDkC6KWOkGoFDqvDEsZ4rzjef99/I/e3iXH4kN0Uc=; b=PdHujyuZdyaMwxooTmbIvOETJfpjTndjFqCNHgTDozZlBOC/WjxJFSmbdSwzfDyXB0 WqpG8NaDYkkH3afJCK/QjDtNyCRKLfV7bqwsOo123atEYoUrj5GPRCezZl7KhZzPn70U fLnSo505+LzhSJqUDS53ZcH0gKJ4wYonExzDHgn/4hLzVWBciUkW5VJTC1o+pNJ16g4g eXhQJVtZiSdaWfHRgvZMhH3wQMmCKmomzPw14aihN9mWFru7pdQufNesXfkefU+t/46R fGhTBl2WdduDvHWdnzmkSflwtrYGYOyd2BFwomilmFqzuOAxdbWy9uo3Z+4vBe1INkJM lxZA== X-Gm-Message-State: AOAM5335Sz3e+hQw2U2bx9HlwRWwbeOESokT6yFISQ9FjTdxMrNwFLzm JF2YfT8WwwleKp5XvMfZRT74Nso+ X-Google-Smtp-Source: ABdhPJxl+z2rlIerZqRlf4WxyQq45Ylss0OoVTYjebDJtVbYAfUY+dSSC6cAbLCKF8wf3ct7kJK1fg== X-Received: by 2002:a7b:c1cc:: with SMTP id a12mr3329874wmj.112.1593089352595; Thu, 25 Jun 2020 05:49:12 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:12 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 15/17] merge: use the "octopus" strategy without forking Date: Thu, 25 Jun 2020 14:19:51 +0200 Message-Id: <20200625121953.16991-16-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches `git merge' to invoke the "octopus" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- builtin/merge.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/merge.c b/builtin/merge.c index d50b4ad6ad..53f64ddb87 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -748,6 +748,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, } else if (!strcmp(strategy, "resolve")) return merge_strategies_resolve(the_repository, common, head_arg, remoteheads); + else if (!strcmp(strategy, "octopus")) + return merge_strategies_octopus(the_repository, common, + head_arg, remoteheads); else { return try_merge_command(the_repository, strategy, xopts_nr, xopts, From patchwork Thu Jun 25 12:19:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625181 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 798AE6C1 for ; Thu, 25 Jun 2020 12:49:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5A2A020724 for ; Thu, 25 Jun 2020 12:49:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="L2ywW+eW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404849AbgFYMtT (ORCPT ); Thu, 25 Jun 2020 08:49:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59366 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404800AbgFYMtP (ORCPT ); Thu, 25 Jun 2020 08:49:15 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D831C061795 for ; Thu, 25 Jun 2020 05:49:15 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id a6so5714594wrm.4 for ; Thu, 25 Jun 2020 05:49:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=NSY9ppiqBuxjNhnWpM8tlVZkd8trufCqv0ywlZ6IJlY=; b=L2ywW+eWHblIHO1ni/H+D8plf4+3y5ORpJXY5tnO9Bpk+yFDmVCMrWVGgdYPX2w4nz hhbO4Hte23hLxyyoersFJLbbBLIW8uNDt+wu0v12x7wPeY8FTa29oFJhvTsmXP38+yG8 aZpx1mtZ3pv4K9R92FMo1fc1xfEpztH6rkRLvrZxyeOqW3GZRXMTRNLvDG8jNXUZafVw 4hlmymPG1DBZbLNXHdAxZJZYqnI9XRklTImtN74ILJVVFW7hZr/gcO6jMZuEMfu8PAfH NCw9ypJ6mdPIgx5esjP2X0L8Cqchk+WUpl2qGgkOEFITp6sMJqf+p/Ru1HrWWMZVBIyZ OLwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NSY9ppiqBuxjNhnWpM8tlVZkd8trufCqv0ywlZ6IJlY=; b=ODTlk3n37Hxcklv8Yi5iakCp0Fukugsq9SzuVsU34agN695IF0S/dHOT5uYgaJWVia ICsJ9p2KdrKqBqTUr4yVm5QUhAIyDFupnJ3wRiUE+s0hoAF61cmbw0yiHUn0p11Lbb5i 2EuTzbL7Q6sgxs2pYGDVFkdQJnjLhJ4yRRLLcelJR8t8JyiGWN6Txa712XiFbmJV8yfe 3qDotfTzVSK6j4G89AwGJPxxyc2G0d+VauOXQFM+cj50scKHO2hIi1iQ9z+/wqS0Julk toRKj1uT4p1UAPSHVJDNQ1NWT55IBMTRBhhZsODJYtv2Th902W+R4ISU+KkzCHKBLBEO ALDA== X-Gm-Message-State: AOAM531D+b3fMf/O5fZ4EVKXtbF6LjQfLADozXE5+ObhBOoYnwahSa5m JUg8hXWHd2iL18UyAJvabTXXjfrb X-Google-Smtp-Source: ABdhPJwMp2xte1dG7BVrIkSOXretMY36/L6B3Qo0kGEWuBwoT4VBREU8kvcVtaGiqYnM7/Iu1cVnzg== X-Received: by 2002:a5d:6912:: with SMTP id t18mr26560309wru.411.1593089353641; Thu, 25 Jun 2020 05:49:13 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:13 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 16/17] sequencer: use the "resolve" strategy without forking Date: Thu, 25 Jun 2020 14:19:52 +0200 Message-Id: <20200625121953.16991-17-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches the sequencer to invoke the "resolve" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- sequencer.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index fd7701c88a..ea8dc58108 100644 --- a/sequencer.c +++ b/sequencer.c @@ -33,6 +33,7 @@ #include "commit-reach.h" #include "rebase-interactive.h" #include "reset.h" +#include "merge-strategies.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -1922,9 +1923,15 @@ static int do_pick_commit(struct repository *r, commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(r, opts->strategy, - opts->xopts_nr, (const char **)opts->xopts, - common, oid_to_hex(&head), remotes); + + if (!strcmp(opts->strategy, "resolve")) { + repo_read_index(r); + res |= merge_strategies_resolve(r, common, oid_to_hex(&head), remotes); + } else + res |= try_merge_command(r, opts->strategy, + opts->xopts_nr, (const char **)opts->xopts, + common, oid_to_hex(&head), remotes); + free_commit_list(common); free_commit_list(remotes); } From patchwork Thu Jun 25 12:19:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11625189 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 29E5914E3 for ; Thu, 25 Jun 2020 12:49:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1217C207E8 for ; Thu, 25 Jun 2020 12:49:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FAbBmMQX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404855AbgFYMtY (ORCPT ); Thu, 25 Jun 2020 08:49:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404830AbgFYMtR (ORCPT ); Thu, 25 Jun 2020 08:49:17 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 268E2C061573 for ; Thu, 25 Jun 2020 05:49:17 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id g18so5739879wrm.2 for ; Thu, 25 Jun 2020 05:49:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BQnHjs2gUr9h7Af164bmLeznclPTq6fiIICM3Trsxx8=; b=FAbBmMQXfu1GFu34JAUrdcib+KbKfcCXCH44DbnykE4EMTM3L0rFEwZ7enbR0focB3 yw8DguuWP4Da+froo/5Pn8naLbzhyEiCcm1ZUEhqd1CgaSyZF54qYWWG83iN8u6ayumy 9u2IuNa4C0/qud6BF7Snn32k2VtkO49kN8tma1e23W99KlcC19YTuoCEn6KrwEvseqCy 4Bs4fRik2ie4aptTXQIynlQtrSIAkLcnEWfW+pnAAaRK6gCPLuj3qwRTnUuiPgRz79yG PO2rZNfW02NXtzs5M/r2JbcoB1xUrfwXxqIa8QQyJKVF/jmCFrhQ4Jz6Qkel/8kbVNjK nWdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BQnHjs2gUr9h7Af164bmLeznclPTq6fiIICM3Trsxx8=; b=I73mbvIdk0wg584jhNaywTsF7W1S4Uy+G0P9iEthjXM7+Ly5WACKdpHb1HolJ1euDE UY82b2TSJ7bTs2flfZaIfKe4NQvy8Z6xAGV58+vhPW4DulqG30nLKaANDrCzSWNDHicw vpNWdTNln4ReYUh/36J8uLCM+i3pDSYzEHZlbeKWz7I8JHTmXNES9EEgVW3/x3nVuPbP 6JFjd+a9CwW91sp5DsWGSRd52S5AYv+WDD4YFj2UcofrJU6DBLq6+8L5zMvon3aiHKXu 3sy72fPHBGqjoh9nUzxB6njCxJl9J1FSCqOmuSnjMHv866mfbH5fdJxm3u4N/RaHjGTS DXtQ== X-Gm-Message-State: AOAM533ipkryoNA7y7TWVpFUqA5EDW0Reps6d1QLasKcqLtPO+EmPDmc 21MhyrcT7CGLiNn+FQfq4fIsCkCJ X-Google-Smtp-Source: ABdhPJxWcCM6/nuVn0gBTuuRnioKdZqd5XXgmFO4weSOsOAhe35quVdT8jChgVNNcs3Jo7RubPIVqQ== X-Received: by 2002:a5d:5549:: with SMTP id g9mr34197175wrw.419.1593089355468; Thu, 25 Jun 2020 05:49:15 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-308-216.w86-199.abo.wanadoo.fr. [86.199.91.216]) by smtp.googlemail.com with ESMTPSA id y16sm31563409wro.71.2020.06.25.05.49.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 05:49:15 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Alban Gruin Subject: [RFC PATCH v1 17/17] sequencer: use the "octopus" merge strategy without forking Date: Thu, 25 Jun 2020 14:19:53 +0200 Message-Id: <20200625121953.16991-18-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200625121953.16991-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches the sequencer to invoke the "octopus" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- sequencer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sequencer.c b/sequencer.c index ea8dc58108..f9fa995b4b 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1927,6 +1927,9 @@ static int do_pick_commit(struct repository *r, if (!strcmp(opts->strategy, "resolve")) { repo_read_index(r); res |= merge_strategies_resolve(r, common, oid_to_hex(&head), remotes); + } else if (!strcmp(opts->strategy, "octopus")) { + repo_read_index(r); + res |= merge_strategies_octopus(r, common, oid_to_hex(&head), remotes); } else res |= try_merge_command(r, opts->strategy, opts->xopts_nr, (const char **)opts->xopts,