From patchwork Sat Jun 18 00:20:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886158 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A5F1C433EF for ; Sat, 18 Jun 2022 00:21:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383643AbiFRAVJ (ORCPT ); Fri, 17 Jun 2022 20:21:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383506AbiFRAVH (ORCPT ); Fri, 17 Jun 2022 20:21:07 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DCC2B5931A for ; Fri, 17 Jun 2022 17:21:04 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id e25so3651025wrc.13 for ; Fri, 17 Jun 2022 17:21:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=HsHj2KxDWTA9QM6TZSN11NDwemvgrQd3pHbka8fElO8=; b=jV7tQQo2XwEeBG1r3FhS8+42bwQpPz9rpoC7RrnJkErMhhhJZ2UD2eWtE7LlEsdx8y 2cZIQMRKUE7wOvbegDl9qVwmAWWCgkMJvyBY9VaHjQRxZVSedCwPmqKxPhlWXlUW6q4v 0qvYM8KuZZwSa843tC/P0+8x9+jtR2GcsMWvdBBrVkIRqQCTR8JEAbBFAfI1G3lmBQKd nfw4wAGKV1AywhnHJCVAPssp5IayBOz2Hht0AaIPM9BIbyOSHmWN+S02H4p0y1MmFGM9 sFMc3ZNj6mEWbIDyE5pQCEfkbiDZ5nTSbjcB3DLqmc6waLfAOzAKloYrD0Xwc9zb20TN fr8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=HsHj2KxDWTA9QM6TZSN11NDwemvgrQd3pHbka8fElO8=; b=jhUkkPitvoGYyVEogObWHYydhvgAEqYRASkOkQfEiMY/oKkshTwX06xdQg2Iz8VcIX gBHpZGEtxTbjtn3459rSP7mNyKsQeTwfu57zFUN2X/a0OHnw3AfgpiIHl22SdAiW+WQL WDXhsXObbdHvbZQlS3OREaWvMyrUU+S4mQCmFJ4CGN57l21wy5KE7P1TSS10njwVQQss 1mI81tdKct3o88BbIvl1eoOZ2Ro4pbhpTwdYf36tGJ3vrAzg1aQIXCAD7e+LcfUxE3cZ 60SsrOmh/pgXtzcZ4EBXyfgvdN6ZD5Keo0ADCvYmdvEbQ7916nsiWM2fqUOXPHGarnp4 Yh0g== X-Gm-Message-State: AJIora/e5GJX01Zq5XURbZU4yWP4/ZCF94Pge8Sz7DMzemZmxFW0ebqm AjW1n37TZAswjPQnoLrP+JIdwYL5/cS3tg== X-Google-Smtp-Source: AGRyM1udfyJIFjHlvov5mhZCIPs5le5/crVI/IxeoI/cVlykbE8h2SQHXK7/0IgIuVSMGRPEYgTbww== X-Received: by 2002:a05:6000:69d:b0:21a:395e:572c with SMTP id bo29-20020a056000069d00b0021a395e572cmr8820949wrb.559.1655511662977; Fri, 17 Jun 2022 17:21:02 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m62-20020a1ca341000000b0039c99f61e5bsm10713438wme.5.2022.06.17.17.21.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:02 -0700 (PDT) Message-Id: <8fb51817ed4688cd8eadb30108f96f741405bb8e.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:44 +0000 Subject: [PATCH v7 01/17] merge-tree: rename merge_trees() to trivial_merge_trees() Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren merge-recursive.h defined its own merge_trees() function, different than the one found in builtin/merge-tree.c. That was okay in the past, but we want merge-tree to be able to use the merge-ort functions, which will end up including merge-recursive.h. Rename the function found in builtin/merge-tree.c to avoid the conflict. Signed-off-by: Elijah Newren --- builtin/merge-tree.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 5dc94d6f880..06f9eee9f78 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -28,7 +28,7 @@ static void add_merge_entry(struct merge_list *entry) merge_result_end = &entry->next; } -static void merge_trees(struct tree_desc t[3], const char *base); +static void trivial_merge_trees(struct tree_desc t[3], const char *base); static const char *explanation(struct merge_list *entry) { @@ -225,7 +225,7 @@ static void unresolved_directory(const struct traverse_info *info, buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2)); #undef ENTRY_OID - merge_trees(t, newbase); + trivial_merge_trees(t, newbase); free(buf0); free(buf1); @@ -342,7 +342,7 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s return mask; } -static void merge_trees(struct tree_desc t[3], const char *base) +static void trivial_merge_trees(struct tree_desc t[3], const char *base) { struct traverse_info info; @@ -378,7 +378,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) buf1 = get_tree_descriptor(r, t+0, argv[1]); buf2 = get_tree_descriptor(r, t+1, argv[2]); buf3 = get_tree_descriptor(r, t+2, argv[3]); - merge_trees(t, ""); + trivial_merge_trees(t, ""); free(buf1); free(buf2); free(buf3); From patchwork Sat Jun 18 00:20:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886159 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4BDA8C433EF for ; Sat, 18 Jun 2022 00:21:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383663AbiFRAVL (ORCPT ); Fri, 17 Jun 2022 20:21:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383585AbiFRAVH (ORCPT ); Fri, 17 Jun 2022 20:21:07 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 660FC59322 for ; Fri, 17 Jun 2022 17:21:06 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id a10so3002933wmj.5 for ; Fri, 17 Jun 2022 17:21:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=s/FNUD3Nfv1aJ56di/sqnJE/jJBUPQEIKWoIKlAJYVg=; b=ql24hsoCkWDrtZY2zSNAdHjH2rVyUNEkNv8NuA4GCltvnSGA67zL0K3deYhRq2A++K xSCYqK53XEk8JZJVpMB4t1VjmuDMLzzK4p0XJnDbMViSFGTPoQku3tc5mcJanLFdibXz 7z9f3sjxcGH9MS5T4oGzzlVKDK4hNg9CWxmAgDnHxBATmcv3jOgiAUbmyOt3n8vBUzu9 PcqCVtN6Lb4U62/Q3MWIzFn+n6N84KBAYdnUhpVoqHaUnk6UAMD6fAL6Ek1PlTXJJ+hn x+tu2MlVcozIBqq97wzpJ6vnL+fG6earaOUeuTJX7ypJFsh4ArpqJHKr20qlx2AXMza2 6tKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=s/FNUD3Nfv1aJ56di/sqnJE/jJBUPQEIKWoIKlAJYVg=; b=3R/aGGneK/5Go6n5ocTv3yRfVA4a6Ss/y11wxWK35ScBELKB0gzby0q7w/Jr6EEi5/ TnvamI1geS2yWtMAsmYt3djl5qCfb8NlYKRHLBCifpWzAQw/e0lC6DzhR60prfkBVQP9 4yY0MpS59C2eLjmqqfuYp2Npn4zRJp2IvrxbcWtoU/v4y7s8fKqijNMeX0MDi75h7T0n V0UG48RUZ2KI5JHFCl4+kbFTKlyzbbLkhfijuIGJMivYSMa82uOCf26eZeN8hAWdjlWM UHqjf53Cb/z4WVaDmpIphk/NoaRNwCMZ1jUjAQsu4RFOgnri2NBpLhUwMTt+NBPAIfNw NhRw== X-Gm-Message-State: AJIora/ABvTJEvP0olUgJWKvEXBN+vfUbDMitkKV1/llOx14wMlnd/iP 8alC4TXOi0FePi9Fb3ucSkOyW3Sy8iaykQ== X-Google-Smtp-Source: AGRyM1uUGxvNxNxvGTJsxnOR/KnAZfaVZhDlyGIcVpXQYf20a+04GzKLLg4vMPoz3ELZ/INzjngslg== X-Received: by 2002:a05:600c:190b:b0:39c:7704:74a4 with SMTP id j11-20020a05600c190b00b0039c770474a4mr12397372wmq.92.1655511664358; Fri, 17 Jun 2022 17:21:04 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id d8-20020adfc088000000b00213ba0cab3asm5996560wrf.44.2022.06.17.17.21.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:03 -0700 (PDT) Message-Id: <8e0a79fa1ad0e1a86617e7f73f5534f5db9818e3.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:45 +0000 Subject: [PATCH v7 02/17] merge-tree: move logic for existing merge into new function Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren In preparation for adding a non-trivial merge capability to merge-tree, move the existing merge logic for trivial merges into a new function. Signed-off-by: Elijah Newren --- builtin/merge-tree.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 06f9eee9f78..914ec960b7e 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -366,15 +366,12 @@ static void *get_tree_descriptor(struct repository *r, return buf; } -int cmd_merge_tree(int argc, const char **argv, const char *prefix) +static int trivial_merge(int argc, const char **argv) { struct repository *r = the_repository; struct tree_desc t[3]; void *buf1, *buf2, *buf3; - if (argc != 4) - usage(merge_tree_usage); - buf1 = get_tree_descriptor(r, t+0, argv[1]); buf2 = get_tree_descriptor(r, t+1, argv[2]); buf3 = get_tree_descriptor(r, t+2, argv[3]); @@ -386,3 +383,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) show_result(); return 0; } + +int cmd_merge_tree(int argc, const char **argv, const char *prefix) +{ + if (argc != 4) + usage(merge_tree_usage); + return trivial_merge(argc, argv); +} From patchwork Sat Jun 18 00:20:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886160 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BDA4C43334 for ; Sat, 18 Jun 2022 00:21:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383679AbiFRAVN (ORCPT ); Fri, 17 Jun 2022 20:21:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383234AbiFRAVI (ORCPT ); Fri, 17 Jun 2022 20:21:08 -0400 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA2C059308 for ; Fri, 17 Jun 2022 17:21:07 -0700 (PDT) Received: by mail-wr1-x429.google.com with SMTP id e25so3651103wrc.13 for ; Fri, 17 Jun 2022 17:21:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=vEAtzJqQU86WTzAVqYZ5zRmNunliq8JAKiwDpJdSlvI=; b=pmCAuZ/+AqgBhGHFAyCW5q+8q1hFPiiPhSddrVztESPSSUzeOL1t61GmEn+Jy/Ecri gwa7LQvizTZ/FgUn5a5DJbdR7p7Wz30sKMMZ5KGncbU3Aty0qTRtQlliKA31hfqR9pmw rgzmWLadyJlfLB1VN//472BuF1OyHNZq8XZUVBSWtEVWrQPSZ7KbtZkOezTESX9xXLcx MfthMZiy5OLWEHdXaPubz5X0Hin1fngS9J3wU8uDmHvPmhhdEf84K1RvVpNrObBlIAwi lqItwLDsBNpowxkQEsXODqIusuzYOUuUBdNrKNwgMueM/LfFyGfRPiW2QM8tW9SLMdTB 3yPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=vEAtzJqQU86WTzAVqYZ5zRmNunliq8JAKiwDpJdSlvI=; b=7JL0QsS9bKQe94l6J/C+JxpUTnUntE3B1ZiFQ0LuWZgqT62rnIeg+CVdS/yehWeDsF mbezW2vtLDfa/9UZLFWGKgh2PCyOUPlkKRh73uIPcRj5t4CJWo74OTLRxmvJVJTN5/o3 tMZudKdQbRLS7Gl3RNqyj5M7BfznQaEU6Gvf0qjtfi/Fm1Y6AuLTZYwvzxVR4F6NpBZN qe+7ORND6ihV9XG9zUzXivm7MQY7HB68bc4/3XUXYXezBCUq6YbuC2jyFo3VA6193nlA fqy5qMVMzUyz6GqIODjqEqwIadyevzDamev4yfRXRMeBlO20K4twKpPeWzWKwX9A4qzC 0O1g== X-Gm-Message-State: AJIora8zCFiSV3O7yktUBPisfLUYB7Ca8fWwY3xFI4oaG8vw5QsSSOws ZyS4hrmS/OYgEmvz/nyMNZl6ngrHcr3Msw== X-Google-Smtp-Source: AGRyM1tQVuCnM+pKJ3MPQSOTr9LCi5G4ocnsfYHFRFeaOUR8CbDnDHbLrYc+oQdTww0KvX3Woz3MoA== X-Received: by 2002:a5d:64e7:0:b0:218:5626:7e7f with SMTP id g7-20020a5d64e7000000b0021856267e7fmr11379093wri.245.1655511665710; Fri, 17 Jun 2022 17:21:05 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id j19-20020a05600c1c1300b0039c5645c60fsm17047119wms.3.2022.06.17.17.21.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:05 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:46 +0000 Subject: [PATCH v7 03/17] merge-tree: add option parsing and initial shell for real merge function Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Let merge-tree accept a `--write-tree` parameter for choosing real merges instead of trivial merges, and accept an optional `--trivial-merge` option to get the traditional behavior. Note that these accept different numbers of arguments, though, so these names need not actually be used. Note that real merges differ from trivial merges in that they handle: - three way content merges - recursive ancestor consolidation - renames - proper directory/file conflict handling - etc. Basically all the stuff you'd expect from `git merge`, just without updating the index and working tree. The initial shell added here does nothing more than die with "real merges are not yet implemented", but that will be fixed in subsequent commits. Signed-off-by: Elijah Newren --- builtin/merge-tree.c | 84 +++++++++++++++++++++++++++++++++++++++----- git.c | 2 +- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 914ec960b7e..0f9d928e862 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -3,13 +3,12 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "object-store.h" +#include "parse-options.h" #include "repository.h" #include "blob.h" #include "exec-cmd.h" #include "merge-blobs.h" -static const char merge_tree_usage[] = "git merge-tree "; - struct merge_list { struct merge_list *next; struct merge_list *link; /* other stages for this object */ @@ -366,15 +365,17 @@ static void *get_tree_descriptor(struct repository *r, return buf; } -static int trivial_merge(int argc, const char **argv) +static int trivial_merge(const char *base, + const char *branch1, + const char *branch2) { struct repository *r = the_repository; struct tree_desc t[3]; void *buf1, *buf2, *buf3; - buf1 = get_tree_descriptor(r, t+0, argv[1]); - buf2 = get_tree_descriptor(r, t+1, argv[2]); - buf3 = get_tree_descriptor(r, t+2, argv[3]); + buf1 = get_tree_descriptor(r, t+0, base); + buf2 = get_tree_descriptor(r, t+1, branch1); + buf3 = get_tree_descriptor(r, t+2, branch2); trivial_merge_trees(t, ""); free(buf1); free(buf2); @@ -384,9 +385,74 @@ static int trivial_merge(int argc, const char **argv) return 0; } +enum mode { + MODE_UNKNOWN, + MODE_TRIVIAL, + MODE_REAL, +}; + +struct merge_tree_options { + int mode; +}; + +static int real_merge(struct merge_tree_options *o, + const char *branch1, const char *branch2) +{ + die(_("real merges are not yet implemented")); +} + int cmd_merge_tree(int argc, const char **argv, const char *prefix) { - if (argc != 4) - usage(merge_tree_usage); - return trivial_merge(argc, argv); + struct merge_tree_options o = { 0 }; + int expected_remaining_argc; + + const char * const merge_tree_usage[] = { + N_("git merge-tree [--write-tree] "), + N_("git merge-tree [--trivial-merge] "), + NULL + }; + struct option mt_options[] = { + OPT_CMDMODE(0, "write-tree", &o.mode, + N_("do a real merge instead of a trivial merge"), + MODE_REAL), + OPT_CMDMODE(0, "trivial-merge", &o.mode, + N_("do a trivial merge only"), MODE_TRIVIAL), + OPT_END() + }; + + /* Parse arguments */ + argc = parse_options(argc, argv, prefix, mt_options, + merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION); + switch (o.mode) { + default: + BUG("unexpected command mode %d", o.mode); + case MODE_UNKNOWN: + switch (argc) { + default: + usage_with_options(merge_tree_usage, mt_options); + case 2: + o.mode = MODE_REAL; + break; + case 3: + o.mode = MODE_TRIVIAL; + break; + } + expected_remaining_argc = argc; + break; + case MODE_REAL: + expected_remaining_argc = 2; + break; + case MODE_TRIVIAL: + expected_remaining_argc = 3; + break; + } + + if (argc != expected_remaining_argc) + usage_with_options(merge_tree_usage, mt_options); + + /* Do the relevant type of merge */ + if (o.mode == MODE_REAL) + return real_merge(&o, argv[0], argv[1]); + else + return trivial_merge(argv[0], argv[1], argv[2]); } diff --git a/git.c b/git.c index 5ff4f3e25b7..861d966c374 100644 --- a/git.c +++ b/git.c @@ -565,7 +565,7 @@ static struct cmd_struct commands[] = { { "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-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, - { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT }, + { "merge-tree", cmd_merge_tree, RUN_SETUP }, { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, { "mktree", cmd_mktree, RUN_SETUP }, { "multi-pack-index", cmd_multi_pack_index, RUN_SETUP }, From patchwork Sat Jun 18 00:20:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886162 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E732FC43334 for ; Sat, 18 Jun 2022 00:21:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383712AbiFRAVV (ORCPT ); Fri, 17 Jun 2022 20:21:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383658AbiFRAVL (ORCPT ); Fri, 17 Jun 2022 20:21:11 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 314DC59322 for ; Fri, 17 Jun 2022 17:21:09 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id c21so7538545wrb.1 for ; Fri, 17 Jun 2022 17:21:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=Qp5R/2nEDrwidqRUvDGZRkgucr9emIb2r0juqChWThw=; b=I+DQIiqwpBjfMuFoTYoVnPmv0CV9BRK7DA8GE45mY8rhFvvmRMIaTFEtbgydHHnisl H0eFal20YsH4r46AhBVuvcqH813WwJtDDPajOqyDqz+NJkx0Y5DBr0vDoEyZztE38ZVK 8TGo+k1S8pICTs4WPbim/oI+ZFvJvVfNZdN4IQretUxLWm4O8/QRYE6QnEM2th8lLeVW 4xYQmsoJI3kP11lW0wgNB9ZMSsrsctdGeLbtrce4372iBYxWeHKUupp+YdQe09l/K/Bo NlCd4/QbM8W+O2gg1hfjA1wKfp8edKAbLmkPTex3MKQGUoPOqUyKnCXVqGEfPqOSfz4T nNew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=Qp5R/2nEDrwidqRUvDGZRkgucr9emIb2r0juqChWThw=; b=wu8b6XaYCUrOm+LVhQbFW/HU6KTAY32sSgN+6xY72/ym6mu/J+MGLVmSvjVetwfimM CCgXei/MHVCLEoivNkCH++4Tj99ryzbnB/imX4HEkcJyRoLiaScjSU2JpzcQkZITlKpN m0AjMHm1s5hI16szFngXTTTZNaabZjHpEK+3MbZwgZCChxZLMKIE8TwFWN/Ic5/SJc6O HaB/y2ksgJwSSTyJ68EGiuewsG5vY2nfIXP+68kdBO7Y+Bqy4eW11KBj2tQvTBUjPASk L4ZLaMijPTEeuDMliiFnAjb+QkhGS8egJlh7m3wW4kyaVjPnIzVxVWFga4Nw67hyzfFf U1Xw== X-Gm-Message-State: AJIora+6u2zR0qtuL8FMOr+Z6P2RQBk7O9NAfhiqXTEO7dCVKKd7uEz6 OZg/zQ1cyVm5ykDm3E+2rxq/6nNSe0RcyA== X-Google-Smtp-Source: AGRyM1t+EGVOIiyLVAyN9FwNKu6I250V9I46vEyzmdOTmSAp8HnRVlwfVRePLBe6yqdZmj/+Ibe5kg== X-Received: by 2002:a05:6000:1e04:b0:217:88ff:eb86 with SMTP id bj4-20020a0560001e0400b0021788ffeb86mr11570990wrb.351.1655511667172; Fri, 17 Jun 2022 17:21:07 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i30-20020a1c541e000000b0039c15861001sm10033094wmb.21.2022.06.17.17.21.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:06 -0700 (PDT) Message-Id: <697470e50aeeb546e055e6c57b17aea32d9ea451.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:47 +0000 Subject: [PATCH v7 04/17] merge-tree: implement real merges Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren This adds the ability to perform real merges rather than just trivial merges (meaning handling three way content merges, recursive ancestor consolidation, renames, proper directory/file conflict handling, and so forth). However, unlike `git merge`, the working tree and index are left alone and no branch is updated. The only output is: - the toplevel resulting tree printed on stdout - exit status of 0 (clean), 1 (conflicts present), anything else (merge could not be performed; unknown if clean or conflicted) This output is meant to be used by some higher level script, perhaps in a sequence of steps like this: NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) test $? -eq 0 || die "There were conflicts..." NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2) git update-ref $BRANCH1 $NEWCOMMIT Note that higher level scripts may also want to access the conflict/warning messages normally output during a merge, or have quick access to a list of files with conflicts. That is not available in this preliminary implementation, but subsequent commits will add that ability (meaning that NEWTREE would be a lot more than a tree in the case of conflicts). This also marks the traditional trivial merge of merge-tree as deprecated. The trivial merge not only had limited applicability, the output format was also difficult to work with (and its format undocumented), and will generally be less performant than real merges. Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 98 ++++++++++++++++++++++++---- builtin/merge-tree.c | 41 +++++++++++- t/t4301-merge-tree-write-tree.sh | 106 +++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 13 deletions(-) create mode 100755 t/t4301-merge-tree-write-tree.sh diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 58731c19422..2a9c91328de 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -3,26 +3,100 @@ git-merge-tree(1) NAME ---- -git-merge-tree - Show three-way merge without touching index +git-merge-tree - Perform merge without touching index or working tree SYNOPSIS -------- [verse] -'git merge-tree' +'git merge-tree' [--write-tree] +'git merge-tree' [--trivial-merge] (deprecated) +[[NEWMERGE]] DESCRIPTION ----------- -Reads three tree-ish, and output trivial merge results and -conflicting stages to the standard output. This is similar to -what three-way 'git read-tree -m' does, but instead of storing the -results in the index, the command outputs the entries to the -standard output. - -This is meant to be used by higher level scripts to compute -merge results outside of the index, and stuff the results back into the -index. For this reason, the output from the command omits -entries that match the tree. + +This command has a modern `--write-tree` mode and a deprecated +`--trivial-merge` mode. With the exception of the +<> section at the end, the rest of +this documentation describes modern `--write-tree` mode. + +Performs a merge, but does not make any new commits and does not read +from or write to either the working tree or index. + +The performed merge will use the same feature as the "real" +linkgit:git-merge[1], including: + + * three way content merges of individual files + * rename detection + * proper directory/file conflict handling + * recursive ancestor consolidation (i.e. when there is more than one + merge base, creating a virtual merge base by merging the merge bases) + * etc. + +After the merge completes, a new toplevel tree object is created. See +`OUTPUT` below for details. + +[[OUTPUT]] +OUTPUT +------ + +For either a successful or conflicted merge, the output from +git-merge-tree is simply one line: + + + +The printed tree object corresponds to what would be checked out in +the working tree at the end of `git merge`, and thus may have files +with conflict markers in them. + +EXIT STATUS +----------- + +For a successful, non-conflicted merge, the exit status is 0. When the +merge has conflicts, the exit status is 1. If the merge is not able to +complete (or start) due to some kind of error, the exit status is +something other than 0 or 1 (and the output is unspecified). + +USAGE NOTES +----------- + +This command is intended as low-level plumbing, similar to +linkgit:git-hash-object[1], linkgit:git-mktree[1], +linkgit:git-commit-tree[1], linkgit:git-write-tree[1], +linkgit:git-update-ref[1], and linkgit:git-mktag[1]. Thus, it can be +used as a part of a series of steps such as: + + NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) + test $? -eq 0 || die "There were conflicts..." + NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2) + git update-ref $BRANCH1 $NEWCOMMIT + +[[DEPMERGE]] +DEPRECATED DESCRIPTION +---------------------- + +Per the <> and unlike the rest of this +documentation, this section describes the deprecated `--trivial-merge` +mode. + +Other than the optional `--trivial-merge`, this mode accepts no +options. + +This mode reads three tree-ish, and outputs trivial merge results and +conflicting stages to the standard output in a semi-diff format. +Since this was designed for higher level scripts to consume and merge +the results back into the index, it omits entries that match +. The result of this second form is similar to what +three-way 'git read-tree -m' does, but instead of storing the results +in the index, the command outputs the entries to the standard output. + +This form not only has limited applicability (a trivial merge cannot +handle content merges of individual files, rename detection, proper +directory/file conflict handling, etc.), the output format is also +difficult to work with, and it will generally be less performant than +the first form even on successful merges (especially if working in +large repositories). GIT --- diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 0f9d928e862..2332525d8bd 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -2,6 +2,9 @@ #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" +#include "help.h" +#include "commit-reach.h" +#include "merge-ort.h" #include "object-store.h" #include "parse-options.h" #include "repository.h" @@ -398,7 +401,43 @@ struct merge_tree_options { static int real_merge(struct merge_tree_options *o, const char *branch1, const char *branch2) { - die(_("real merges are not yet implemented")); + struct commit *parent1, *parent2; + struct commit_list *merge_bases = NULL; + struct merge_options opt; + struct merge_result result = { 0 }; + + parent1 = get_merge_parent(branch1); + if (!parent1) + help_unknown_ref(branch1, "merge-tree", + _("not something we can merge")); + + parent2 = get_merge_parent(branch2); + if (!parent2) + help_unknown_ref(branch2, "merge-tree", + _("not something we can merge")); + + init_merge_options(&opt, the_repository); + + opt.show_rename_progress = 0; + + opt.branch1 = branch1; + opt.branch2 = branch2; + + /* + * Get the merge bases, in reverse order; see comment above + * merge_incore_recursive in merge-ort.h + */ + merge_bases = get_merge_bases(parent1, parent2); + if (!merge_bases) + die(_("refusing to merge unrelated histories")); + merge_bases = reverse_commit_list(merge_bases); + + merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result); + if (result.clean < 0) + die(_("failure to merge")); + puts(oid_to_hex(&result.tree->object.oid)); + merge_finalize(&opt, &result); + return !result.clean; /* result.clean < 0 handled above */ } int cmd_merge_tree(int argc, const char **argv, const char *prefix) diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh new file mode 100755 index 00000000000..6d321652e21 --- /dev/null +++ b/t/t4301-merge-tree-write-tree.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +test_description='git merge-tree --write-tree' + +. ./test-lib.sh + +# This test is ort-specific +if test "$GIT_TEST_MERGE_ALGORITHM" != "ort" +then + skip_all="GIT_TEST_MERGE_ALGORITHM != ort" + test_done +fi + +test_expect_success setup ' + test_write_lines 1 2 3 4 5 >numbers && + echo hello >greeting && + echo foo >whatever && + git add numbers greeting whatever && + test_tick && + git commit -m initial && + + git branch side1 && + git branch side2 && + git branch side3 && + + git checkout side1 && + test_write_lines 1 2 3 4 5 6 >numbers && + echo hi >greeting && + echo bar >whatever && + git add numbers greeting whatever && + test_tick && + git commit -m modify-stuff && + + git checkout side2 && + test_write_lines 0 1 2 3 4 5 >numbers && + echo yo >greeting && + git rm whatever && + mkdir whatever && + >whatever/empty && + git add numbers greeting whatever/empty && + test_tick && + git commit -m other-modifications && + + git checkout side3 && + git mv numbers sequence && + test_tick && + git commit -m rename-numbers +' + +test_expect_success 'Clean merge' ' + TREE_OID=$(git merge-tree --write-tree side1 side3) && + q_to_tab <<-EOF >expect && + 100644 blob $(git rev-parse side1:greeting)Qgreeting + 100644 blob $(git rev-parse side1:numbers)Qsequence + 100644 blob $(git rev-parse side1:whatever)Qwhatever + EOF + + git ls-tree $TREE_OID >actual && + test_cmp expect actual +' + +test_expect_success 'Content merge and a few conflicts' ' + git checkout side1^0 && + test_must_fail git merge side2 && + expected_tree=$(git rev-parse AUTO_MERGE) && + + # We will redo the merge, while we are still in a conflicted state! + test_when_finished "git reset --hard" && + + test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT && + actual_tree=$(head -n 1 RESULT) && + + # Due to differences of e.g. "HEAD" vs "side1", the results will not + # exactly match. Dig into individual files. + + # Numbers should have three-way merged cleanly + test_write_lines 0 1 2 3 4 5 6 >expect && + git show ${actual_tree}:numbers >actual && + test_cmp expect actual && + + # whatever and whatever~ should have same HASHES + git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect && + git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual && + test_cmp expect actual && + + # greeting should have a merge conflict + git show ${expected_tree}:greeting >tmp && + sed -e s/HEAD/side1/ tmp >expect && + git show ${actual_tree}:greeting >actual && + test_cmp expect actual +' + +test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' ' + # Mis-spell with single "s" instead of double "s" + test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect && + + grep "error: unknown option.*mesages" expect +' + +test_expect_success 'Barf on too many arguments' ' + test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect && + + grep "^usage: git merge-tree" expect +' + +test_done From patchwork Sat Jun 18 00:20:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886161 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19723C43334 for ; Sat, 18 Jun 2022 00:21:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383710AbiFRAVU (ORCPT ); Fri, 17 Jun 2022 20:21:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43454 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383657AbiFRAVK (ORCPT ); Fri, 17 Jun 2022 20:21:10 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 76DA159940 for ; Fri, 17 Jun 2022 17:21:09 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id a10so3002933wmj.5 for ; Fri, 17 Jun 2022 17:21:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=CcJkWnEFnOZJo37/Id2fDAEn7q90VLqUiJDTNnkGQco=; b=nQP5p9+/ClATQJammKPduc7mnjIgg/mWhpLUEfN9G4UzQ5eg1sJtBRKMr04g+TgVh5 CzHafSPWALN/Rn8LJQV7xS9ZWPb9A9o3FIIAW/q96NWBYWfja5MTm6EIj4H6wRQvLXBk nNPj7ESlV77RKFrjajWncMHetHuLpf/DgCsEGuIyaXaHU1T1wVCBELoa3VKZensh579o qpIkr++XatC7zidv4GFnGvTTxcWkOZjWWrrPD3JrDYNFIZmo7thxwTyYlpYW5w7BYkNy PyHlXkACB7HHpYo3H6SH/hYFTLvWC8MYMew2aELtngKrnGq3mdWjB6rsJ/Ud2iaX9rtH j2VQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=CcJkWnEFnOZJo37/Id2fDAEn7q90VLqUiJDTNnkGQco=; b=Gtg3oX+eNa83qyd7V4GCAokPHF1CZzMpHNOM47GmfO1ek/77bLstY0odVnPf8hJrkh xkOAL4RRfAzutrlLJ474xhLrhKy0k5HIU6/vnOhogjloTty4nKS3AzbbjOuIFGIeG+6K L5QOylGdaKZIUkNSfx5QzfY1XYcR0i8G+y6d3hOq8G6heDtKMGQ/W9WtW46dGsLV6Wcn o4FFu2jCgwz2vbC8T9BAoiQveI8Udfu4wtYOqvpEyr2pYm6tgO4seg7bIJXOwNA4jWrb JbWvs5ZluqXIdhDDIJI15pS3YBrHemyVYl94XDtC2IjXdldurUbaCXCd28jGlaRgXzn6 t8Vg== X-Gm-Message-State: AJIora9FlZb0y0mrWC5MXbNxCS+OlKHVChLFCncrFgACkvmoqkDJZFFj rJ2agsFTpRmX0rR3P7+EXDskL/bZyEN5yg== X-Google-Smtp-Source: AGRyM1tsEct64cZ1d5mObgpmynEDCCjaky0vvLGTac5pZBRWtaqa5xmzrh2TdKYTilve81ziZZe/OA== X-Received: by 2002:a1c:f213:0:b0:39b:ad32:5e51 with SMTP id s19-20020a1cf213000000b0039bad325e51mr12518360wmc.72.1655511668580; Fri, 17 Jun 2022 17:21:08 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h8-20020a05600c350800b0039c50d2d28csm10798190wmq.44.2022.06.17.17.21.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:08 -0700 (PDT) Message-Id: <069af1ecc303b38b18f053c040416954097f2ee4.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:48 +0000 Subject: [PATCH v7 05/17] merge-ort: split out a separate display_update_messages() function Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren This patch includes no new code; it simply moves a bunch of lines into a new function. As such, there are no functional changes. This is just a preparatory step to allow the printed messages to be handled differently by other callers, such as in `git merge-tree --write-tree`. (Patch best viewed with --color-moved --color-moved-ws=allow-indentation-change to see that it is a simple code movement.) Signed-off-by: Elijah Newren --- merge-ort.c | 78 ++++++++++++++++++++++++++++------------------------- merge-ort.h | 8 ++++++ 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index 0d3f42592fb..b9c9e906e94 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4256,6 +4256,45 @@ static int record_conflicted_index_entries(struct merge_options *opt) return errs; } +void merge_display_update_messages(struct merge_options *opt, + struct merge_result *result) +{ + struct merge_options_internal *opti = result->priv; + struct hashmap_iter iter; + struct strmap_entry *e; + struct string_list olist = STRING_LIST_INIT_NODUP; + int i; + + if (opt->record_conflict_msgs_as_headers) + BUG("Either display conflict messages or record them as headers, not both"); + + trace2_region_enter("merge", "display messages", opt->repo); + + /* Hack to pre-allocate olist to the desired size */ + ALLOC_GROW(olist.items, strmap_get_size(&opti->output), + olist.alloc); + + /* Put every entry from output into olist, then sort */ + strmap_for_each_entry(&opti->output, &iter, e) { + string_list_append(&olist, e->key)->util = e->value; + } + string_list_sort(&olist); + + /* Iterate over the items, printing them */ + for (i = 0; i < olist.nr; ++i) { + struct strbuf *sb = olist.items[i].util; + + printf("%s", sb->buf); + } + string_list_clear(&olist, 0); + + /* Also include needed rename limit adjustment now */ + diff_warn_rename_limit("merge.renamelimit", + opti->renames.needed_limit, 0); + + trace2_region_leave("merge", "display messages", opt->repo); +} + void merge_switch_to_result(struct merge_options *opt, struct tree *head, struct merge_result *result, @@ -4293,43 +4332,8 @@ void merge_switch_to_result(struct merge_options *opt, fclose(fp); trace2_region_leave("merge", "write_auto_merge", opt->repo); } - - if (display_update_msgs) { - struct merge_options_internal *opti = result->priv; - struct hashmap_iter iter; - struct strmap_entry *e; - struct string_list olist = STRING_LIST_INIT_NODUP; - int i; - - if (opt->record_conflict_msgs_as_headers) - BUG("Either display conflict messages or record them as headers, not both"); - - trace2_region_enter("merge", "display messages", opt->repo); - - /* Hack to pre-allocate olist to the desired size */ - ALLOC_GROW(olist.items, strmap_get_size(&opti->output), - olist.alloc); - - /* Put every entry from output into olist, then sort */ - strmap_for_each_entry(&opti->output, &iter, e) { - string_list_append(&olist, e->key)->util = e->value; - } - string_list_sort(&olist); - - /* Iterate over the items, printing them */ - for (i = 0; i < olist.nr; ++i) { - struct strbuf *sb = olist.items[i].util; - - printf("%s", sb->buf); - } - string_list_clear(&olist, 0); - - /* Also include needed rename limit adjustment now */ - diff_warn_rename_limit("merge.renamelimit", - opti->renames.needed_limit, 0); - - trace2_region_leave("merge", "display messages", opt->repo); - } + if (display_update_msgs) + merge_display_update_messages(opt, result); merge_finalize(opt, result); } diff --git a/merge-ort.h b/merge-ort.h index fe599b87868..e5aec45b18f 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -80,6 +80,14 @@ void merge_switch_to_result(struct merge_options *opt, int update_worktree_and_index, int display_update_msgs); +/* + * Display messages about conflicts and which files were 3-way merged. + * Automatically called by merge_switch_to_result() with stream == stdout, + * so only call this when bypassing merge_switch_to_result(). + */ +void merge_display_update_messages(struct merge_options *opt, + struct merge_result *result); + /* Do needed cleanup when not calling merge_switch_to_result() */ void merge_finalize(struct merge_options *opt, struct merge_result *result); From patchwork Sat Jun 18 00:20:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886163 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C344C433EF for ; Sat, 18 Jun 2022 00:21:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383758AbiFRAVb (ORCPT ); Fri, 17 Jun 2022 20:21:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383685AbiFRAVS (ORCPT ); Fri, 17 Jun 2022 20:21:18 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2F1859973 for ; Fri, 17 Jun 2022 17:21:11 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id s1so7511966wra.9 for ; Fri, 17 Jun 2022 17:21:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=WpxAId1kdO/lJ7t476gCpgr/ZvqAUZeQTXQX9mQSlaQ=; b=PTjQLfg0ZI7XjGwDl2GGKnIuKFSyPYem4ikxNOzPo3GUGk+eAf9aP1glvMPFmaZlVn YAr3SWsMK00/J5BP0TPbsBv9VyUerezzloLU2ThbtmdMTNHquXNOSdHL6N+F/jsuctOS wuEdl9VdlaA6/v12N7u9eh65R6rg2hMq3FVuXIe1hKIdzOCQQqFeWG5BZcvkf7erAY1B pLZXcjmiA1gn8YVSh4pCJGM0ShRwKfw2UGWblDK8H9qq5Dh+dVLZDmR5xVxWqRoDIrcY JSiXX+l4rGADdWAyTLpWIs+DyZXzXm9YUqc65RnMPHTolyMPUg81rQC/kiezAES/80xy d/ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=WpxAId1kdO/lJ7t476gCpgr/ZvqAUZeQTXQX9mQSlaQ=; b=Vafmhh622gUdgVlAmSnox04EH9NoHuIM+h0XI9QPAOF9j1CGfbYsvZzdfD56aTOC6y 6aNjilbCS6oRUzgT4IMYJkS2o6NqiEB4ukXEhoh/GSWQnT1MWESTmX0LnvB73EhI+0FK 0O8xYpOyvS1uh/sT+XJD+z05VqLHsNhBsNYf4PpJCl61xobXD0vac9QuSdjdF5mfIRCC WGeVPK8Dwf3J6SWt4scwcSEdrqXSbGaUkGASChkPB3np6zB14wyJoOlLJfHSR5oe+M7M jjW0e0UVEIPvef4t05RuPwsBwoegc8xxVy4BHg+LtZSMjLJvLkJDx2dfaOVaDeS8s+7j G2SQ== X-Gm-Message-State: AJIora+modbik6RVWv5+qCKz4gbh4OFID4ofbWdku7f9QSSLmXZdnW3K gLxZmORNDXRX6ZKDntx10/uJRW2ijIE7hA== X-Google-Smtp-Source: AGRyM1vs7UV8brxbjnl5P9i3TixrGQC+y5pKBCZdNOGrg+676NvcKiOoVigJS/yjNBMh47hsadCxow== X-Received: by 2002:adf:fa8b:0:b0:214:1f4f:5e71 with SMTP id h11-20020adffa8b000000b002141f4f5e71mr11209722wrr.149.1655511669988; Fri, 17 Jun 2022 17:21:09 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id d3-20020adffbc3000000b0020e6ce4dabdsm6070589wrs.103.2022.06.17.17.21.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:09 -0700 (PDT) Message-Id: <53c92a5d8d93c30305dddf8e2aa7a5e7fdfb493f.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:49 +0000 Subject: [PATCH v7 06/17] merge-tree: support including merge messages in output Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren When running `git merge-tree --write-tree`, we previously would only return an exit status reflecting the cleanness of a merge, and print out the toplevel tree of the resulting merge. Merges also have informational messages, such as: * "Auto-merging " * "CONFLICT (content): ..." * "CONFLICT (file/directory)" * etc. In fact, when non-content conflicts occur (such as file/directory, modify/delete, add/add with differing modes, rename/rename (1to2), etc.), these informational messages may be the only notification the user gets since these conflicts are not representable in the contents of the file. Add a --[no-]messages option so that callers can request these messages be included at the end of the output. Include such messages by default when there are conflicts, and omit them by default when the merge is clean. Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 47 ++++++++++++++++++++++++++++---- builtin/merge-tree.c | 21 ++++++++++++-- t/t4301-merge-tree-write-tree.sh | 37 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 8 deletions(-) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 2a9c91328de..25b462be14e 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -9,7 +9,7 @@ git-merge-tree - Perform merge without touching index or working tree SYNOPSIS -------- [verse] -'git merge-tree' [--write-tree] +'git merge-tree' [--write-tree] [] 'git merge-tree' [--trivial-merge] (deprecated) [[NEWMERGE]] @@ -37,18 +37,50 @@ linkgit:git-merge[1], including: After the merge completes, a new toplevel tree object is created. See `OUTPUT` below for details. +OPTIONS +------- + +--[no-]messages:: + Write any informational messages such as "Auto-merging " + or CONFLICT notices to the end of stdout. If unspecified, the + default is to include these messages if there are merge + conflicts, and to omit them otherwise. + [[OUTPUT]] OUTPUT ------ -For either a successful or conflicted merge, the output from -git-merge-tree is simply one line: +For a successful merge, the output from git-merge-tree is simply one +line: + + + +Whereas for a conflicted merge, the output is by default of the form: + + +These are discussed individually below. -The printed tree object corresponds to what would be checked out in -the working tree at the end of `git merge`, and thus may have files -with conflict markers in them. +[[OIDTLT]] +OID of toplevel tree +~~~~~~~~~~~~~~~~~~~~ + +This is a tree object that represents what would be checked out in the +working tree at the end of `git merge`. If there were conflicts, then +files within this tree may have embedded conflict markers. + +[[IM]] +Informational messages +~~~~~~~~~~~~~~~~~~~~~~ + +This always starts with a blank line to separate it from the previous +section, and then has free-form messages about the merge, such as: + + * "Auto-merging " + * "CONFLICT (rename/delete): renamed...but deleted in..." + * "Failed to merge submodule ()" + * "Warning: cannot merge binary files: " EXIT STATUS ----------- @@ -72,6 +104,9 @@ used as a part of a series of steps such as: NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2) git update-ref $BRANCH1 $NEWCOMMIT +Note that when the exit status is non-zero, `NEWTREE` in this sequence +will contain a lot more output than just a tree. + [[DEPMERGE]] DEPRECATED DESCRIPTION ---------------------- diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 2332525d8bd..831d9c77583 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -396,6 +396,7 @@ enum mode { struct merge_tree_options { int mode; + int show_messages; }; static int real_merge(struct merge_tree_options *o, @@ -435,18 +436,27 @@ static int real_merge(struct merge_tree_options *o, merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result); if (result.clean < 0) die(_("failure to merge")); + + if (o->show_messages == -1) + o->show_messages = !result.clean; + puts(oid_to_hex(&result.tree->object.oid)); + if (o->show_messages) { + printf("\n"); + merge_display_update_messages(&opt, &result); + } merge_finalize(&opt, &result); return !result.clean; /* result.clean < 0 handled above */ } int cmd_merge_tree(int argc, const char **argv, const char *prefix) { - struct merge_tree_options o = { 0 }; + struct merge_tree_options o = { .show_messages = -1 }; int expected_remaining_argc; + int original_argc; const char * const merge_tree_usage[] = { - N_("git merge-tree [--write-tree] "), + N_("git merge-tree [--write-tree] [] "), N_("git merge-tree [--trivial-merge] "), NULL }; @@ -456,10 +466,13 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) MODE_REAL), OPT_CMDMODE(0, "trivial-merge", &o.mode, N_("do a trivial merge only"), MODE_TRIVIAL), + OPT_BOOL(0, "messages", &o.show_messages, + N_("also show informational/conflict messages")), OPT_END() }; /* Parse arguments */ + original_argc = argc - 1; /* ignoring argv[0] */ argc = parse_options(argc, argv, prefix, mt_options, merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION); switch (o.mode) { @@ -483,8 +496,12 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) break; case MODE_TRIVIAL: expected_remaining_argc = 3; + /* Removal of `--trivial-merge` is expected */ + original_argc--; break; } + if (o.mode == MODE_TRIVIAL && argc < original_argc) + die(_("--trivial-merge is incompatible with all other options")); if (argc != expected_remaining_argc) usage_with_options(merge_tree_usage, mt_options); diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 6d321652e21..719d81e7173 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -103,4 +103,41 @@ test_expect_success 'Barf on too many arguments' ' grep "^usage: git merge-tree" expect ' +anonymize_hash() { + sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@" +} + +test_expect_success 'test conflict notices and such' ' + test_expect_code 1 git merge-tree --write-tree side1 side2 >out && + anonymize_hash out >actual && + + # Expected results: + # "greeting" should merge with conflicts + # "numbers" should merge cleanly + # "whatever" has *both* a modify/delete and a file/directory conflict + cat <<-EOF >expect && + HASH + + Auto-merging greeting + CONFLICT (content): Merge conflict in greeting + Auto-merging numbers + CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead. + CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree. + EOF + + test_cmp expect actual +' + +for opt in $(git merge-tree --git-completion-helper-all) +do + if test $opt = "--trivial-merge" || test $opt = "--write-tree" + then + continue + fi + + test_expect_success "usage: --trivial-merge is incompatible with $opt" ' + test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3 + ' +done + test_done From patchwork Sat Jun 18 00:20:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886164 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1AEFEC433EF for ; Sat, 18 Jun 2022 00:21:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383730AbiFRAVf (ORCPT ); Fri, 17 Jun 2022 20:21:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43630 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383690AbiFRAVS (ORCPT ); Fri, 17 Jun 2022 20:21:18 -0400 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0418759B9E for ; Fri, 17 Jun 2022 17:21:13 -0700 (PDT) Received: by mail-wm1-x330.google.com with SMTP id m125-20020a1ca383000000b0039c63fe5f64so3082305wme.0 for ; Fri, 17 Jun 2022 17:21:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=0nohZfrU3waxiggkleheiPc9iFJgwC2t5qYWboTFqks=; b=a5qfH1vc6N/eLc2sopo3TMQJ5uQUa4NwIDKXJQuu/7ZTDvH+VVJSehfTjXm+EQuKwD e/sJrPVYGIGeR3WXnBZUn5mkX3JMgrRs0YjePJy0RgLd9XQuUIYzEltYVk/d4NeGa0cZ n6udQFn1sxdwgrIJ/Ja6szt0f3zcaBj2L5yzx8cNYWKieLLiEZmmPnxX3jLkiJJx9Kam ZMZPheEfXgQQx6TSFlj+dsZCGk5Ndt6XVfulwg5P2HopJv/3v/VkHjpD5vvNnxzbIt4x gWhBwscNODUZzxq8WleuCawQf+vawkMZNZzUb0pUmF5J8RTlX/8S0N4YorpEjQ6RjhEQ o2vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=0nohZfrU3waxiggkleheiPc9iFJgwC2t5qYWboTFqks=; b=wFPcGwhMMI7cZX4uTt8POPkB432f6sogfYpMofDBpdu+F9wbAHsnumkwcme+ZZldlL hz/Kn7QbwA1WnJhRqKd5eF725PKIIxSRbt7u1SuPDYJfCnrEQG0fA+ppHTTKal5EveDu aqgOCsCUC/w8xes4udOwbq2Ld1/EWZqLuRBuKwhDJ4Cox0pL7MIGnP+t80/ZuxbsrQh7 9GZPgiAjittMVkv2YNGHa2NfZM1uVfdFm7ENrd892755l93ff50F/27IKxhf7k7zsfsC YjTbuqf5UWK+oQx3HkettMpeKEt/6Fb9dsUM8Yutz+bET19NgHKK0Je3HvN3CHtpBnWQ D8EA== X-Gm-Message-State: AOAM530qReEIhO2iH+iGMyFwQi9YYLsvQLGbb0uIhGy1UdJqcyTxPBZr JiT/nTAhxmtqO1MKz8h/74s1dlTcmhUBwQ== X-Google-Smtp-Source: ABdhPJxiFyT6Oxr5nOHjMkny3qIJPLYtoT+bvRHlXrdR4HaJTTsf+VBut+rM4q8vt7AIoDWUC0xkSw== X-Received: by 2002:a05:600c:8a4:b0:39c:54fd:acbb with SMTP id l36-20020a05600c08a400b0039c54fdacbbmr23599381wmp.92.1655511671067; Fri, 17 Jun 2022 17:21:11 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z6-20020a7bc7c6000000b0039c63f4bce0sm10318327wmk.12.2022.06.17.17.21.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:10 -0700 (PDT) Message-Id: <67a728d35f0e3a3dde63d7fc8116ed20cad44141.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:50 +0000 Subject: [PATCH v7 07/17] merge-ort: provide a merge_get_conflicted_files() helper function Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren After a merge, this function allows the user to extract the same information that would be printed by `ls-files -u`, which means files with their mode, oid, and stage. Signed-off-by: Elijah Newren --- merge-ort.c | 31 +++++++++++++++++++++++++++++++ merge-ort.h | 21 +++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/merge-ort.c b/merge-ort.c index b9c9e906e94..1635d215c0b 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4295,6 +4295,37 @@ void merge_display_update_messages(struct merge_options *opt, trace2_region_leave("merge", "display messages", opt->repo); } +void merge_get_conflicted_files(struct merge_result *result, + struct string_list *conflicted_files) +{ + struct hashmap_iter iter; + struct strmap_entry *e; + struct merge_options_internal *opti = result->priv; + + strmap_for_each_entry(&opti->conflicted, &iter, e) { + const char *path = e->key; + struct conflict_info *ci = e->value; + int i; + + VERIFY_CI(ci); + + for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) { + struct stage_info *si; + + if (!(ci->filemask & (1ul << i))) + continue; + + si = xmalloc(sizeof(*si)); + si->stage = i+1; + si->mode = ci->stages[i].mode; + oidcpy(&si->oid, &ci->stages[i].oid); + string_list_append(conflicted_files, path)->util = si; + } + } + /* string_list_sort() uses a stable sort, so we're good */ + string_list_sort(conflicted_files); +} + void merge_switch_to_result(struct merge_options *opt, struct tree *head, struct merge_result *result, diff --git a/merge-ort.h b/merge-ort.h index e5aec45b18f..ddcc39d7270 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -2,6 +2,7 @@ #define MERGE_ORT_H #include "merge-recursive.h" +#include "hash.h" struct commit; struct tree; @@ -88,6 +89,26 @@ void merge_switch_to_result(struct merge_options *opt, void merge_display_update_messages(struct merge_options *opt, struct merge_result *result); +struct stage_info { + struct object_id oid; + int mode; + int stage; +}; + +/* + * Provide a list of path -> {struct stage_info*} mappings for + * all conflicted files. Note that each path could appear up to three + * times in the list, corresponding to 3 different stage entries. In short, + * this basically provides the info that would be printed by `ls-files -u`. + * + * result should have been populated by a call to + * one of the merge_incore_[non]recursive() functions. + * + * conflicted_files should be empty before calling this function. + */ +void merge_get_conflicted_files(struct merge_result *result, + struct string_list *conflicted_files); + /* Do needed cleanup when not calling merge_switch_to_result() */ void merge_finalize(struct merge_options *opt, struct merge_result *result); From patchwork Sat Jun 18 00:20:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886166 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93D5CC43334 for ; Sat, 18 Jun 2022 00:21:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383737AbiFRAVi (ORCPT ); Fri, 17 Jun 2022 20:21:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43632 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383705AbiFRAVS (ORCPT ); Fri, 17 Jun 2022 20:21:18 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 520E75A2C2 for ; Fri, 17 Jun 2022 17:21:14 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id q15so3001392wmj.2 for ; Fri, 17 Jun 2022 17:21:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=hiORs4e9DkzNUZHgsiWSwsPhsPUCvMsvR9nowMjv0Z8=; b=R28rqkEwDTi5dJTfN9CozNA25LVl7R0XzbWjNEKkrbLMbNol6IPrUv9xFcbThapdqV 5WbkHQ35XfXynxV1zrT1AclKY2gFbV/Upg9vF6lV0jNlguUFgCm7ie1Wu4368t7cDE8s Oo8Nn0gBISAVIgXdYW9ylYlYL3U3UHYKlfcSz9tOivV2ZRGU5gHljAjDpTYigDLuBDXp d0ssTZ2VAq3h2zX58Nx4fDTsl1piDwGGqB+yBmrJeCf/TtdSqjArnP6ckW2uCoC6DLt+ j6VD9kdd7RppWmyHJB79vxv+LVEpXddePACzlC4TW9ux1Q4ijeEtw4qHX4bCvPLoK85N 1tSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=hiORs4e9DkzNUZHgsiWSwsPhsPUCvMsvR9nowMjv0Z8=; b=GQF88RwUdcc7PobK3ajf0kjIbD6enIeyTDXUvaIkCJHdXj9xHbZMvBxghyfKOayvrG iMVvneC/4Us2eCBFaJEFI70WKn8l2SiHj79sW0eNbbVfSezTvNxAgZzG5ZEzqqrwSu+m rGE64JPTRfZLAvy/lRlFuEJy7fbJ05UukGWqVitgrTS96BIGtzHT9bpYHN8O3HDaEtiX BBnfFSlfu51CnnDZxnF4zo9M6A+vhSOKez9H0YO3YSjFsIRoxdZrPOmPWjH6XfpG7OR9 1AMutQ1EI6UPfBsY3F02yoKY9Y7J5VCU7/Ceh0PQSdGaxCFSYUMKb86Awwua0UabcjkW rSZw== X-Gm-Message-State: AOAM530z8BWedxsPHWPoP1tr2TXmn0GycNr9WZ3X/BwqXjKjRGe65lz9 UaR+35fC7lqA031MyE744Rkj7C1xkS4dFA== X-Google-Smtp-Source: ABdhPJzncmqMLQ5bIXbUR1n0YUdAFOj1AP4OIy8M17kQSDc4nBwKtyBHvsOoYUIQj+Hz4zPRwhIHPA== X-Received: by 2002:a05:600c:1547:b0:39c:7fc6:3082 with SMTP id f7-20020a05600c154700b0039c7fc63082mr23253466wmg.189.1655511672319; Fri, 17 Jun 2022 17:21:12 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id j13-20020a5d452d000000b0021a3d94c7bdsm3837374wra.28.2022.06.17.17.21.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:11 -0700 (PDT) Message-Id: <6419487e26bdaa3fdad357c993f5dd25efe1c70b.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:51 +0000 Subject: [PATCH v7 08/17] merge-ort: remove command-line-centric submodule message from merge-ort Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren There was one case in merge-ort that would call path_msg() multiple times for the same logical conflict, and it was in order to give advice about how to resolve a conflict. This advice does not make as much sense with remerge-diff, or with merge-tree being invoked by a GitHub GUI for resolution of messages, and is making it hard to provide which-logical-conflict-affects-which-paths information in a machine parseable way to a higher level caller of merge-tree. Let's simply remove this informational message. Signed-off-by: Elijah Newren --- merge-ort.c | 9 +-------- t/t6437-submodule-merge.sh | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index 1635d215c0b..7e8b9cd6ea7 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -1693,15 +1693,8 @@ static int merge_submodule(struct merge_options *opt, (struct commit *)merges.objects[0].item); path_msg(opt, path, 0, _("Failed to merge submodule %s, but a possible merge " - "resolution exists:\n%s\n"), + "resolution exists: %s"), path, sb.buf); - path_msg(opt, path, 1, - _("If this is correct simply add it to the index " - "for example\n" - "by using:\n\n" - " git update-index --cacheinfo 160000 %s \"%s\"\n\n" - "which will accept this suggestion.\n"), - oid_to_hex(&merges.objects[0].item->oid), path); strbuf_release(&sb); break; default: diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh index 178413c22f0..c253bf759ab 100755 --- a/t/t6437-submodule-merge.sh +++ b/t/t6437-submodule-merge.sh @@ -133,7 +133,7 @@ test_expect_success 'merging should conflict for non fast-forward' ' (cd merge-search && git checkout -b test-nonforward b && (cd sub && - git rev-parse sub-d > ../expect) && + git rev-parse --short sub-d > ../expect) && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then test_must_fail git merge c >actual From patchwork Sat Jun 18 00:20:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886165 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9FC1CC43334 for ; Sat, 18 Jun 2022 00:21:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383694AbiFRAVi (ORCPT ); Fri, 17 Jun 2022 20:21:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383709AbiFRAVS (ORCPT ); Fri, 17 Jun 2022 20:21:18 -0400 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 915645A2E1 for ; Fri, 17 Jun 2022 17:21:14 -0700 (PDT) Received: by mail-wm1-x330.google.com with SMTP id m125-20020a1ca383000000b0039c63fe5f64so3082305wme.0 for ; Fri, 17 Jun 2022 17:21:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=NklJAMExKowYKfay6MxXIm7zrujP40tvGRFMqbVfzgo=; b=IO5VfoVJpWZkFdpgonAfa0PViBtCA7ZPa2wHFa975/otfxIhBSoXceed9mmxmCgBZR yMjf9VbCcoanTbkpfQKTSAmosht0HrvvjFz2/U9Y7u3YOeYNIQKzW+f7Y1ifcGvA8qpY hV3PJdnOIQk7lrmn0G8mKHb9en2uBF4B1cRqHgsJGXA5zrlY7IGvVjA6Arj7lwiV9rQF 7Vx68P2vq/VmAQiv/ii/RzS+WyQFRK2aAi5CMuoPPHvV6bnCYdewJyKMJsPkryUObwsC afG+6zF+YQJN7LAwAS5fC77KCIIcLs1RbqJirspyRsjLoLWFpCNoWz/J2Fi8AzDGY14V goFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=NklJAMExKowYKfay6MxXIm7zrujP40tvGRFMqbVfzgo=; b=E6ABeO5ghaStxcYCA1UQ4w0zdgashIb9mFa5wRclnNoKiRF4YzVo6EXR3DJxpIduvi mlygafiVjo2YJVj49JUlDggFpsAb3vcICOV6omKs++uGaji/P8obERsWP2WNOVICdLvl P6h3MHG+9gZSrSr8bjGuIO9hS0BovHfjbbtqFYzVsOK99wmAKf8UhSz+/uM7ciOfphZ8 Uq9YfrgcO43NbBc0jO9AoekaUHX0KoFLoUwW15YOk62zobNvDI/uW1ikWbrt3W5ku6uV 4/y5S/T9sGDHpi+5J0GAr2wJzZBa9yjriIUcuCuNkQXCcc0PMGWt6+fut1m2KG1CH/JY U48Q== X-Gm-Message-State: AOAM5311UcKaQAz4Xeu3Tx+jjcPR7T4iAjIGBEv7irvuV9HAgaq1uRUN XhfTcfH5ojiSi8sw5Bxyz4b0VqIoGon1tw== X-Google-Smtp-Source: ABdhPJzd6M1lwPD96jrBukjDjOqMB6pEb5pk01nOkUb25o6QfxDkkq7YMFjgS/a3cO/J3o1ICGRY6Q== X-Received: by 2002:a7b:c757:0:b0:39c:69dd:b42a with SMTP id w23-20020a7bc757000000b0039c69ddb42amr23137350wmk.12.1655511673601; Fri, 17 Jun 2022 17:21:13 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4c48000000b0021b8213fa3bsm2276101wrt.19.2022.06.17.17.21.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:13 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:52 +0000 Subject: [PATCH v7 09/17] merge-tree: provide a list of which files have conflicts Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Callers of `git merge-tree --write-tree` will often want to know which files had conflicts. While they could potentially attempt to parse the CONFLICT notices printed, those messages are not meant to be machine readable. Provide a simpler mechanism of just printing the files (in the same format as `git ls-files` with quoting, but restricted to unmerged files) in the output before the free-form messages. Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 9 +++++++++ builtin/merge-tree.c | 26 +++++++++++++++++++++++--- t/t4301-merge-tree-write-tree.sh | 11 +++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 25b462be14e..68a51c82618 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -58,6 +58,7 @@ line: Whereas for a conflicted merge, the output is by default of the form: + These are discussed individually below. @@ -70,6 +71,14 @@ This is a tree object that represents what would be checked out in the working tree at the end of `git merge`. If there were conflicts, then files within this tree may have embedded conflict markers. +[[CFI]] +Conflicted file list +~~~~~~~~~~~~~~~~~~~~ + +This is a sequence of lines containing a filename on each line, quoted +as explained for the configuration variable `core.quotePath` (see +linkgit:git-config[1]). + [[IM]] Informational messages ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 831d9c77583..13a9536f7c1 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -11,6 +11,9 @@ #include "blob.h" #include "exec-cmd.h" #include "merge-blobs.h" +#include "quote.h" + +static int line_termination = '\n'; struct merge_list { struct merge_list *next; @@ -400,7 +403,8 @@ struct merge_tree_options { }; static int real_merge(struct merge_tree_options *o, - const char *branch1, const char *branch2) + const char *branch1, const char *branch2, + const char *prefix) { struct commit *parent1, *parent2; struct commit_list *merge_bases = NULL; @@ -441,8 +445,24 @@ static int real_merge(struct merge_tree_options *o, o->show_messages = !result.clean; puts(oid_to_hex(&result.tree->object.oid)); + if (!result.clean) { + struct string_list conflicted_files = STRING_LIST_INIT_NODUP; + const char *last = NULL; + int i; + + merge_get_conflicted_files(&result, &conflicted_files); + for (i = 0; i < conflicted_files.nr; i++) { + const char *name = conflicted_files.items[i].string; + if (last && !strcmp(last, name)) + continue; + write_name_quoted_relative( + name, prefix, stdout, line_termination); + last = name; + } + string_list_clear(&conflicted_files, 1); + } if (o->show_messages) { - printf("\n"); + putchar(line_termination); merge_display_update_messages(&opt, &result); } merge_finalize(&opt, &result); @@ -508,7 +528,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) /* Do the relevant type of merge */ if (o.mode == MODE_REAL) - return real_merge(&o, argv[0], argv[1]); + return real_merge(&o, argv[0], argv[1], prefix); else return trivial_merge(argv[0], argv[1], argv[2]); } diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 719d81e7173..8e6dba44288 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -117,6 +117,8 @@ test_expect_success 'test conflict notices and such' ' # "whatever" has *both* a modify/delete and a file/directory conflict cat <<-EOF >expect && HASH + greeting + whatever~side1 Auto-merging greeting CONFLICT (content): Merge conflict in greeting @@ -140,4 +142,13 @@ do ' done +test_expect_success 'Just the conflicted files without the messages' ' + test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out && + anonymize_hash out >actual && + + test_write_lines HASH greeting whatever~side1 >expect && + + test_cmp expect actual +' + test_done From patchwork Sat Jun 18 00:20:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886174 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 53FE2C43334 for ; Sat, 18 Jun 2022 00:21:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383829AbiFRAVz (ORCPT ); Fri, 17 Jun 2022 20:21:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43924 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383656AbiFRAV2 (ORCPT ); Fri, 17 Jun 2022 20:21:28 -0400 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0CFFE5C86C for ; Fri, 17 Jun 2022 17:21:17 -0700 (PDT) Received: by mail-wr1-x430.google.com with SMTP id a15so7532866wrh.2 for ; Fri, 17 Jun 2022 17:21:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=NJvLjppATFP/LedW1KcY658sTKcAI5mB9yKUInFronM=; b=OqPpeArzTLj+WA2kQQhmsiKtyDg8s81YBUTWpQKRLV5ebd7Sryc7NSc9CHelrAsUsk ipKA/Rm4KAAY1wHn0nPCsz9F/dqFMflwwg8ktlPnUZo6XPfrjkMW1Iiq4ZaIfEAF+OzH YpwBupBrxoj+NaYtUK8b1unE67MZ+anGiQbzm8DReom7f+i8s13Q2OMZEQHjsYuotSjP Vs3znc3tW0PTIibhK+3K5yGbVuFSAiONgZ2QUY2IR5NDsMp79ZxgKo609gEGEOh28RQJ zi1YvLI4e8xgucds4ql4fs75hifqLrtj7EQRmSoLIh1rWbN8I/9NAnvQTOmyXOJHJw34 MkHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=NJvLjppATFP/LedW1KcY658sTKcAI5mB9yKUInFronM=; b=AznZH2Vp8qxH2LCv2JGKCzp2S9j5X4d2QgvNaCQE23XJz+9xrX+ij1/tTyUa/MxfSS 2QzWYMyCZAnegE373Sg83/900n8krnAK+w9rEhlp5DCd/5X0PPyp5FZIMCZYcmZaNSzA ednF0DjEtF714VyEJIwlA6rrzkduDyrKAcIOQhY+l2cdOI6GOV4QBGmuJB9QBBfOp1O+ PY7b9JmUW+di/iaywS+y8xOOaE5ZCYVAlpLGuMpPBS06XoiKqLsBK3ESUVj88Npgk+1m 346Aj5rH7qwTNOHVHpiLGy9TcJjVw56xJPfo25uu4SNUMCbPdKCwdTjjKHWlAjTqp/UT d/Pg== X-Gm-Message-State: AJIora85/35QV+MDjeFsBL5h3IwYfqAA/wKHH4HTKj4vqRkYAz2Z3LcD OXwtpqc+1VYilyQQZYfF2m8wE3RSXy8XyA== X-Google-Smtp-Source: AGRyM1vCUHsx97ZGSHpk4cOCj0m/nTMMSzs18E6+W+6r07zUy/lSYeqDK+LHCZX2EtPOCcwbtG2KRQ== X-Received: by 2002:a5d:4310:0:b0:21a:26a5:69b with SMTP id h16-20020a5d4310000000b0021a26a5069bmr11541123wrq.269.1655511675149; Fri, 17 Jun 2022 17:21:15 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v188-20020a1cacc5000000b003973c54bd69sm10462866wme.1.2022.06.17.17.21.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:14 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:53 +0000 Subject: [PATCH v7 10/17] merge-tree: provide easy access to `ls-files -u` style info Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Much like `git merge` updates the index with information of the form (mode, oid, stage, name) provide this output for conflicted files for merge-tree as well. Provide a --name-only option for users to exclude the mode, oid, and stage and only get the list of conflicted filenames. Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 34 ++++++++++++++++++++++++++------ builtin/merge-tree.c | 11 ++++++++++- t/t4301-merge-tree-write-tree.sh | 26 ++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 68a51c82618..b89aabdb98e 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -40,6 +40,13 @@ After the merge completes, a new toplevel tree object is created. See OPTIONS ------- +--name-only:: + In the Conflicted file info section, instead of writing a list + of (mode, oid, stage, path) tuples to output for conflicted + files, just provide a list of filenames with conflicts (and + do not list filenames multiple times if they have multiple + conflicting stages). + --[no-]messages:: Write any informational messages such as "Auto-merging " or CONFLICT notices to the end of stdout. If unspecified, the @@ -58,7 +65,7 @@ line: Whereas for a conflicted merge, the output is by default of the form: - + These are discussed individually below. @@ -72,19 +79,24 @@ working tree at the end of `git merge`. If there were conflicts, then files within this tree may have embedded conflict markers. [[CFI]] -Conflicted file list +Conflicted file info ~~~~~~~~~~~~~~~~~~~~ -This is a sequence of lines containing a filename on each line, quoted -as explained for the configuration variable `core.quotePath` (see -linkgit:git-config[1]). +This is a sequence of lines with the format + + + +The filename will be quoted as explained for the configuration +variable `core.quotePath` (see linkgit:git-config[1]). However, if +the `--name-only` option is passed, the mode, object, and stage will +be omitted. [[IM]] Informational messages ~~~~~~~~~~~~~~~~~~~~~~ This always starts with a blank line to separate it from the previous -section, and then has free-form messages about the merge, such as: +sections, and then has free-form messages about the merge, such as: * "Auto-merging " * "CONFLICT (rename/delete): renamed...but deleted in..." @@ -116,6 +128,16 @@ used as a part of a series of steps such as: Note that when the exit status is non-zero, `NEWTREE` in this sequence will contain a lot more output than just a tree. +For conflicts, the output includes the same information that you'd get +with linkgit:git-merge[1]: + + * what would be written to the working tree (the + <>) + * the higher order stages that would be written to the index (the + <>) + * any messages that would have been printed to stdout (the + <>) + [[DEPMERGE]] DEPRECATED DESCRIPTION ---------------------- diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 13a9536f7c1..c61b5b4a10d 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -400,6 +400,7 @@ enum mode { struct merge_tree_options { int mode; int show_messages; + int name_only; }; static int real_merge(struct merge_tree_options *o, @@ -453,7 +454,11 @@ static int real_merge(struct merge_tree_options *o, merge_get_conflicted_files(&result, &conflicted_files); for (i = 0; i < conflicted_files.nr; i++) { const char *name = conflicted_files.items[i].string; - if (last && !strcmp(last, name)) + struct stage_info *c = conflicted_files.items[i].util; + if (!o->name_only) + printf("%06o %s %d\t", + c->mode, oid_to_hex(&c->oid), c->stage); + else if (last && !strcmp(last, name)) continue; write_name_quoted_relative( name, prefix, stdout, line_termination); @@ -488,6 +493,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) N_("do a trivial merge only"), MODE_TRIVIAL), OPT_BOOL(0, "messages", &o.show_messages, N_("also show informational/conflict messages")), + OPT_BOOL_F(0, "name-only", + &o.name_only, + N_("list filenames without modes/oids/stages"), + PARSE_OPT_NONEG), OPT_END() }; diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 8e6dba44288..0ec5f0d3f7e 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -65,6 +65,7 @@ test_expect_success 'Content merge and a few conflicts' ' expected_tree=$(git rev-parse AUTO_MERGE) && # We will redo the merge, while we are still in a conflicted state! + git ls-files -u >conflicted-file-info && test_when_finished "git reset --hard" && test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT && @@ -108,7 +109,7 @@ anonymize_hash() { } test_expect_success 'test conflict notices and such' ' - test_expect_code 1 git merge-tree --write-tree side1 side2 >out && + test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out && anonymize_hash out >actual && # Expected results: @@ -143,7 +144,7 @@ do done test_expect_success 'Just the conflicted files without the messages' ' - test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out && + test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out && anonymize_hash out >actual && test_write_lines HASH greeting whatever~side1 >expect && @@ -151,4 +152,25 @@ test_expect_success 'Just the conflicted files without the messages' ' test_cmp expect actual ' +test_expect_success 'Check conflicted oids and modes without messages' ' + test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out && + anonymize_hash out >actual && + + # Compare the basic output format + q_to_tab >expect <<-\EOF && + HASH + 100644 HASH 1Qgreeting + 100644 HASH 2Qgreeting + 100644 HASH 3Qgreeting + 100644 HASH 1Qwhatever~side1 + 100644 HASH 2Qwhatever~side1 + EOF + + test_cmp expect actual && + + # Check the actual hashes against the `ls-files -u` output too + tail -n +2 out | sed -e s/side1/HEAD/ >actual && + test_cmp conflicted-file-info actual +' + test_done From patchwork Sat Jun 18 00:20:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Schindelin X-Patchwork-Id: 12886173 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 58DD1C433EF for ; Sat, 18 Jun 2022 00:21:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383784AbiFRAVv (ORCPT ); Fri, 17 Jun 2022 20:21:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383734AbiFRAV2 (ORCPT ); Fri, 17 Jun 2022 20:21:28 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5290459974 for ; Fri, 17 Jun 2022 17:21:18 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id c130-20020a1c3588000000b0039c6fd897b4so5051255wma.4 for ; Fri, 17 Jun 2022 17:21:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=NjCsXM44Os9LwG0J5rgBxCUbk4ZjcUC52aWZ+4EwgJE=; b=MoqSrJoEGXKqTEV8mrWOuC4o63OAyxBZ0sZgGPCo9Lw55p7mVe3HMTAd9YHUQ1kyJf leJn6uf7LiH7rVzf1uNioNyWYP+NTYXXfg454Qg+LJ2vew3LigvbzvqfVr4O3QwfCcu7 vgVaJ1aIimSl5MPsjVAvl3utk9WPXtUV922DnTgGJvL/JxyPoFeXgjJMZZpQF5sQCdaH l4GfHpUuv57TiuCcB4Q5eAnwe2QYUr5Aqw4JEu98wRI+YZLKwNsNzWXYk/ZVobGg4rnu HiuxTBmqzrpOzQuT91FmnfJVZFVz+D6KAgF3cylg3Rw5kI/Z6KAStH8P6nElkYZX6qzz lqGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=NjCsXM44Os9LwG0J5rgBxCUbk4ZjcUC52aWZ+4EwgJE=; b=CsXd7ZCrdXpxtYZs4CVr+WUOo8BfsdWPtNDWQ3PjKyUgam8UCMp+W3ZtVUl1+KUUO2 TugXG0IoxOZJdOGkOc8wVHX6sM7psuRGSmA+MFOCkGWuRGkgQk21QA1sh4fIz9fS0aTu 9M1yT2vcSjIJhuF3tip4d3z2ABUnqVWsydKm/0dfA9OKLEqSZ0faDkt30/CdNyuF6zTh L2xFrZHbQmX+FNpDnF221zYvHChOblbKJIpxbSU2meIcUdsHNVXbRD8UdHC9jzOX4jdf MY7yWRBvQosmOab6iF16N/pcB2yVTq7mEIRniUzL/YSZF5CDsXthsvYYTjzbbr+zKDap O0ZQ== X-Gm-Message-State: AJIora9OxLjNTVrGgA1pA4s2s1Lh2mzCU4RcAFR/y53snVBe+VyneCz4 zBpVhLiYDIlxJ548vyJ0olvrK7i1ta/REA== X-Google-Smtp-Source: AGRyM1sCdf80W88s5faAN0X1tyCcLeT1Xd2N+w+vMvSgiQT++kPpcJO+LPmWcsbFH7/u/Br0RtJbug== X-Received: by 2002:a7b:ce08:0:b0:39c:8f58:2414 with SMTP id m8-20020a7bce08000000b0039c8f582414mr12531552wmc.74.1655511676247; Fri, 17 Jun 2022 17:21:16 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id x1-20020adff0c1000000b002103cfd2fbasm6066441wro.65.2022.06.17.17.21.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:15 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:54 +0000 Subject: [PATCH v7 11/17] merge-ort: store messages in a list, not in a single strbuf Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Johannes Schindelin Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin From: Johannes Schindelin To prepare for using the `merge-ort` machinery in server operations, we cannot simply produce a free-form string that combines a variable-length list of messages. Instead, we need to list them one by one. The natural fit for this is a `string_list`. We will subsequently add even more information in the `util` attribute of the string list items. Based-on-a-patch-by: Elijah Newren Signed-off-by: Johannes Schindelin Signed-off-by: Elijah Newren --- merge-ort.c | 123 ++++++++++++++++++++++++++++++++++------------------ merge-ort.h | 2 +- 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index 7e8b9cd6ea7..668aec64f13 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -349,13 +349,15 @@ struct merge_options_internal { struct mem_pool pool; /* - * output: special messages and conflict notices for various paths + * conflicts: logical conflicts and messages stored by _primary_ path * * This is a map of pathnames (a subset of the keys in "paths" above) - * to strbufs. It gathers various warning/conflict/notice messages - * for later processing. + * to struct string_list, with each item's `util` containing a + * `struct logical_conflict_info`. Note, though, that for each path, + * it only stores the logical conflicts for which that path is the + * primary path; the path might be part of additional conflicts. */ - struct strmap output; + struct strmap conflicts; /* * renames: various data relating to rename detection @@ -567,20 +569,20 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti, struct strmap_entry *e; /* Release and free each strbuf found in output */ - strmap_for_each_entry(&opti->output, &iter, e) { - struct strbuf *sb = e->value; - strbuf_release(sb); + strmap_for_each_entry(&opti->conflicts, &iter, e) { + struct string_list *list = e->value; /* - * While strictly speaking we don't need to free(sb) - * here because we could pass free_values=1 when - * calling strmap_clear() on opti->output, that would - * require strmap_clear to do another - * strmap_for_each_entry() loop, so we just free it - * while we're iterating anyway. + * While strictly speaking we don't need to + * free(conflicts) here because we could pass + * free_values=1 when calling strmap_clear() on + * opti->conflicts, that would require strmap_clear + * to do another strmap_for_each_entry() loop, so we + * just free it while we're iterating anyway. */ - free(sb); + string_list_clear(list, 1); + free(list); } - strmap_clear(&opti->output, 0); + strmap_clear(&opti->conflicts, 0); } mem_pool_discard(&opti->pool, 0); @@ -634,7 +636,9 @@ static void path_msg(struct merge_options *opt, const char *fmt, ...) { va_list ap; - struct strbuf *sb, *dest; + struct string_list *path_conflicts; + struct strbuf buf = STRBUF_INIT; + struct strbuf *dest; struct strbuf tmp = STRBUF_INIT; if (opt->record_conflict_msgs_as_headers && omittable_hint) @@ -642,14 +646,16 @@ static void path_msg(struct merge_options *opt, if (opt->priv->call_depth && opt->verbosity < 5) return; /* Ignore messages from inner merges */ - sb = strmap_get(&opt->priv->output, path); - if (!sb) { - sb = xmalloc(sizeof(*sb)); - strbuf_init(sb, 0); - strmap_put(&opt->priv->output, path, sb); + /* Ensure path_conflicts (ptr to array of logical_conflict) allocated */ + path_conflicts = strmap_get(&opt->priv->conflicts, path); + if (!path_conflicts) { + path_conflicts = xmalloc(sizeof(*path_conflicts)); + string_list_init_dup(path_conflicts); + strmap_put(&opt->priv->conflicts, path, path_conflicts); } - dest = (opt->record_conflict_msgs_as_headers ? &tmp : sb); + /* Handle message and its format, in normal case */ + dest = (opt->record_conflict_msgs_as_headers ? &tmp : &buf); va_start(ap, fmt); if (opt->priv->call_depth) { @@ -660,32 +666,31 @@ static void path_msg(struct merge_options *opt, strbuf_vaddf(dest, fmt, ap); va_end(ap); + /* Handle specialized formatting of message under --remerge-diff */ if (opt->record_conflict_msgs_as_headers) { int i_sb = 0, i_tmp = 0; /* Start with the specified prefix */ if (opt->msg_header_prefix) - strbuf_addf(sb, "%s ", opt->msg_header_prefix); + strbuf_addf(&buf, "%s ", opt->msg_header_prefix); /* Copy tmp to sb, adding spaces after newlines */ - strbuf_grow(sb, sb->len + 2*tmp.len); /* more than sufficient */ + strbuf_grow(&buf, buf.len + 2*tmp.len); /* more than sufficient */ for (; i_tmp < tmp.len; i_tmp++, i_sb++) { /* Copy next character from tmp to sb */ - sb->buf[sb->len + i_sb] = tmp.buf[i_tmp]; + buf.buf[buf.len + i_sb] = tmp.buf[i_tmp]; /* If we copied a newline, add a space */ if (tmp.buf[i_tmp] == '\n') - sb->buf[++i_sb] = ' '; + buf.buf[++i_sb] = ' '; } /* Update length and ensure it's NUL-terminated */ - sb->len += i_sb; - sb->buf[sb->len] = '\0'; + buf.len += i_sb; + buf.buf[buf.len] = '\0'; strbuf_release(&tmp); } - - /* Add final newline character to sb */ - strbuf_addch(sb, '\n'); + string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL)); } static struct diff_filespec *pool_alloc_filespec(struct mem_pool *pool, @@ -4256,7 +4261,6 @@ void merge_display_update_messages(struct merge_options *opt, struct hashmap_iter iter; struct strmap_entry *e; struct string_list olist = STRING_LIST_INIT_NODUP; - int i; if (opt->record_conflict_msgs_as_headers) BUG("Either display conflict messages or record them as headers, not both"); @@ -4264,20 +4268,20 @@ void merge_display_update_messages(struct merge_options *opt, trace2_region_enter("merge", "display messages", opt->repo); /* Hack to pre-allocate olist to the desired size */ - ALLOC_GROW(olist.items, strmap_get_size(&opti->output), + ALLOC_GROW(olist.items, strmap_get_size(&opti->conflicts), olist.alloc); /* Put every entry from output into olist, then sort */ - strmap_for_each_entry(&opti->output, &iter, e) { + strmap_for_each_entry(&opti->conflicts, &iter, e) { string_list_append(&olist, e->key)->util = e->value; } string_list_sort(&olist); /* Iterate over the items, printing them */ - for (i = 0; i < olist.nr; ++i) { - struct strbuf *sb = olist.items[i].util; - - printf("%s", sb->buf); + for (int path_nr = 0; path_nr < olist.nr; ++path_nr) { + struct string_list *conflicts = olist.items[path_nr].util; + for (int i = 0; i < conflicts->nr; i++) + puts(conflicts->items[i].string); } string_list_clear(&olist, 0); @@ -4366,6 +4370,8 @@ void merge_finalize(struct merge_options *opt, struct merge_result *result) { struct merge_options_internal *opti = result->priv; + struct hashmap_iter iter; + struct strmap_entry *e; if (opt->renormalize) git_attr_set_direction(GIT_ATTR_CHECKIN); @@ -4373,6 +4379,15 @@ void merge_finalize(struct merge_options *opt, clear_or_reinit_internal_opts(opti, 0); FREE_AND_NULL(opti); + + /* Release and free each strbuf found in path_messages */ + strmap_for_each_entry(result->path_messages, &iter, e) { + struct strbuf *buf = e->value; + + strbuf_release(buf); + } + strmap_clear(result->path_messages, 1); + FREE_AND_NULL(result->path_messages); } /*** Function Grouping: helper functions for merge_incore_*() ***/ @@ -4531,11 +4546,11 @@ static void merge_start(struct merge_options *opt, struct merge_result *result) strmap_init_with_options(&opt->priv->conflicted, pool, 0); /* - * keys & strbufs in output will sometimes need to outlive "paths", - * so it will have a copy of relevant keys. It's probably a small - * subset of the overall paths that have special output. + * keys & string_lists in conflicts will sometimes need to outlive + * "paths", so it will have a copy of relevant keys. It's probably + * a small subset of the overall paths that have special output. */ - strmap_init(&opt->priv->output); + strmap_init(&opt->priv->conflicts); trace2_region_leave("merge", "allocate/init", opt->repo); } @@ -4596,6 +4611,8 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt, struct merge_result *result) { struct object_id working_tree_oid; + struct hashmap_iter iter; + struct strmap_entry *e; if (opt->subtree_shift) { side2 = shift_tree_object(opt->repo, side1, side2, @@ -4636,7 +4653,27 @@ redo: trace2_region_leave("merge", "process_entries", opt->repo); /* Set return values */ - result->path_messages = &opt->priv->output; + result->path_messages = xcalloc(1, sizeof(*result->path_messages)); + strmap_init_with_options(result->path_messages, NULL, 0); + strmap_for_each_entry(&opt->priv->conflicts, &iter, e) { + const char *path = e->key; + struct strbuf *buf = strmap_get(result->path_messages, path); + struct string_list *conflicts = e->value; + + if (!buf) { + buf = xcalloc(1, sizeof(*buf)); + strbuf_init(buf, 0); + strmap_put(result->path_messages, path, buf); + } + + for (int i = 0; i < conflicts->nr; i++) { + if (buf->len) + strbuf_addch(buf, '\n'); + strbuf_addstr(buf, conflicts->items[i].string); + strbuf_trim_trailing_newline(buf); + } + } + result->tree = parse_tree_indirect(&working_tree_oid); /* existence of conflicted entries implies unclean */ result->clean &= strmap_empty(&opt->priv->conflicted); diff --git a/merge-ort.h b/merge-ort.h index ddcc39d7270..f9c536ed8c4 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -28,7 +28,7 @@ struct merge_result { /* * Special messages and conflict notices for various paths * - * This is a map of pathnames to strbufs. It contains various + * This is a map of pathnames to strbufs. It contains various * warning/conflict/notice messages (possibly multiple per path) * that callers may want to use. */ From patchwork Sat Jun 18 00:20:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Schindelin X-Patchwork-Id: 12886167 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A22E8C433EF for ; Sat, 18 Jun 2022 00:21:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383765AbiFRAVm (ORCPT ); Fri, 17 Jun 2022 20:21:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383739AbiFRAV3 (ORCPT ); Fri, 17 Jun 2022 20:21:29 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7356E663C9 for ; Fri, 17 Jun 2022 17:21:19 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id q9so7510433wrd.8 for ; Fri, 17 Jun 2022 17:21:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=x8732zrRviVYi7oflkB1AFK8oc6/ARNmZOK3eguro0U=; b=I6V/kQ+ehLP8ozpkftZIyBRmiHgkY6c9IkOHvxlFcc+cOgSy0XIMBye67ltoXex/+H tuKV0XU9efmZB0t1NXd9XhfkytJ41ytaUJvWaXzZjbqPuNmER9FhnqrZjIdhzDOyQbcb 9NGZGioF+JXLtHcmWJRkyc2QsfHX0RtQriAMzgyCZ6vtF+WGhjgDgPwx5deyeOVo8NsD +mANNQV1UvbiZiV1CZSuvgwwWHoiKdX/YE3FYQEClRbeZ464tKaIf7HMu379PDdovkkt +sBZ8Gb6LPwEYybFhNG970sJAHCRrHtZ+14D+67dDIep3g43SJE4Iret8wYg1O87b2uf d7pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=x8732zrRviVYi7oflkB1AFK8oc6/ARNmZOK3eguro0U=; b=GHwCXB3d05j9cj1B7TXtkn5ZLP3GQrnITn2UANPcARa96Puipm9LagysFgG9hdZwm8 yEFV0Prkq+Mf7wDNEoZ6tYZnkZ3jtu23B2UsSqoHOX8aHItORzmvZhVZF5K2V3DkRY60 QE3u2weHaF4q6wW9lPo3zz34UgFg0KiW7+Jiz5jYGh9Hn+M0iBaj/fNcxeHvNMcV11wN FTxiYsnVYtzJk4bxVTOwZSpQHOhKC6N4GEqnEaA44al1j6Yu6a7v5jR0KoM54EzUIVIc BMpdfr3I1iL8dJOeTUuvO8Me13wZBqgQdmnhePJ1IKbLUKnpZUpiJRDHaKyoSn9tWWeP yMdA== X-Gm-Message-State: AJIora+2L2whViaJWwkppCcynPyCJlTrYvBkl0UikZmjGPkeFTNfHTI/ Xz01OONJXUhobB9mA0OaHfc7nS0GDWWdYA== X-Google-Smtp-Source: AGRyM1vo+rEdwq0BfV1FV5ifpMwUtJ0lxXucYpbgqxsCQUGzSxiisTj94h1iuIDujtYB9jCDwYTm0A== X-Received: by 2002:adf:db91:0:b0:21a:2731:fca8 with SMTP id u17-20020adfdb91000000b0021a2731fca8mr11291640wri.520.1655511677524; Fri, 17 Jun 2022 17:21:17 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id c5-20020a05600c0a4500b0039c4ba160absm20391697wmq.2.2022.06.17.17.21.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:16 -0700 (PDT) Message-Id: <6b47c0fdbd7764275325ae75d534c506da4fe4d5.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:55 +0000 Subject: [PATCH v7 12/17] merge-ort: make `path_messages` a strmap to a string_list Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Johannes Schindelin Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Johannes Schindelin From: Johannes Schindelin This allows us once again to get away with less data copying. Signed-off-by: Johannes Schindelin Signed-off-by: Elijah Newren --- diff.c | 27 ++++++++++++++++++++------- merge-ort.c | 34 +--------------------------------- merge-ort.h | 2 +- 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/diff.c b/diff.c index e71cf758861..2214ae49e4b 100644 --- a/diff.c +++ b/diff.c @@ -3362,23 +3362,23 @@ struct userdiff_driver *get_textconv(struct repository *r, return userdiff_get_textconv(r, one->driver); } -static struct strbuf *additional_headers(struct diff_options *o, - const char *path) +static struct string_list *additional_headers(struct diff_options *o, + const char *path) { if (!o->additional_path_headers) return NULL; return strmap_get(o->additional_path_headers, path); } -static void add_formatted_headers(struct strbuf *msg, - struct strbuf *more_headers, +static void add_formatted_header(struct strbuf *msg, + const char *header, const char *line_prefix, const char *meta, const char *reset) { - char *next, *newline; + const char *next, *newline; - for (next = more_headers->buf; *next; next = newline) { + for (next = header; *next; next = newline) { newline = strchrnul(next, '\n'); strbuf_addf(msg, "%s%s%.*s%s\n", line_prefix, meta, (int)(newline - next), next, reset); @@ -3387,6 +3387,19 @@ static void add_formatted_headers(struct strbuf *msg, } } +static void add_formatted_headers(struct strbuf *msg, + struct string_list *more_headers, + const char *line_prefix, + const char *meta, + const char *reset) +{ + int i; + + for (i = 0; i < more_headers->nr; i++) + add_formatted_header(msg, more_headers->items[i].string, + line_prefix, meta, reset); +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -4314,7 +4327,7 @@ static void fill_metainfo(struct strbuf *msg, const char *set = diff_get_color(use_color, DIFF_METAINFO); const char *reset = diff_get_color(use_color, DIFF_RESET); const char *line_prefix = diff_line_prefix(o); - struct strbuf *more_headers = NULL; + struct string_list *more_headers = NULL; *must_show_header = 1; strbuf_init(msg, PATH_MAX * 2 + 300); diff --git a/merge-ort.c b/merge-ort.c index 668aec64f13..dfec08c88be 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4370,8 +4370,6 @@ void merge_finalize(struct merge_options *opt, struct merge_result *result) { struct merge_options_internal *opti = result->priv; - struct hashmap_iter iter; - struct strmap_entry *e; if (opt->renormalize) git_attr_set_direction(GIT_ATTR_CHECKIN); @@ -4379,15 +4377,6 @@ void merge_finalize(struct merge_options *opt, clear_or_reinit_internal_opts(opti, 0); FREE_AND_NULL(opti); - - /* Release and free each strbuf found in path_messages */ - strmap_for_each_entry(result->path_messages, &iter, e) { - struct strbuf *buf = e->value; - - strbuf_release(buf); - } - strmap_clear(result->path_messages, 1); - FREE_AND_NULL(result->path_messages); } /*** Function Grouping: helper functions for merge_incore_*() ***/ @@ -4611,8 +4600,6 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt, struct merge_result *result) { struct object_id working_tree_oid; - struct hashmap_iter iter; - struct strmap_entry *e; if (opt->subtree_shift) { side2 = shift_tree_object(opt->repo, side1, side2, @@ -4653,26 +4640,7 @@ redo: trace2_region_leave("merge", "process_entries", opt->repo); /* Set return values */ - result->path_messages = xcalloc(1, sizeof(*result->path_messages)); - strmap_init_with_options(result->path_messages, NULL, 0); - strmap_for_each_entry(&opt->priv->conflicts, &iter, e) { - const char *path = e->key; - struct strbuf *buf = strmap_get(result->path_messages, path); - struct string_list *conflicts = e->value; - - if (!buf) { - buf = xcalloc(1, sizeof(*buf)); - strbuf_init(buf, 0); - strmap_put(result->path_messages, path, buf); - } - - for (int i = 0; i < conflicts->nr; i++) { - if (buf->len) - strbuf_addch(buf, '\n'); - strbuf_addstr(buf, conflicts->items[i].string); - strbuf_trim_trailing_newline(buf); - } - } + result->path_messages = &opt->priv->conflicts; result->tree = parse_tree_indirect(&working_tree_oid); /* existence of conflicted entries implies unclean */ diff --git a/merge-ort.h b/merge-ort.h index f9c536ed8c4..c4909bcbf96 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -28,7 +28,7 @@ struct merge_result { /* * Special messages and conflict notices for various paths * - * This is a map of pathnames to strbufs. It contains various + * This is a map of pathnames to a string_list. It contains various * warning/conflict/notice messages (possibly multiple per path) * that callers may want to use. */ From patchwork Sat Jun 18 00:20:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886172 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 428C3C433EF for ; Sat, 18 Jun 2022 00:21:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383818AbiFRAVu (ORCPT ); Fri, 17 Jun 2022 20:21:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383745AbiFRAV3 (ORCPT ); Fri, 17 Jun 2022 20:21:29 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8AD966F9C for ; Fri, 17 Jun 2022 17:21:19 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id s1so7511966wra.9 for ; Fri, 17 Jun 2022 17:21:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=zJfRyoBvuWNcOv1lkfUlG+kXrpIMd7GAkbs1CMlB9DM=; b=lpxmfKIiECHhJSePorKAxZRvsUU6+UvhrXUru69NPS+tLOL01XX9E9sCZBYrvtcyqZ F5M1jFDyNbgDQvpNS9A9QhB7Ns2Bir/MDzfO01zK8piFWu7qp448KcxHQu7K49jinqkD UNTd46ehBlPhl8N3anDsiB0/oTzV4/o62zrapvSW1qGI7b29jy4gnKghPYVLTx/CXwaE kWWZZgK9oiATp3xzK7Dctz5Twv1ZKyTOqwTeiSer3tpm+tmq1UG0x3XB6XA0xTSzJs4j z3ZcC9UEgFVsN8txAeHE9ninY0rWt50LGRZp3kLch1Xy6Doe2FfUs07adq182B5d32X7 vfpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=zJfRyoBvuWNcOv1lkfUlG+kXrpIMd7GAkbs1CMlB9DM=; b=cDw7Xq9wRTPUtixqBDHOWC6octwY0fxo/bPN243B/T+vxIIBL797QRJgyzk7oOWyno CtURYG+ByioJC8/vSVq5il5bXfb4LAkVVixFHM5fIGWR51JUe1LlsN8GcXVtun/8T0u4 LxlB1Xc8lQYIs0Y2zhw3r1365I1n7Vm8L8ZyvkLcY8PUbValG54Io0lgdmruLTJtfEHj 7l6tXSTCqndN1/OLngjHcufn2PKKrqtlF0lHNc5HjbI89L7sEGkdMt3TeyQJldnBorTc 8XT1kEjKnEvqvvzwg/6PNghpbceKoJ3Tw6WVckJt7ClE2papNP7P6gocigsvME4qc8ga 6glQ== X-Gm-Message-State: AJIora/Hsjy0780RV0LRuIkrojgilJX7KCtFcy0U8RmVs3ZxiMfQrdNG NExCPDsXPU6LBWmIan+GQ3S/cS7xTAtL+A== X-Google-Smtp-Source: AGRyM1s9gXGpyUaZ7QokNfZczn15+FbyqwYYi8LUMvZbpEU9K3VpfyZTtqHzrKCuQDDymLIlgYCD3w== X-Received: by 2002:adf:d1ca:0:b0:218:47e1:ab0b with SMTP id b10-20020adfd1ca000000b0021847e1ab0bmr11659486wrd.90.1655511678736; Fri, 17 Jun 2022 17:21:18 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id d5-20020a5d4f85000000b0021b862ad439sm432639wru.9.2022.06.17.17.21.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:18 -0700 (PDT) Message-Id: <7eb70f77c81bd506c6d6be680961677407bf68df.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:56 +0000 Subject: [PATCH v7 13/17] merge-ort: store more specific conflict information Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren It is all fine and dandy for a regular Git command that is intended to be run interactively to produce a bunch of messages upon an error. However, in `merge-ort`'s case, we want to call the command e.g. in server-side software, where the actual error messages are not quite as interesting as machine-readable, immutable terms that describe the exact nature of any given conflict. With this patch, the `merge-ort` machinery records the exact type (as specified via an `enum` value) as well as the involved path(s) together with the conflict's message. Signed-off-by: Elijah Newren Signed-off-by: Johannes Schindelin --- merge-ort.c | 267 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 212 insertions(+), 55 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index dfec08c88be..432937255f6 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -483,6 +483,100 @@ struct conflict_info { unsigned match_mask:3; }; +enum conflict_and_info_types { + /* "Simple" conflicts and informational messages */ + INFO_AUTO_MERGING = 0, + CONFLICT_CONTENTS, /* text file that failed to merge */ + CONFLICT_BINARY, + CONFLICT_FILE_DIRECTORY, + CONFLICT_DISTINCT_MODES, + CONFLICT_MODIFY_DELETE, + CONFLICT_PRESENT_DESPITE_SKIPPED, + + /* Regular rename */ + CONFLICT_RENAME_RENAME, /* same file renamed differently */ + CONFLICT_RENAME_COLLIDES, /* rename/add or two files renamed to 1 */ + CONFLICT_RENAME_DELETE, + + /* Basic directory rename */ + CONFLICT_DIR_RENAME_SUGGESTED, + INFO_DIR_RENAME_APPLIED, + + /* Special directory rename cases */ + INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, + CONFLICT_DIR_RENAME_FILE_IN_WAY, + CONFLICT_DIR_RENAME_COLLISION, + CONFLICT_DIR_RENAME_SPLIT, + + /* Basic submodule */ + INFO_SUBMODULE_FAST_FORWARDING, + CONFLICT_SUBMODULE_FAILED_TO_MERGE, + + /* Special submodule cases broken out from FAILED_TO_MERGE */ + CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, + CONFLICT_SUBMODULE_NOT_INITIALIZED, + CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE, + CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, + + /* Keep this entry _last_ in the list */ + NB_CONFLICT_TYPES, +}; + +/* + * Short description of conflict type, relied upon by external tools. + * + * We can add more entries, but DO NOT change any of these strings. Also, + * Order MUST match conflict_info_and_types. + */ +static const char *type_short_descriptions[] = { + /*** "Simple" conflicts and informational messages ***/ + [INFO_AUTO_MERGING] = "Auto-merging", + [CONFLICT_CONTENTS] = "CONFLICT (contents)", + [CONFLICT_BINARY] = "CONFLICT (binary)", + [CONFLICT_FILE_DIRECTORY] = "CONFLICT (file/directory)", + [CONFLICT_DISTINCT_MODES] = "CONFLICT (distinct modes)", + [CONFLICT_MODIFY_DELETE] = "CONFLICT (modify/delete)", + [CONFLICT_PRESENT_DESPITE_SKIPPED] = + "CONFLICT (upgrade your version of git)", + + /*** Regular rename ***/ + [CONFLICT_RENAME_RENAME] = "CONFLICT (rename/rename)", + [CONFLICT_RENAME_COLLIDES] = "CONFLICT (rename involved in collision)", + [CONFLICT_RENAME_DELETE] = "CONFLICT (rename/delete)", + + /*** Basic directory rename ***/ + [CONFLICT_DIR_RENAME_SUGGESTED] = + "CONFLICT (directory rename suggested)", + [INFO_DIR_RENAME_APPLIED] = "Path updated due to directory rename", + + /*** Special directory rename cases ***/ + [INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME] = + "Directory rename skipped since directory was renamed on both sides", + [CONFLICT_DIR_RENAME_FILE_IN_WAY] = + "CONFLICT (file in way of directory rename)", + [CONFLICT_DIR_RENAME_COLLISION] = "CONFLICT(directory rename collision)", + [CONFLICT_DIR_RENAME_SPLIT] = "CONFLICT(directory rename unclear split)", + + /*** Basic submodule ***/ + [INFO_SUBMODULE_FAST_FORWARDING] = "Fast forwarding submodule", + [CONFLICT_SUBMODULE_FAILED_TO_MERGE] = "CONFLICT (submodule)", + + /*** Special submodule cases broken out from FAILED_TO_MERGE ***/ + [CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION] = + "CONFLICT (submodule with possible resolution)", + [CONFLICT_SUBMODULE_NOT_INITIALIZED] = + "CONFLICT (submodule not initialized)", + [CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE] = + "CONFLICT (submodule history not available)", + [CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] = + "CONFLICT (submodule may have rewinds)", +}; + +struct logical_conflict_info { + enum conflict_and_info_types type; + struct strvec paths; +}; + /*** Function Grouping: various utility functions ***/ /* @@ -571,6 +665,11 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti, /* Release and free each strbuf found in output */ strmap_for_each_entry(&opti->conflicts, &iter, e) { struct string_list *list = e->value; + for (int i = 0; i < list->nr; i++) { + struct logical_conflict_info *info = + list->items[i].util; + strvec_clear(&info->paths); + } /* * While strictly speaking we don't need to * free(conflicts) here because we could pass @@ -629,31 +728,56 @@ static void format_commit(struct strbuf *sb, strbuf_addch(sb, '\n'); } -__attribute__((format (printf, 4, 5))) +__attribute__((format (printf, 8, 9))) static void path_msg(struct merge_options *opt, - const char *path, + enum conflict_and_info_types type, int omittable_hint, /* skippable under --remerge-diff */ + const char *primary_path, + const char *other_path_1, /* may be NULL */ + const char *other_path_2, /* may be NULL */ + struct string_list *other_paths, /* may be NULL */ const char *fmt, ...) { va_list ap; struct string_list *path_conflicts; + struct logical_conflict_info *info; struct strbuf buf = STRBUF_INIT; struct strbuf *dest; struct strbuf tmp = STRBUF_INIT; + /* Sanity checks */ + assert(omittable_hint == + !starts_with(type_short_descriptions[type], "CONFLICT") || + type == CONFLICT_DIR_RENAME_SUGGESTED || + type == CONFLICT_PRESENT_DESPITE_SKIPPED); if (opt->record_conflict_msgs_as_headers && omittable_hint) return; /* Do not record mere hints in headers */ if (opt->priv->call_depth && opt->verbosity < 5) return; /* Ignore messages from inner merges */ /* Ensure path_conflicts (ptr to array of logical_conflict) allocated */ - path_conflicts = strmap_get(&opt->priv->conflicts, path); + path_conflicts = strmap_get(&opt->priv->conflicts, primary_path); if (!path_conflicts) { path_conflicts = xmalloc(sizeof(*path_conflicts)); string_list_init_dup(path_conflicts); - strmap_put(&opt->priv->conflicts, path, path_conflicts); + strmap_put(&opt->priv->conflicts, primary_path, path_conflicts); } + /* Add a logical_conflict at the end to store info from this call */ + info = xcalloc(1, sizeof(*info)); + info->type = type; + strvec_init(&info->paths); + + /* Handle the list of paths */ + strvec_push(&info->paths, primary_path); + if (other_path_1) + strvec_push(&info->paths, other_path_1); + if (other_path_2) + strvec_push(&info->paths, other_path_2); + if (other_paths) + for (int i = 0; i < other_paths->nr; i++) + strvec_push(&info->paths, other_paths->items[i].string); + /* Handle message and its format, in normal case */ dest = (opt->record_conflict_msgs_as_headers ? &tmp : &buf); @@ -690,7 +814,8 @@ static void path_msg(struct merge_options *opt, strbuf_release(&tmp); } - string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL)); + string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL)) + ->util = info; } static struct diff_filespec *pool_alloc_filespec(struct mem_pool *pool, @@ -1631,16 +1756,18 @@ static int merge_submodule(struct merge_options *opt, return 0; if (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) { - path_msg(opt, path, 0, - _("Failed to merge submodule %s (not checked out)"), - path); + path_msg(opt, CONFLICT_SUBMODULE_NOT_INITIALIZED, 0, + path, NULL, NULL, NULL, + _("Failed to merge submodule %s (not checked out)"), + path); return 0; } if (!(commit_o = lookup_commit_reference(&subrepo, o)) || !(commit_a = lookup_commit_reference(&subrepo, a)) || !(commit_b = lookup_commit_reference(&subrepo, b))) { - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE, 0, + path, NULL, NULL, NULL, _("Failed to merge submodule %s (commits not present)"), path); goto cleanup; @@ -1649,7 +1776,8 @@ static int merge_submodule(struct merge_options *opt, /* check whether both changes are forward */ if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) || !repo_in_merge_bases(&subrepo, commit_o, commit_b)) { - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0, + path, NULL, NULL, NULL, _("Failed to merge submodule %s " "(commits don't follow merge-base)"), path); @@ -1659,7 +1787,8 @@ static int merge_submodule(struct merge_options *opt, /* Case #1: a is contained in b or vice versa */ if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) { oidcpy(result, b); - path_msg(opt, path, 1, + path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1, + path, NULL, NULL, NULL, _("Note: Fast-forwarding submodule %s to %s"), path, oid_to_hex(b)); ret = 1; @@ -1667,7 +1796,8 @@ static int merge_submodule(struct merge_options *opt, } if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) { oidcpy(result, a); - path_msg(opt, path, 1, + path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1, + path, NULL, NULL, NULL, _("Note: Fast-forwarding submodule %s to %s"), path, oid_to_hex(a)); ret = 1; @@ -1690,13 +1820,16 @@ static int merge_submodule(struct merge_options *opt, &merges); switch (parent_count) { case 0: - path_msg(opt, path, 0, _("Failed to merge submodule %s"), path); + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0, + path, NULL, NULL, NULL, + _("Failed to merge submodule %s"), path); break; case 1: format_commit(&sb, 4, &subrepo, (struct commit *)merges.objects[0].item); - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0, + path, NULL, NULL, NULL, _("Failed to merge submodule %s, but a possible merge " "resolution exists: %s"), path, sb.buf); @@ -1706,7 +1839,8 @@ static int merge_submodule(struct merge_options *opt, for (i = 0; i < merges.nr; i++) format_commit(&sb, 4, &subrepo, (struct commit *)merges.objects[i].item); - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0, + path, NULL, NULL, NULL, _("Failed to merge submodule %s, but multiple " "possible merges exist:\n%s"), path, sb.buf); strbuf_release(&sb); @@ -1832,7 +1966,8 @@ static int merge_3way(struct merge_options *opt, &src1, name1, &src2, name2, &opt->priv->attr_index, &ll_opts); if (merge_status == LL_MERGE_BINARY_CONFLICT) - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_BINARY, 0, + path, NULL, NULL, NULL, "warning: Cannot merge binary files: %s (%s vs. %s)", path, name1, name2); @@ -1944,7 +2079,8 @@ static int handle_content_merge(struct merge_options *opt, if (ret) return -1; clean &= (merge_status == 0); - path_msg(opt, path, 1, _("Auto-merging %s"), path); + path_msg(opt, INFO_AUTO_MERGING, 1, path, NULL, NULL, NULL, + _("Auto-merging %s"), path); } else if (S_ISGITLINK(a->mode)) { int two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode)); clean = merge_submodule(opt, pathnames[0], @@ -2082,21 +2218,24 @@ static char *handle_path_level_conflicts(struct merge_options *opt, c_info->reported_already = 1; strbuf_add_separated_string_list(&collision_paths, ", ", &c_info->source_files); - path_msg(opt, new_path, 0, - _("CONFLICT (implicit dir rename): Existing file/dir " - "at %s in the way of implicit directory rename(s) " - "putting the following path(s) there: %s."), - new_path, collision_paths.buf); + path_msg(opt, CONFLICT_DIR_RENAME_FILE_IN_WAY, 0, + new_path, NULL, NULL, &c_info->source_files, + _("CONFLICT (implicit dir rename): Existing " + "file/dir at %s in the way of implicit " + "directory rename(s) putting the following " + "path(s) there: %s."), + new_path, collision_paths.buf); clean = 0; } else if (c_info->source_files.nr > 1) { c_info->reported_already = 1; strbuf_add_separated_string_list(&collision_paths, ", ", &c_info->source_files); - path_msg(opt, new_path, 0, - _("CONFLICT (implicit dir rename): Cannot map more " - "than one path to %s; implicit directory renames " - "tried to put these paths there: %s"), - new_path, collision_paths.buf); + path_msg(opt, CONFLICT_DIR_RENAME_COLLISION, 0, + new_path, NULL, NULL, &c_info->source_files, + _("CONFLICT (implicit dir rename): Cannot map " + "more than one path to %s; implicit directory " + "renames tried to put these paths there: %s"), + new_path, collision_paths.buf); clean = 0; } @@ -2150,13 +2289,14 @@ static void get_provisional_directory_renames(struct merge_options *opt, continue; if (bad_max == max) { - path_msg(opt, source_dir, 0, - _("CONFLICT (directory rename split): " - "Unclear where to rename %s to; it was " - "renamed to multiple other directories, with " - "no destination getting a majority of the " - "files."), - source_dir); + path_msg(opt, CONFLICT_DIR_RENAME_SPLIT, 0, + source_dir, NULL, NULL, NULL, + _("CONFLICT (directory rename split): " + "Unclear where to rename %s to; it was " + "renamed to multiple other directories, " + "with no destination getting a majority of " + "the files."), + source_dir); *clean = 0; } else { strmap_put(&renames->dir_renames[side], @@ -2304,7 +2444,8 @@ static char *check_for_directory_rename(struct merge_options *opt, */ otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir); if (otherinfo) { - path_msg(opt, rename_info->key, 1, + path_msg(opt, INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, 1, + rename_info->key, path, new_dir, NULL, _("WARNING: Avoiding applying %s -> %s rename " "to %s, because %s itself was renamed."), rename_info->key, new_dir, path, new_dir); @@ -2444,14 +2585,16 @@ static void apply_directory_rename_modifications(struct merge_options *opt, if (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) { /* Notify user of updated path */ if (pair->status == 'A') - path_msg(opt, new_path, 1, + path_msg(opt, INFO_DIR_RENAME_APPLIED, 1, + new_path, old_path, NULL, NULL, _("Path updated: %s added in %s inside a " "directory that was renamed in %s; moving " "it to %s."), old_path, branch_with_new_path, branch_with_dir_rename, new_path); else - path_msg(opt, new_path, 1, + path_msg(opt, INFO_DIR_RENAME_APPLIED, 1, + new_path, old_path, NULL, NULL, _("Path updated: %s renamed to %s in %s, " "inside a directory that was renamed in %s; " "moving it to %s."), @@ -2464,7 +2607,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt, */ ci->path_conflict = 1; if (pair->status == 'A') - path_msg(opt, new_path, 1, + path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1, + new_path, old_path, NULL, NULL, _("CONFLICT (file location): %s added in %s " "inside a directory that was renamed in %s, " "suggesting it should perhaps be moved to " @@ -2472,7 +2616,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt, old_path, branch_with_new_path, branch_with_dir_rename, new_path); else - path_msg(opt, new_path, 1, + path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1, + new_path, old_path, NULL, NULL, _("CONFLICT (file location): %s renamed to %s " "in %s, inside a directory that was renamed " "in %s, suggesting it should perhaps be " @@ -2628,7 +2773,8 @@ static int process_renames(struct merge_options *opt, * and remove the setting of base->path_conflict to 1. */ base->path_conflict = 1; - path_msg(opt, oldpath, 0, + path_msg(opt, CONFLICT_RENAME_RENAME, 0, + pathnames[0], pathnames[1], pathnames[2], NULL, _("CONFLICT (rename/rename): %s renamed to " "%s in %s and to %s in %s."), pathnames[0], @@ -2723,7 +2869,8 @@ static int process_renames(struct merge_options *opt, memcpy(&newinfo->stages[target_index], &merged, sizeof(merged)); if (!clean) { - path_msg(opt, newpath, 0, + path_msg(opt, CONFLICT_RENAME_COLLIDES, 0, + newpath, oldpath, NULL, NULL, _("CONFLICT (rename involved in " "collision): rename of %s -> %s has " "content conflicts AND collides " @@ -2742,7 +2889,8 @@ static int process_renames(struct merge_options *opt, */ newinfo->path_conflict = 1; - path_msg(opt, newpath, 0, + path_msg(opt, CONFLICT_RENAME_DELETE, 0, + newpath, oldpath, NULL, NULL, _("CONFLICT (rename/delete): %s renamed " "to %s in %s, but deleted in %s."), oldpath, newpath, rename_branch, delete_branch); @@ -2766,7 +2914,8 @@ static int process_renames(struct merge_options *opt, } else if (source_deleted) { /* rename/delete */ newinfo->path_conflict = 1; - path_msg(opt, newpath, 0, + path_msg(opt, CONFLICT_RENAME_DELETE, 0, + newpath, oldpath, NULL, NULL, _("CONFLICT (rename/delete): %s renamed" " to %s in %s, but deleted in %s."), oldpath, newpath, @@ -3687,7 +3836,8 @@ static void process_entry(struct merge_options *opt, path = unique_path(opt, path, branch); strmap_put(&opt->priv->paths, path, new_ci); - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_FILE_DIRECTORY, 0, + path, old_path, NULL, NULL, _("CONFLICT (file/directory): directory in the way " "of %s from %s; moving it to %s instead."), old_path, branch, path); @@ -3763,15 +3913,23 @@ static void process_entry(struct merge_options *opt, rename_b = 1; } + if (rename_a) + a_path = unique_path(opt, path, opt->branch1); + if (rename_b) + b_path = unique_path(opt, path, opt->branch2); + if (rename_a && rename_b) { - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_DISTINCT_MODES, 0, + path, a_path, b_path, NULL, _("CONFLICT (distinct types): %s had " "different types on each side; " "renamed both of them so each can " "be recorded somewhere."), path); } else { - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_DISTINCT_MODES, 0, + path, rename_a ? a_path : b_path, + NULL, NULL, _("CONFLICT (distinct types): %s had " "different types on each side; " "renamed one of them so each can be " @@ -3808,14 +3966,10 @@ static void process_entry(struct merge_options *opt, /* Insert entries into opt->priv_paths */ assert(rename_a || rename_b); - if (rename_a) { - a_path = unique_path(opt, path, opt->branch1); + if (rename_a) strmap_put(&opt->priv->paths, a_path, ci); - } - if (rename_b) - b_path = unique_path(opt, path, opt->branch2); - else + if (!rename_b) b_path = path; strmap_put(&opt->priv->paths, b_path, new_ci); @@ -3866,7 +4020,8 @@ static void process_entry(struct merge_options *opt, reason = _("add/add"); if (S_ISGITLINK(merged_file.mode)) reason = _("submodule"); - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_CONTENTS, 0, + path, NULL, NULL, NULL, _("CONFLICT (%s): Merge conflict in %s"), reason, path); } @@ -3910,7 +4065,8 @@ static void process_entry(struct merge_options *opt, * since the contents were not modified. */ } else { - path_msg(opt, path, 0, + path_msg(opt, CONFLICT_MODIFY_DELETE, 0, + path, NULL, NULL, NULL, _("CONFLICT (modify/delete): %s deleted in %s " "and modified in %s. Version %s of %s left " "in tree."), @@ -4206,7 +4362,8 @@ static int record_conflicted_index_entries(struct merge_options *opt) path, "cruft"); - path_msg(opt, path, 1, + path_msg(opt, CONFLICT_PRESENT_DESPITE_SKIPPED, 1, + path, NULL, NULL, NULL, _("Note: %s not up to date and in way of checking out conflicted version; old copy renamed to %s"), path, new_name); errs |= rename(path, new_name); From patchwork Sat Jun 18 00:20:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886171 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5100ECCA479 for ; Sat, 18 Jun 2022 00:21:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383815AbiFRAVs (ORCPT ); Fri, 17 Jun 2022 20:21:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383753AbiFRAVa (ORCPT ); Fri, 17 Jun 2022 20:21:30 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FCED694B0 for ; Fri, 17 Jun 2022 17:21:21 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id e25so3651025wrc.13 for ; Fri, 17 Jun 2022 17:21:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=FrwOd8OrO4nYNpu/ilYgrOx3eNO/WHAbShED3LrPe7s=; b=X0+vjKbP2nG9MqebFQr9+7vjSNnUnLP6wCbbqIcXiOuYsID44wg94mTu275eUFSj6e el46mZZOAAyd+O5RDM9SlQKdRmliDp98tjRWTpUo6+ynNjI2qPW0EjFsLQdVeWgzOvyX S9ANX7qf030swApNvhnhkF5yw+PaxKX1Z5nFEIKcP0tzCIt+cz17ucQBplvgyDgCAd3P /szRGt1V0M1l4+RmOkRaUGba+iB77bGsfdYZNaJjl5Dxl5iQouWUdJNqFTBmS0BGSv7E xiQ2HCa73tALAkNHBgOqqDqd5thq5q6CbVnSbsp279y7Lmg+Kl75Ip11GaAOKfNXIM9Q fPRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=FrwOd8OrO4nYNpu/ilYgrOx3eNO/WHAbShED3LrPe7s=; b=aoeZGjTPXIK76MrU36l73gM/1yysVlQOE0HVqfQvy3z0bzBMiWTzoabrvovEeoUcnu D2pNIFDji+4vI1GdfuH7KadsmGveJ3XrXeCUP/sEGi/uLsTpCGqGYWZt+k6x7A49RwfT JYnjDtBxSNCpJV0lRjED8Gv7YzbQH26tevofFkLKD7VOyEUezQ/Vs8Mexlq1oaVAtbB4 LhtQ0XQTjf8jcb/81Fk8K5pxwFLOzWpR3iTZ2jbwt70bJrd9VQ9a4ptUDCBtyfd+mrLE O+y52Fl5EU676RDnbikv4dqH3WJSqlhHO1ywipGW/uI4YJJmX5DlLgAgOozDNliUO7Br 7UGA== X-Gm-Message-State: AJIora/o4UYZ7ssVbwxONznHVj+vb2vFQi+QJq/u5KALhRYkEdQAUXLi Tm5Yy29585eVAO+ha0p3OLDWS0HWMIY47w== X-Google-Smtp-Source: AGRyM1uMwxdBjp6p3lj+D4gJGGypoF2VnF1rKj4y6HSbLDHLBvgBz6q6t8R5GONA2EZDtotSAvfZ/w== X-Received: by 2002:a5d:5a86:0:b0:218:4929:3dad with SMTP id bp6-20020a5d5a86000000b0021849293dadmr11354314wrb.338.1655511679938; Fri, 17 Jun 2022 17:21:19 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id t22-20020a05600c41d600b0039db7f1a3f5sm6702538wmh.45.2022.06.17.17.21.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:19 -0700 (PDT) Message-Id: <662e97f2ed4b6a0698bb86493efc3650763600d3.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:57 +0000 Subject: [PATCH v7 14/17] merge-ort: optionally produce machine-readable output Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren With the new `detailed` parameter, a new mode can be triggered when displaying the merge messages: The `detailed` mode prints NUL-delimited fields of the following form: NUL ... NUL NUL The `` field determines how many `` fields there are. The intention of this mode is to support server-side operations, where worktree-less merges can lead to conflicts and depending on the type and/or path count, the caller might know how to handle said conflict. Signed-off-by: Elijah Newren Signed-off-by: Johannes Schindelin --- builtin/merge-tree.c | 3 ++- merge-ort.c | 22 ++++++++++++++++++++-- merge-ort.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index c61b5b4a10d..b3c5692498e 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -468,7 +468,8 @@ static int real_merge(struct merge_tree_options *o, } if (o->show_messages) { putchar(line_termination); - merge_display_update_messages(&opt, &result); + merge_display_update_messages(&opt, line_termination == '\0', + &result); } merge_finalize(&opt, &result); return !result.clean; /* result.clean < 0 handled above */ diff --git a/merge-ort.c b/merge-ort.c index 432937255f6..4a56c189ddf 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4412,6 +4412,7 @@ static int record_conflicted_index_entries(struct merge_options *opt) } void merge_display_update_messages(struct merge_options *opt, + int detailed, struct merge_result *result) { struct merge_options_internal *opti = result->priv; @@ -4437,8 +4438,25 @@ void merge_display_update_messages(struct merge_options *opt, /* Iterate over the items, printing them */ for (int path_nr = 0; path_nr < olist.nr; ++path_nr) { struct string_list *conflicts = olist.items[path_nr].util; - for (int i = 0; i < conflicts->nr; i++) + for (int i = 0; i < conflicts->nr; i++) { + struct logical_conflict_info *info = + conflicts->items[i].util; + + if (detailed) { + printf("%lu", (unsigned long)info->paths.nr); + putchar('\0'); + for (int n = 0; n < info->paths.nr; n++) { + fputs(info->paths.v[n], stdout); + putchar('\0'); + } + fputs(type_short_descriptions[info->type], + stdout); + putchar('\0'); + } puts(conflicts->items[i].string); + if (detailed) + putchar('\0'); + } } string_list_clear(&olist, 0); @@ -4518,7 +4536,7 @@ void merge_switch_to_result(struct merge_options *opt, trace2_region_leave("merge", "write_auto_merge", opt->repo); } if (display_update_msgs) - merge_display_update_messages(opt, result); + merge_display_update_messages(opt, /* detailed */ 0, result); merge_finalize(opt, result); } diff --git a/merge-ort.h b/merge-ort.h index c4909bcbf96..a994c9a5fcd 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -87,6 +87,7 @@ void merge_switch_to_result(struct merge_options *opt, * so only call this when bypassing merge_switch_to_result(). */ void merge_display_update_messages(struct merge_options *opt, + int detailed, struct merge_result *result); struct stage_info { From patchwork Sat Jun 18 00:20:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886168 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC1A1C43334 for ; Sat, 18 Jun 2022 00:21:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383767AbiFRAVn (ORCPT ); Fri, 17 Jun 2022 20:21:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44014 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383754AbiFRAVa (ORCPT ); Fri, 17 Jun 2022 20:21:30 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 692876970B for ; Fri, 17 Jun 2022 17:21:22 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id g27so864459wrb.10 for ; Fri, 17 Jun 2022 17:21:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=SSiRW01ACwOK0LAIQZ5fNsRTzzFu0Gl8U0LeJb+1GHg=; b=MLRMTd3rHcAm15I61b7EHh8OwfJQQ4xvhfwG7grCcaynxg4gpxBhJhYoYaDy7OleZI BMMiZK7BV6fK1r+r4RDJdg1/YXzSHpxNuBQ5yaXwvva2ZDkWvHQ34ILMBoB71VjfUBWH v78yan9xXlQt48EHofHn7HUOzQiG+6v0kChcyMKnADPPeDfG59VH5eM4cyhe+pUIUb8Q VosYCxgPDQV5fRlsCIo9UB5iptohLFlVMsgF3ueDGe8t3oLN9d27ANb5bpbk7iRzIN4w mzhxopOh4ZbTmpus12oD8lpfyETg8dZg0IcHEBVQdGOPoYF/E1zrIyd/qvA5qBs/60dH Y8oA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=SSiRW01ACwOK0LAIQZ5fNsRTzzFu0Gl8U0LeJb+1GHg=; b=fMfSyVJL28ltxzwbB8tpw7X2SaQnHjKDvlVIHRYBfMhMweWlpk1wRtfO59c2xkqOMx Y0ZQAp615Gfo98b7mLHhZyy4JU3RFRIjqm7Mv/x0ZJEocXNcTxCts+fIWfzamMAfg4dp 6UZNglf71pGA1mnXTQcyaIq0VkMabt9B/Rtn3QI69hi22JsUA79Vvm8fO/Cwb8AEaPlB 3U93gBnoAF9YHJi7LdO6Mqm8UHaN9HVP3l0hfurbHeI+WsmzprzFyqmoCab1to89GtvL uz6lQxiOlR0Jqkj40jzL7EYLlFF0bd0LU2bgT21uxcdZ5SQajLF3izc6onzHfL5z6m7L ld6A== X-Gm-Message-State: AJIora/mbbwQV6aV8xjqcm8OC1khgn95EuhVshWbDLnyR/anp9jwv2ye N36o0qsowj8VX1EKFBDok19Zz3C8hL0pWg== X-Google-Smtp-Source: AGRyM1sdKo8merGW/hwSwg/bNVa+mVPnKqnoyaI+DrHRYaroe907YMgxmKnJBhqP7gEYeKhHkAdCpw== X-Received: by 2002:a05:6000:1686:b0:219:b932:ffba with SMTP id y6-20020a056000168600b00219b932ffbamr11715028wrd.227.1655511681548; Fri, 17 Jun 2022 17:21:21 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i9-20020a05600c354900b003975c7058bfsm7260860wmq.12.2022.06.17.17.21.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:20 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:58 +0000 Subject: [PATCH v7 15/17] merge-tree: allow `ls-files -u` style info to be NUL terminated Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Much as `git ls-files` has a -z option, let's add one to merge-tree so that the conflict-info section can be NUL terminated (and avoid quoting of unusual filenames). Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 21 +++++++++++++--- builtin/merge-tree.c | 4 ++- t/t4301-merge-tree-write-tree.sh | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index b89aabdb98e..75b57f8abab 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -40,6 +40,12 @@ After the merge completes, a new toplevel tree object is created. See OPTIONS ------- +-z:: + Do not quote filenames in the section, + and end each filename with a NUL character rather than + newline. Also begin the messages section with a NUL character + instead of a newline. See <> below for more information. + --name-only:: In the Conflicted file info section, instead of writing a list of (mode, oid, stage, path) tuples to output for conflicted @@ -76,7 +82,8 @@ OID of toplevel tree This is a tree object that represents what would be checked out in the working tree at the end of `git merge`. If there were conflicts, then -files within this tree may have embedded conflict markers. +files within this tree may have embedded conflict markers. This section +is always followed by a newline (or NUL if `-z` is passed). [[CFI]] Conflicted file info @@ -89,20 +96,26 @@ This is a sequence of lines with the format The filename will be quoted as explained for the configuration variable `core.quotePath` (see linkgit:git-config[1]). However, if the `--name-only` option is passed, the mode, object, and stage will -be omitted. +be omitted. If `-z` is passed, the "lines" are terminated by a NUL +character instead of a newline character. [[IM]] Informational messages ~~~~~~~~~~~~~~~~~~~~~~ -This always starts with a blank line to separate it from the previous -sections, and then has free-form messages about the merge, such as: +This always starts with a blank line (or NUL if `-z` is passed) to +separate it from the previous sections, and then has free-form +messages about the merge, such as: * "Auto-merging " * "CONFLICT (rename/delete): renamed...but deleted in..." * "Failed to merge submodule ()" * "Warning: cannot merge binary files: " +Note that these free-form messages will never have a NUL character +in or between them, even if -z is passed. It is simply a large block +of text taking up the remainder of the output. + EXIT STATUS ----------- diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index b3c5692498e..c159e317743 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -445,7 +445,7 @@ static int real_merge(struct merge_tree_options *o, if (o->show_messages == -1) o->show_messages = !result.clean; - puts(oid_to_hex(&result.tree->object.oid)); + printf("%s%c", oid_to_hex(&result.tree->object.oid), line_termination); if (!result.clean) { struct string_list conflicted_files = STRING_LIST_INIT_NODUP; const char *last = NULL; @@ -494,6 +494,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) N_("do a trivial merge only"), MODE_TRIVIAL), OPT_BOOL(0, "messages", &o.show_messages, N_("also show informational/conflict messages")), + OPT_SET_INT('z', NULL, &line_termination, + N_("separate paths with the NUL character"), '\0'), OPT_BOOL_F(0, "name-only", &o.name_only, N_("list filenames without modes/oids/stages"), diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 0ec5f0d3f7e..88e75b18cc5 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -173,4 +173,46 @@ test_expect_success 'Check conflicted oids and modes without messages' ' test_cmp conflicted-file-info actual ' +test_expect_success 'NUL terminated conflicted file "lines"' ' + git checkout -b tweak1 side1 && + test_write_lines zero 1 2 3 4 5 6 >numbers && + git add numbers && + git mv numbers "Αυτά μου φαίνονται κινέζικα" && + git commit -m "Renamed numbers" && + + test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out && + anonymize_hash out >actual && + printf "\\n" >>actual && + + # Expected results: + # "greeting" should merge with conflicts + # "whatever" has *both* a modify/delete and a file/directory conflict + # "Αυτά μου φαίνονται κινέζικα" should have a conflict + echo HASH | lf_to_nul >expect && + + q_to_tab <<-EOF | lf_to_nul >>expect && + 100644 HASH 1Qgreeting + 100644 HASH 2Qgreeting + 100644 HASH 3Qgreeting + 100644 HASH 1Qwhatever~tweak1 + 100644 HASH 2Qwhatever~tweak1 + 100644 HASH 1QΑυτά μου φαίνονται κινέζικα + 100644 HASH 2QΑυτά μου φαίνονται κινέζικα + 100644 HASH 3QΑυτά μου φαίνονται κινέζικα + + EOF + + q_to_nul <<-EOF >>expect && + 1QgreetingQAuto-mergingQAuto-merging greeting + Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting + Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead. + Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1. Version tweak1 of whatever~tweak1 left in tree. + Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα + Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα + Q + EOF + + test_cmp expect actual +' + test_done From patchwork Sat Jun 18 00:20:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886169 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2640CCA479 for ; Sat, 18 Jun 2022 00:21:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383777AbiFRAVp (ORCPT ); Fri, 17 Jun 2022 20:21:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383658AbiFRAVc (ORCPT ); Fri, 17 Jun 2022 20:21:32 -0400 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F81D6972B for ; Fri, 17 Jun 2022 17:21:24 -0700 (PDT) Received: by mail-wr1-x430.google.com with SMTP id w17so7500344wrg.7 for ; Fri, 17 Jun 2022 17:21:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=TT74SY4vdwupF7Apj8+pubYOYZb9BPcSsfOpp//NhsM=; b=NFJU2y2tHY0TBiITnL/wqnqtAG8uRlLyl6SrIku8fzWPDjX+s4R/ftjTW+mpVb7Krq ocTgSrkgwKQ0n07L/9K9mKS9sBHWXIFpbWZKmBNvNMgz0SQmWfpzkUJSrG9A5LavMfyH cE+vN37oRqbauWu9PmCxOXFAPim4aQxRC+ERRjylv61X/ylmgzjx2nVLKSXLHrUTjUIg mX7SviP6Y/7LyDWDllu0YiP0I4ZRYZttcbhd2HdNLoVXER3Vkpil1f20BdUh98/98OI/ 0BusdLyGMFlTUXSdKhCO9+/HIcBWI1R5JoT6f/1EGuCF7B+f6pet9G7sk2KzBifudOO6 FeWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=TT74SY4vdwupF7Apj8+pubYOYZb9BPcSsfOpp//NhsM=; b=e0DeHCiguubIuRXCveIv3AQiZxD3lOn9NaAbEzedcc26mvgktZPfvUX5tqA4fUp/Os F3hlxXMqM3PARi2VtV9PXIzC+uCk21NbmRiqaiZhRjH2nueGY5VS6ZBybnxMfZ/esHNF QXvcw5JxMCm3LDIAr7DCn3tLcMe/PhFaRnin7397tegEXCQKYgQZdOSqLaGsnA59Ouhf kF1QnLbVvOSmAy5kSD4aeZ4huB6Bkw8oi+lbiT9GrheVaxhpfo/YOYtmSNaoEZryamv/ k6YuiBIusnqsznN6tVw4hlTpqcU2rt5Hw2kyewi2O7JLnhCfT6F746Jg6lKHWq3ksU3q 1W9Q== X-Gm-Message-State: AJIora9FnwgW4l2JX/WQb15CvGjuBzJAgfxBNQf3FRN0EcwsWJdJwlBw p98QifwIoCVjGgUwvzr+6UxuPQTpw8MzlA== X-Google-Smtp-Source: AGRyM1vlaKRqKi8NzXeiVhY1sNn9dudTyiQ9zTNMqzK8JFLLomb2FZw6Rz/7M5QrILLg3nQjPoOXfQ== X-Received: by 2002:a05:6000:18a9:b0:218:891d:815c with SMTP id b9-20020a05600018a900b00218891d815cmr11495623wri.311.1655511682617; Fri, 17 Jun 2022 17:21:22 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z12-20020a05600c220c00b0039c5b4ab1b0sm6562179wml.48.2022.06.17.17.21.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:21 -0700 (PDT) Message-Id: <66df0c2e8379ca10debd403da295a2d6d230d453.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:20:59 +0000 Subject: [PATCH v7 16/17] merge-tree: add a --allow-unrelated-histories flag Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Folks may want to merge histories that have no common ancestry; provide a flag with the same name as used by `git merge` to allow this. Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 5 +++++ builtin/merge-tree.c | 7 ++++++- t/t4301-merge-tree-write-tree.sh | 24 +++++++++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 75b57f8abab..628324646d3 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -59,6 +59,11 @@ OPTIONS default is to include these messages if there are merge conflicts, and to omit them otherwise. +--allow-unrelated-histories:: + merge-tree will by default error out if the two branches specified + share no common history. This flag can be given to override that + check and make the merge proceed anyway. + [[OUTPUT]] OUTPUT ------ diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index c159e317743..ae5782917b9 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -399,6 +399,7 @@ enum mode { struct merge_tree_options { int mode; + int allow_unrelated_histories; int show_messages; int name_only; }; @@ -434,7 +435,7 @@ static int real_merge(struct merge_tree_options *o, * merge_incore_recursive in merge-ort.h */ merge_bases = get_merge_bases(parent1, parent2); - if (!merge_bases) + if (!merge_bases && !o->allow_unrelated_histories) die(_("refusing to merge unrelated histories")); merge_bases = reverse_commit_list(merge_bases); @@ -500,6 +501,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) &o.name_only, N_("list filenames without modes/oids/stages"), PARSE_OPT_NONEG), + OPT_BOOL_F(0, "allow-unrelated-histories", + &o.allow_unrelated_histories, + N_("allow merging unrelated histories"), + PARSE_OPT_NONEG), OPT_END() }; diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 88e75b18cc5..f091259a55e 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -44,7 +44,13 @@ test_expect_success setup ' git checkout side3 && git mv numbers sequence && test_tick && - git commit -m rename-numbers + git commit -m rename-numbers && + + git switch --orphan unrelated && + >something-else && + git add something-else && + test_tick && + git commit -m first-commit ' test_expect_success 'Clean merge' ' @@ -215,4 +221,20 @@ test_expect_success 'NUL terminated conflicted file "lines"' ' test_cmp expect actual ' +test_expect_success 'error out by default for unrelated histories' ' + test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error && + + grep "refusing to merge unrelated histories" error +' + +test_expect_success 'can override merge of unrelated histories' ' + git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree && + TREE=$(cat tree) && + + git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect && + git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual && + + test_cmp expect actual +' + test_done From patchwork Sat Jun 18 00:21:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12886170 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BD04C43334 for ; Sat, 18 Jun 2022 00:21:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1383808AbiFRAVq (ORCPT ); Fri, 17 Jun 2022 20:21:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44064 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1383234AbiFRAVc (ORCPT ); Fri, 17 Jun 2022 20:21:32 -0400 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A4AF969CCF for ; Fri, 17 Jun 2022 17:21:25 -0700 (PDT) Received: by mail-wr1-x436.google.com with SMTP id v14so7517785wra.5 for ; Fri, 17 Jun 2022 17:21:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=MUjTW0FGzziTHwmT76HmwERAj5PW1p0v96TUM4MmGVE=; b=l0vd9xoDA2olKoYw/iG+QfVT/6AWTnwGBMH/ClDyc8rP/NzdVuvn4Bo3la6YXrqpTf DYs5dlzLu+sFN3SwVK4OdMc1DHbpXQxC/FOSEr2VjIx2oqjD8SiyBB6ythl9nnQRH1Ha N6TLlSBAN2eo2nyr8yg7q25KC40HqW1kFFIzDL6xOsPlwQqnec7XU69cU8WEZa6BffE6 c8F3cqkCBqPeYdWRVNM8TwPR0u7DktA229S8dMolikUNPBP4hx6QIygZ++0/YuLq6ua8 vUyhbaOLcCoPFaeK/DifmtfSxaH9NMwqiDf5bUSVm7MTV9RS7k6zpmYaRF9znpGOf4qb SbmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=MUjTW0FGzziTHwmT76HmwERAj5PW1p0v96TUM4MmGVE=; b=6inVldxpv/qbDCUdB6TiIwhwQT1PBMJyPCiXK82amtvrKpojrVj6HZo3vqD2db48eW RJD/vn1MdX93vpJCy0WOqoj3YpisrwoclocZWHkPYu5z9BFaUBWyUrjfXkAu59gGPGwR YIrZuprQA6ft8PnRUwyppcHzj/sSAl9A07g3UFvSTU66uF8ldcFp5FXI2NOWTLXA1hp8 0aGVKnoe8nF61DTE6oXN+UrjddoCZsaSSy+7oCYOgUH9VogA540SNfHee0pq58bSmqaa u+qj5EiRnP862jECIlk6s7DKBTruElAkiiMqw+K49nW1910ysmjzo+0p6YeC/kOF+HuJ yUlw== X-Gm-Message-State: AJIora8rKNHxjSuBK1FuBT9SSBJItVycyXBLlgJeFQ1o/YwDlOrflTll K4hDMYWwk4Eto/zBfkrOSyvW4XwKL5IxUg== X-Google-Smtp-Source: AGRyM1s2DsJLW2HqJzdQEzKEYiY7WCkWJ2ZU2q5PsTq8Uc+WQdO/z6YJO8W1jSwEVUHtZs2kQUpliw== X-Received: by 2002:a05:6000:1c01:b0:20f:c6ff:43d9 with SMTP id ba1-20020a0560001c0100b0020fc6ff43d9mr11646470wrb.156.1655511683790; Fri, 17 Jun 2022 17:21:23 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b18-20020a056000055200b0021a38089e99sm5732054wrf.57.2022.06.17.17.21.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jun 2022 17:21:23 -0700 (PDT) Message-Id: <70ea8281952c4ee75ce67fe907ce32340032e7e3.1655511660.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sat, 18 Jun 2022 00:21:00 +0000 Subject: [PATCH v7 17/17] git-merge-tree.txt: add a section on potentional usage mistakes Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Christian Couder , Taylor Blau , Johannes Altmanninger , Ramsay Jones , Johannes Schindelin , Christian Couder , =?utf-8?b?UmVuw6k=?= Scharfe , =?utf-8?b?w4Z2YXIgQXJuZmrDtnI=?= =?utf-8?b?w7A=?= Bjarmason , Elijah Newren , Johannes Sixt , Josh Steadmon , Emily Shaffer , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Signed-off-by: Elijah Newren --- Documentation/git-merge-tree.txt | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index 628324646d3..d6c356740ef 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -156,6 +156,59 @@ with linkgit:git-merge[1]: * any messages that would have been printed to stdout (the <>) +MISTAKES TO AVOID +----------------- + +Do NOT look through the resulting toplevel tree to try to find which +files conflict; parse the <> section instead. +Not only would parsing an entire tree be horrendously slow in large +repositories, there are numerous types of conflicts not representable by +conflict markers (modify/delete, mode conflict, binary file changed on +both sides, file/directory conflicts, various rename conflict +permutations, etc.) + +Do NOT interpret an empty <> list as a clean +merge; check the exit status. A merge can have conflicts without having +individual files conflict (there are a few types of directory rename +conflicts that fall into this category, and others might also be added +in the future). + +Do NOT attempt to guess or make the user guess the conflict types from +the <> list. The information there is +insufficient to do so. For example: Rename/rename(1to2) conflicts (both +sides renamed the same file differently) will result in three different +file having higher order stages (but each only has one higher order +stage), with no way (short of the <> section) +to determine which three files are related. File/directory conflicts +also result in a file with exactly one higher order stage. +Possibly-involved-in-directory-rename conflicts (when +"merge.directoryRenames" is unset or set to "conflicts") also result in +a file with exactly one higher order stage. In all cases, the +<> section has the necessary info, though it +is not designed to be machine parseable. + +Do NOT assume that each paths from <>, and +the logical conflicts in the <> have a +one-to-one mapping, nor that there is a one-to-many mapping, nor a +many-to-one mapping. Many-to-many mappings exist, meaning that each +path can have many logical conflict types in a single merge, and each +logical conflict type can affect many paths. + +Do NOT assume all filenames listed in the <> +section had conflicts. Messages can be included for files that have no +conflicts, such as "Auto-merging ". + +AVOID taking the OIDS from the <> and +re-merging them to present the conflicts to the user. This will lose +information. Instead, look up the version of the file found within the +<> and show that instead. In particular, +the latter will have conflict markers annotated with the original +branch/commit being merged and, if renames were involved, the original +filename. While you could include the original branch/commit in the +conflict marker annotations when re-merging, the original filename is +not available from the <> and thus you would +be losing information that might help the user resolve the conflict. + [[DEPMERGE]] DEPRECATED DESCRIPTION ----------------------