From patchwork Fri Jan 21 19:12:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720141 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 A088EC433EF for ; Fri, 21 Jan 2022 19:12:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231264AbiAUTM0 (ORCPT ); Fri, 21 Jan 2022 14:12:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbiAUTMZ (ORCPT ); Fri, 21 Jan 2022 14:12:25 -0500 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E106C06173B for ; Fri, 21 Jan 2022 11:12:25 -0800 (PST) Received: by mail-wr1-x42c.google.com with SMTP id v13so1391940wrv.10 for ; Fri, 21 Jan 2022 11:12:25 -0800 (PST) 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=tUcb2x3r3ORBLBUjMIsmMGcF0qH+Yuzwxzo0uPqByYM=; b=FrYeIJZ2HQowTSJnl02mziaMfBephZ1q0JlP29TPu0sNcU5XqM5Nhmf7znPwZ6XkuN bEhwrFSeApkM355C4ba2Dvl+756uCbr4/62GhN317pwKj4pmIPi0F7z29u5ZbZaCfSU1 kj/taGrDkBTivEz3ouJpoMxGxjsH2tu9AVBYadb2o+LacOnlTalJIzyDm/Kxsgv4GEDV +426CoxzCVqm+rdizdqcpnHYn07rePpS/QBonfzX/BdjBUa93rL1r7qd0ngK+8CM/R4f Zo7ATdBX2SLzTaNJKts2ao/L7z3BPuFTUtuB8HSn9vwRa7Rhq8UpZjMvh0XUTexvbazB Jx9A== 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=tUcb2x3r3ORBLBUjMIsmMGcF0qH+Yuzwxzo0uPqByYM=; b=3xa3cZ4c5mibXycvX0aUZGwfBugwhABJgOO2umPhThNyAPzpelQcOGNYrC8KcuUXRG OrH/dV8ghaVytQBT0dSnlYqPWNOAuSMu2IJHBaAKzYpmDhI/PXRvwWY0hbqSBpIpw4TO ijixvqCH6FNkiJEZxOnAEXy83vTg7C566+l+/cL78DYZAiEMdiEM7ZGefYrAsEzF2qmP 96BGR1TgnStAFERUbncHd9CH3UCUVePUSXBCAHcRR5zuA0+sWUKgd+U1EtuGC2QmBQzV +hphSpFpzJUu6CCgJ9qgMKTfG5TGdC8lfIpjCN8QHXOJfpG8+6fFEcKlgTEsiWyyfn4G 82Zg== X-Gm-Message-State: AOAM531hBTlPuXIBAglhoF1oTVNpWWspYQcucgRxF03uWaNhnuAjJBgx apqT6yZmRfo4cR12s1HIXchjEU4lL40= X-Google-Smtp-Source: ABdhPJxbkC2gF3oR7FXyMv9sbgli4hJyPCFnhSuijYV8WxV1mJyIDe055secU3LBJw3M49nMFQdvgw== X-Received: by 2002:adf:e8c3:: with SMTP id k3mr4908790wrn.597.1642792343727; Fri, 21 Jan 2022 11:12:23 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h9sm6576046wmq.8.2022.01.21.11.12.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:23 -0800 (PST) Message-Id: <0b94724311df34dd10debd43c466695ed406d790.1642792341.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:11 +0000 Subject: [PATCH v4 01/10] show, log: provide a --remerge-diff capability Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren When this option is specified, we remerge all (two parent) merge commits and diff the actual merge commit to the automatically created version, in order to show how users removed conflict markers, resolved the different conflict versions, and potentially added new changes outside of conflict regions in order to resolve semantic merge problems (or, possibly, just to hide other random changes). This capability works by creating a temporary object directory and marking it as the primary object store. This makes it so that any blobs or trees created during the automatic merge are easily removable afterwards by just deleting all objects from the temporary object directory. There are a few ways that this implementation is suboptimal: * `log --remerge-diff` becomes slow, because the temporary object directory can fill with many loose objects while running * the log output can be muddied with misplaced "warning: cannot merge binary files" messages, since ll-merge.c unconditionally writes those messages to stderr while running instead of allowing callers to manage them. * important conflict and warning messages are simply dropped; thus for conflicts like modify/delete or rename/rename or file/directory which are not representable with content conflict markers, there may be no way for a user of --remerge-diff to know that there had been a conflict which was resolved (and which possibly motivated other changes in the merge commit). * when fixing the previous issue, note that some unimportant conflict and warning messages might start being included. We should instead make sure these remain dropped. Subsequent commits will address these issues. Signed-off-by: Elijah Newren --- Documentation/diff-options.txt | 10 +++- builtin/log.c | 14 ++++++ diff-merges.c | 12 +++++ log-tree.c | 59 ++++++++++++++++++++++ revision.h | 3 +- t/t4069-remerge-diff.sh | 90 ++++++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+), 2 deletions(-) create mode 100755 t/t4069-remerge-diff.sh diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c89d530d3d1..6b8175defe6 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -34,7 +34,7 @@ endif::git-diff[] endif::git-format-patch[] ifdef::git-log[] ---diff-merges=(off|none|on|first-parent|1|separate|m|combined|c|dense-combined|cc):: +--diff-merges=(off|none|on|first-parent|1|separate|m|combined|c|dense-combined|cc|remerge|r):: --no-diff-merges:: Specify diff format to be used for merge commits. Default is {diff-merges-default} unless `--first-parent` is in use, in which case @@ -64,6 +64,14 @@ ifdef::git-log[] each of the parents. Separate log entry and diff is generated for each parent. + +--diff-merges=remerge::: +--diff-merges=r::: +--remerge-diff::: + With this option, two-parent merge commits are remerged to + create a temporary tree object -- potentially containing files + with conflict markers and such. A diff is then shown between + that temporary tree and the actual merge commit. ++ --diff-merges=combined::: --diff-merges=c::: -c::: diff --git a/builtin/log.c b/builtin/log.c index f75d87e8d7f..846ba0f995a 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -35,6 +35,7 @@ #include "repository.h" #include "commit-reach.h" #include "range-diff.h" +#include "tmp-objdir.h" #define MAIL_DEFAULT_WRAP 72 #define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100 @@ -406,6 +407,14 @@ static int cmd_log_walk(struct rev_info *rev) struct commit *commit; int saved_nrl = 0; int saved_dcctc = 0; + struct tmp_objdir *remerge_objdir = NULL; + + if (rev->remerge_diff) { + remerge_objdir = tmp_objdir_create("remerge-diff"); + if (!remerge_objdir) + die(_("unable to create temporary object directory")); + tmp_objdir_replace_primary_odb(remerge_objdir, 1); + } if (rev->early_output) setup_early_output(); @@ -449,6 +458,9 @@ static int cmd_log_walk(struct rev_info *rev) rev->diffopt.no_free = 0; diff_free(&rev->diffopt); + if (rev->remerge_diff) + tmp_objdir_destroy(remerge_objdir); + if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF && rev->diffopt.flags.check_failed) { return 02; @@ -1943,6 +1955,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) die(_("--name-status does not make sense")); if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) die(_("--check does not make sense")); + if (rev.remerge_diff) + die(_("--remerge-diff does not make sense")); if (!use_patch_format && (!rev.diffopt.output_format || diff --git a/diff-merges.c b/diff-merges.c index 5060ccd890b..0af4b3f9191 100644 --- a/diff-merges.c +++ b/diff-merges.c @@ -17,6 +17,7 @@ static void suppress(struct rev_info *revs) revs->combined_all_paths = 0; revs->merges_imply_patch = 0; revs->merges_need_diff = 0; + revs->remerge_diff = 0; } static void set_separate(struct rev_info *revs) @@ -45,6 +46,12 @@ static void set_dense_combined(struct rev_info *revs) revs->dense_combined_merges = 1; } +static void set_remerge_diff(struct rev_info *revs) +{ + suppress(revs); + revs->remerge_diff = 1; +} + static diff_merges_setup_func_t func_by_opt(const char *optarg) { if (!strcmp(optarg, "off") || !strcmp(optarg, "none")) @@ -57,6 +64,8 @@ static diff_merges_setup_func_t func_by_opt(const char *optarg) return set_combined; else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined")) return set_dense_combined; + else if (!strcmp(optarg, "r") || !strcmp(optarg, "remerge")) + return set_remerge_diff; else if (!strcmp(optarg, "m") || !strcmp(optarg, "on")) return set_to_default; return NULL; @@ -110,6 +119,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv) } else if (!strcmp(arg, "--cc")) { set_dense_combined(revs); revs->merges_imply_patch = 1; + } else if (!strcmp(arg, "--remerge-diff")) { + set_remerge_diff(revs); + revs->merges_imply_patch = 1; } else if (!strcmp(arg, "--no-diff-merges")) { suppress(revs); } else if (!strcmp(arg, "--combined-all-paths")) { diff --git a/log-tree.c b/log-tree.c index 644893fd8cf..84ed864fc81 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "commit-reach.h" #include "config.h" #include "diff.h" #include "object-store.h" @@ -7,6 +8,7 @@ #include "tag.h" #include "graph.h" #include "log-tree.h" +#include "merge-ort.h" #include "reflog-walk.h" #include "refs.h" #include "string-list.h" @@ -902,6 +904,51 @@ static int do_diff_combined(struct rev_info *opt, struct commit *commit) return !opt->loginfo; } +static int do_remerge_diff(struct rev_info *opt, + struct commit_list *parents, + struct object_id *oid, + struct commit *commit) +{ + struct merge_options o; + struct commit_list *bases; + struct merge_result res = {0}; + struct pretty_print_context ctx = {0}; + struct commit *parent1 = parents->item; + struct commit *parent2 = parents->next->item; + struct strbuf parent1_desc = STRBUF_INIT; + struct strbuf parent2_desc = STRBUF_INIT; + + /* Setup merge options */ + init_merge_options(&o, the_repository); + o.show_rename_progress = 0; + + ctx.abbrev = DEFAULT_ABBREV; + format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx); + format_commit_message(parent2, "%h (%s)", &parent2_desc, &ctx); + o.branch1 = parent1_desc.buf; + o.branch2 = parent2_desc.buf; + + /* Parse the relevant commits and get the merge bases */ + parse_commit_or_die(parent1); + parse_commit_or_die(parent2); + bases = get_merge_bases(parent1, parent2); + + /* Re-merge the parents */ + merge_incore_recursive(&o, bases, parent1, parent2, &res); + + /* Show the diff */ + diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt); + log_tree_diff_flush(opt); + + /* Cleanup */ + strbuf_release(&parent1_desc); + strbuf_release(&parent2_desc); + merge_finalize(&o, &res); + /* TODO: clean up the temporary object directory */ + + return !opt->loginfo; +} + /* * Show the diff of a commit. * @@ -936,6 +983,18 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log } if (is_merge) { + int octopus = (parents->next->next != NULL); + + if (opt->remerge_diff) { + if (octopus) { + show_log(opt); + fprintf(opt->diffopt.file, + "diff: warning: Skipping remerge-diff " + "for octopus merges.\n"); + return 1; + } + return do_remerge_diff(opt, parents, oid, commit); + } if (opt->combine_merges) return do_diff_combined(opt, commit); if (opt->separate_merges) { diff --git a/revision.h b/revision.h index 5578bb4720a..13178e6b8f3 100644 --- a/revision.h +++ b/revision.h @@ -195,7 +195,8 @@ struct rev_info { combine_merges:1, combined_all_paths:1, dense_combined_merges:1, - first_parent_merges:1; + first_parent_merges:1, + remerge_diff:1; /* Format info */ int show_notes; diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh new file mode 100755 index 00000000000..5ef191f4fc9 --- /dev/null +++ b/t/t4069-remerge-diff.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +test_description='remerge-diff handling' + +. ./test-lib.sh + +# This test is ort-specific +test "${GIT_TEST_MERGE_ALGORITHM:-ort}" = ort || { + skip_all="GIT_TEST_MERGE_ALGORITHM != ort" + test_done +} + +test_expect_success 'setup basic merges' ' + test_write_lines 1 2 3 4 5 6 7 8 9 >numbers && + git add numbers && + git commit -m base && + + git branch feature_a && + git branch feature_b && + git branch feature_c && + + git branch ab_resolution && + git branch bc_resolution && + + git checkout feature_a && + test_write_lines 1 2 three 4 5 6 7 eight 9 >numbers && + git commit -a -m change_a && + + git checkout feature_b && + test_write_lines 1 2 tres 4 5 6 7 8 9 >numbers && + git commit -a -m change_b && + + git checkout feature_c && + test_write_lines 1 2 3 4 5 6 7 8 9 10 >numbers && + git commit -a -m change_c && + + git checkout bc_resolution && + git merge --ff-only feature_b && + # no conflict + git merge feature_c && + + git checkout ab_resolution && + git merge --ff-only feature_a && + # conflicts! + test_must_fail git merge feature_b && + # Resolve conflict...and make another change elsewhere + test_write_lines 1 2 drei 4 5 6 7 acht 9 >numbers && + git add numbers && + git merge --continue +' + +test_expect_success 'remerge-diff on a clean merge' ' + git log -1 --oneline bc_resolution >expect && + git show --oneline --remerge-diff bc_resolution >actual && + test_cmp expect actual +' + +test_expect_success 'remerge-diff with both a resolved conflict and an unrelated change' ' + git log -1 --oneline ab_resolution >tmp && + cat <<-EOF >>tmp && + diff --git a/numbers b/numbers + index a1fb731..6875544 100644 + --- a/numbers + +++ b/numbers + @@ -1,13 +1,9 @@ + 1 + 2 + -<<<<<<< b0ed5cb (change_a) + -three + -======= + -tres + ->>>>>>> 6cd3f82 (change_b) + +drei + 4 + 5 + 6 + 7 + -eight + +acht + 9 + EOF + # Hashes above are sha1; rip them out so test works with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff ab_resolution >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + +test_done From patchwork Fri Jan 21 19:12:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720142 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 3B365C433F5 for ; Fri, 21 Jan 2022 19:12:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231871AbiAUTMa (ORCPT ); Fri, 21 Jan 2022 14:12:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbiAUTM1 (ORCPT ); Fri, 21 Jan 2022 14:12:27 -0500 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4A51FC06173B for ; Fri, 21 Jan 2022 11:12:26 -0800 (PST) Received: by mail-wm1-x32c.google.com with SMTP id e9-20020a05600c4e4900b0034d23cae3f0so23402179wmq.2 for ; Fri, 21 Jan 2022 11:12:26 -0800 (PST) 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=LLRddwRlb3+xaGRybKZWXk1WLkIn9q55Y8o8W1Ldyek=; b=Kqir6E1anO1eWzEANs/xh/7ZA01yQREbZ4h9IJz+B6TBCyo5/rF5Pl7Y2j216u2u08 ijGEYgHxeCy0Ig2KhNM1UCcMRO348B2yO6SIvSVTZXEJSm+T5H3CSQW+6QIDUpbNt9Po Vva926dzOS7i08LfCZ9EOEqPfQ1K6ewtkQY8JPsyt66PxiGSi/qHSh7QmFqL7h5nO1qB BicZh3pEGsiXydbqturyn8mF3JdczsOWgzNcif3Bteobk4qfQsywiV8s7O7i1c5/RRmm Fhk05cFosc/I4ZGFaJeaYyGR5xuYa3aMT+im4U+ywTv99uPqZ9uC82YEccIKIoYs4RmP AYiA== 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=LLRddwRlb3+xaGRybKZWXk1WLkIn9q55Y8o8W1Ldyek=; b=IhvVCPrC7KCjZEYgLsIbaCos6aYsSKZmxOF8SbWnX6vsgeUXIDuJMmqJr+AHUDlJyG /Pboik3KpMvHeagksIul9YDUcRhwJy57Bo3r+uuAu6lProKkseLDJTLuijFd2HXfbyDn ldFuikf+jGM0h/1estJrl8h0D1UWaXg2dat5Bpl3O8qfSCHf7nyjbZEALPzUxt6WXT5W 8SQeNe2Bt/QQriXiiSCUMr4z39nBjbUqbW/LTsAC3uWM202K1KAnA2MD9tYHU5CxaJDG c7WiBzpFbPCZv+6aOzd1CxJHdpsgpRM9KmXIHefEY536Qet5xAFBwZoyt6s64KyD7me8 UCHw== X-Gm-Message-State: AOAM532M6HN6fcXShVqHZUPZv/hR8YDgkuphrTRCnwcYSvZi3lzRmTTa aJ5PIRxN5946pFAhobbwAC8KJMnrK3E= X-Google-Smtp-Source: ABdhPJxhlr/64aSAoF+qV2npX2rH9uAUoJ1wrFxzRE61bM/mKp2XR6JxlZeK8RMfIaN11VYBdpEd1Q== X-Received: by 2002:a1c:a7c2:: with SMTP id q185mr1958672wme.3.1642792344740; Fri, 21 Jan 2022 11:12:24 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 16sm5689064wmj.12.2022.01.21.11.12.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:24 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:12 +0000 Subject: [PATCH v4 02/10] log: clean unneeded objects during `log --remerge-diff` Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren The --remerge-diff option will need to create new blobs and trees representing the "automatic merge" state. If one is traversing a long project history, one can easily get hundreds of thousands of loose objects generated during `log --remerge-diff`. However, none of those loose objects are needed after we have completed our diff operation; they can be summarily deleted. Add a new helper function to tmp_objdir to discard all the contained objects, and call it after each merge is handled. Signed-off-by: Elijah Newren --- builtin/log.c | 13 +++++++------ log-tree.c | 8 +++++++- revision.h | 3 +++ tmp-objdir.c | 5 +++++ tmp-objdir.h | 6 ++++++ 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 846ba0f995a..ac550e1ae62 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -407,13 +407,12 @@ static int cmd_log_walk(struct rev_info *rev) struct commit *commit; int saved_nrl = 0; int saved_dcctc = 0; - struct tmp_objdir *remerge_objdir = NULL; if (rev->remerge_diff) { - remerge_objdir = tmp_objdir_create("remerge-diff"); - if (!remerge_objdir) + rev->remerge_objdir = tmp_objdir_create("remerge-diff"); + if (!rev->remerge_objdir) die(_("unable to create temporary object directory")); - tmp_objdir_replace_primary_odb(remerge_objdir, 1); + tmp_objdir_replace_primary_odb(rev->remerge_objdir, 1); } if (rev->early_output) @@ -458,8 +457,10 @@ static int cmd_log_walk(struct rev_info *rev) rev->diffopt.no_free = 0; diff_free(&rev->diffopt); - if (rev->remerge_diff) - tmp_objdir_destroy(remerge_objdir); + if (rev->remerge_diff) { + tmp_objdir_destroy(rev->remerge_objdir); + rev->remerge_objdir = NULL; + } if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF && rev->diffopt.flags.check_failed) { diff --git a/log-tree.c b/log-tree.c index 84ed864fc81..d4655b63d75 100644 --- a/log-tree.c +++ b/log-tree.c @@ -4,6 +4,7 @@ #include "diff.h" #include "object-store.h" #include "repository.h" +#include "tmp-objdir.h" #include "commit.h" #include "tag.h" #include "graph.h" @@ -944,7 +945,12 @@ static int do_remerge_diff(struct rev_info *opt, strbuf_release(&parent1_desc); strbuf_release(&parent2_desc); merge_finalize(&o, &res); - /* TODO: clean up the temporary object directory */ + + /* Clean up the contents of the temporary object directory */ + if (opt->remerge_objdir) + tmp_objdir_discard_objects(opt->remerge_objdir); + else + BUG("unable to remove temporary object directory"); return !opt->loginfo; } diff --git a/revision.h b/revision.h index 13178e6b8f3..44efce3f410 100644 --- a/revision.h +++ b/revision.h @@ -318,6 +318,9 @@ struct rev_info { /* misc. flags related to '--no-kept-objects' */ unsigned keep_pack_cache_flags; + + /* Location where temporary objects for remerge-diff are written. */ + struct tmp_objdir *remerge_objdir; }; int ref_excluded(struct string_list *, const char *path); diff --git a/tmp-objdir.c b/tmp-objdir.c index 3d38eeab66b..adf6033549e 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -79,6 +79,11 @@ static void remove_tmp_objdir_on_signal(int signo) raise(signo); } +void tmp_objdir_discard_objects(struct tmp_objdir *t) +{ + remove_dir_recursively(&t->path, REMOVE_DIR_KEEP_TOPLEVEL); +} + /* * These env_* functions are for setting up the child environment; the * "replace" variant overrides the value of any existing variable with that diff --git a/tmp-objdir.h b/tmp-objdir.h index cda5ec76778..76efc7edee5 100644 --- a/tmp-objdir.h +++ b/tmp-objdir.h @@ -46,6 +46,12 @@ int tmp_objdir_migrate(struct tmp_objdir *); */ int tmp_objdir_destroy(struct tmp_objdir *); +/* + * Remove all objects from the temporary object directory, while leaving it + * around so more objects can be added. + */ +void tmp_objdir_discard_objects(struct tmp_objdir *); + /* * Add the temporary object directory as an alternate object store in the * current process. From patchwork Fri Jan 21 19:12:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720143 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 4932BC433FE for ; Fri, 21 Jan 2022 19:12:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231517AbiAUTMb (ORCPT ); Fri, 21 Jan 2022 14:12:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231277AbiAUTM1 (ORCPT ); Fri, 21 Jan 2022 14:12:27 -0500 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 4965CC06173D for ; Fri, 21 Jan 2022 11:12:27 -0800 (PST) Received: by mail-wm1-x32a.google.com with SMTP id q141-20020a1ca793000000b00347b48dfb53so23528176wme.0 for ; Fri, 21 Jan 2022 11:12:27 -0800 (PST) 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=yNaezyHCbZfihrt2P4wjEMui/03iDIuquSCOMU1Tw38=; b=k/3euAwVVGU+IufBDqt8HpKf/SpsHFkZO3NdswuuR8FBZkSoyxEHMqpj0yAb6i0HVE gYC1IU2rv8uYKZzYNy2mg3dCkYzpx5A06qqFBa9UwV44zJSoa6lSvYJcSV3qohC+sKTm jNNDQahTI6aUAyKGvTB+r+YQcP9zHqgMT5IJWT23FihG+Y5HvOguZWe0+nfJdnPwsV2S n12fzFpUoKaMpTYAWdTmZqdRR5eSGeqBMeLAqgXmDl1sL5rPXNuJhIM+yWart/rj6f6X wwRo7knQ9S0Okn+aF4kwGKEsLfWtPKW9v+H73i76mzlZJFSBoj+I+6+GS7Pycr7wizV3 8LEw== 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=yNaezyHCbZfihrt2P4wjEMui/03iDIuquSCOMU1Tw38=; b=hPJUcrsXBy1KG8srcBpg2cLrwosk3IusjMIuxb0urLGfOvacdOVhxRyna9dizH14jd 8XOusoWZeQgxEYACe4AkRByCEa3VsrmGCkgJHWVYwF9cj7xkhjuI+Ucq7FrJzOa2KnB1 eDZplX9YMr+vEv7hw8pY4SXnQvxi7RUmMOhImEvthcZ3hrazPYBBPiM+8+7e43lUM2A6 QusSSQXZaX1UPXMeJCd6pqkn6iD9qRgh5rK69DCctekty4p+NJIPOq/PmxHsgbTN0nQM 1PeKHsbnQdMYj1c3w85xMY5l0LMSR4XEEX0ukEGVMvVb4q/VhVedo5WRJoKgfMZkJR+E 5ZJA== X-Gm-Message-State: AOAM530Cs0KIAHQnHoaKJdMZCbsDBb/HkKae3khtnjBMBvh8leEEA7cz 6rz/hj5LBGavLDugUaTboFhcq1IVzr4= X-Google-Smtp-Source: ABdhPJyP8BKPPRA3P+kPQUI1x5A9xay7PswihvjF++QJGOK8psFvNGtssFRJhXw6Ftr70qZ/8dlX/Q== X-Received: by 2002:a7b:c317:: with SMTP id k23mr2005832wmj.20.1642792345552; Fri, 21 Jan 2022 11:12:25 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id u15sm917842wrn.48.2022.01.21.11.12.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:25 -0800 (PST) Message-Id: <8d6c3d48f0eb0e3af00a01d6463f6cd601bb0076.1642792341.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:13 +0000 Subject: [PATCH v4 03/10] ll-merge: make callers responsible for showing warnings Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Since some callers may want to send warning messages to somewhere other than stdout/stderr, stop printing "warning: Cannot merge binary files" from ll-merge and instead modify the return status of ll_merge() to indicate when a merge of binary files has occurred. Message printing probably does not belong in a "low-level merge" anyway. This commit continues printing the message as-is, just from the callers instead of within ll_merge(). Future changes will start handling the message differently in the merge-ort codepath. There was one special case here: the callers in rerere.c do NOT check for and print such a message; since those code paths explicitly skip over binary files, there is no reason to check for a return status of LL_MERGE_BINARY_CONFLICT or print the related message. Note that my methodology included first modifying ll_merge() to return a struct, so that the compiler would catch all the callers for me and ensure I had modified all of them. After modifying all of them, I then changed the struct to an enum. Signed-off-by: Elijah Newren --- apply.c | 5 ++++- builtin/checkout.c | 12 ++++++++---- ll-merge.c | 40 ++++++++++++++++++++++------------------ ll-merge.h | 9 ++++++++- merge-blobs.c | 5 ++++- merge-ort.c | 5 ++++- merge-recursive.c | 5 ++++- notes-merge.c | 5 ++++- rerere.c | 9 +++++---- 9 files changed, 63 insertions(+), 32 deletions(-) diff --git a/apply.c b/apply.c index 43a0aebf4ee..8079395755f 100644 --- a/apply.c +++ b/apply.c @@ -3492,7 +3492,7 @@ static int three_way_merge(struct apply_state *state, { mmfile_t base_file, our_file, their_file; mmbuffer_t result = { NULL }; - int status; + enum ll_merge_result status; /* resolve trivial cases first */ if (oideq(base, ours)) @@ -3509,6 +3509,9 @@ static int three_way_merge(struct apply_state *state, &their_file, "theirs", state->repo->index, NULL); + if (status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + path, "ours", "theirs"); free(base_file.ptr); free(our_file.ptr); free(their_file.ptr); diff --git a/builtin/checkout.c b/builtin/checkout.c index cbf73b8c9f6..3a559d69303 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -237,6 +237,7 @@ static int checkout_merged(int pos, const struct checkout *state, struct cache_entry *ce = active_cache[pos]; const char *path = ce->name; mmfile_t ancestor, ours, theirs; + enum ll_merge_result merge_status; int status; struct object_id oid; mmbuffer_t result_buf; @@ -267,13 +268,16 @@ static int checkout_merged(int pos, const struct checkout *state, memset(&ll_opts, 0, sizeof(ll_opts)); git_config_get_bool("merge.renormalize", &renormalize); ll_opts.renormalize = renormalize; - status = ll_merge(&result_buf, path, &ancestor, "base", - &ours, "ours", &theirs, "theirs", - state->istate, &ll_opts); + merge_status = ll_merge(&result_buf, path, &ancestor, "base", + &ours, "ours", &theirs, "theirs", + state->istate, &ll_opts); free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); - if (status < 0 || !result_buf.ptr) { + if (merge_status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + path, "ours", "theirs"); + if (merge_status < 0 || !result_buf.ptr) { free(result_buf.ptr); return error(_("path '%s': cannot merge"), path); } diff --git a/ll-merge.c b/ll-merge.c index 261657578c7..a937cec59a6 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -14,7 +14,7 @@ struct ll_merge_driver; -typedef int (*ll_merge_fn)(const struct ll_merge_driver *, +typedef enum ll_merge_result (*ll_merge_fn)(const struct ll_merge_driver *, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, @@ -49,7 +49,7 @@ void reset_merge_attributes(void) /* * Built-in low-levels */ -static int ll_binary_merge(const struct ll_merge_driver *drv_unused, +static enum ll_merge_result ll_binary_merge(const struct ll_merge_driver *drv_unused, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, @@ -58,6 +58,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, const struct ll_merge_options *opts, int marker_size) { + enum ll_merge_result ret; mmfile_t *stolen; assert(opts); @@ -68,16 +69,19 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, */ if (opts->virtual_ancestor) { stolen = orig; + ret = LL_MERGE_OK; } else { switch (opts->variant) { default: - warning("Cannot merge binary files: %s (%s vs. %s)", - path, name1, name2); - /* fallthru */ + ret = LL_MERGE_BINARY_CONFLICT; + stolen = src1; + break; case XDL_MERGE_FAVOR_OURS: + ret = LL_MERGE_OK; stolen = src1; break; case XDL_MERGE_FAVOR_THEIRS: + ret = LL_MERGE_OK; stolen = src2; break; } @@ -87,16 +91,10 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, result->size = stolen->size; stolen->ptr = NULL; - /* - * With -Xtheirs or -Xours, we have cleanly merged; - * otherwise we got a conflict. - */ - return opts->variant == XDL_MERGE_FAVOR_OURS || - opts->variant == XDL_MERGE_FAVOR_THEIRS ? - 0 : 1; + return ret; } -static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, +static enum ll_merge_result ll_xdl_merge(const struct ll_merge_driver *drv_unused, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, @@ -105,7 +103,9 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, const struct ll_merge_options *opts, int marker_size) { + enum ll_merge_result ret; xmparam_t xmp; + int status; assert(opts); if (orig->size > MAX_XDIFF_SIZE || @@ -133,10 +133,12 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, xmp.ancestor = orig_name; xmp.file1 = name1; xmp.file2 = name2; - return xdl_merge(orig, src1, src2, &xmp, result); + status = xdl_merge(orig, src1, src2, &xmp, result); + ret = (status > 0) ? LL_MERGE_CONFLICT : status; + return ret; } -static int ll_union_merge(const struct ll_merge_driver *drv_unused, +static enum ll_merge_result ll_union_merge(const struct ll_merge_driver *drv_unused, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, @@ -178,7 +180,7 @@ static void create_temp(mmfile_t *src, char *path, size_t len) /* * User defined low-level merge driver support. */ -static int ll_ext_merge(const struct ll_merge_driver *fn, +static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn, mmbuffer_t *result, const char *path, mmfile_t *orig, const char *orig_name, @@ -194,6 +196,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, const char *args[] = { NULL, NULL }; int status, fd, i; struct stat st; + enum ll_merge_result ret; assert(opts); sq_quote_buf(&path_sq, path); @@ -236,7 +239,8 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, unlink_or_warn(temp[i]); strbuf_release(&cmd); strbuf_release(&path_sq); - return status; + ret = (status > 0) ? LL_MERGE_CONFLICT : status; + return ret; } /* @@ -362,7 +366,7 @@ static void normalize_file(mmfile_t *mm, const char *path, struct index_state *i } } -int ll_merge(mmbuffer_t *result_buf, +enum ll_merge_result ll_merge(mmbuffer_t *result_buf, const char *path, mmfile_t *ancestor, const char *ancestor_label, mmfile_t *ours, const char *our_label, diff --git a/ll-merge.h b/ll-merge.h index aceb1b24132..e4a20e81a3a 100644 --- a/ll-merge.h +++ b/ll-merge.h @@ -82,13 +82,20 @@ struct ll_merge_options { long xdl_opts; }; +enum ll_merge_result { + LL_MERGE_ERROR = -1, + LL_MERGE_OK = 0, + LL_MERGE_CONFLICT, + LL_MERGE_BINARY_CONFLICT, +}; + /** * Perform a three-way single-file merge in core. This is a thin wrapper * around `xdl_merge` that takes the path and any merge backend specified in * `.gitattributes` or `.git/info/attributes` into account. * Returns 0 for a clean merge. */ -int ll_merge(mmbuffer_t *result_buf, +enum ll_merge_result ll_merge(mmbuffer_t *result_buf, const char *path, mmfile_t *ancestor, const char *ancestor_label, mmfile_t *ours, const char *our_label, diff --git a/merge-blobs.c b/merge-blobs.c index ee0a0e90c94..8138090f81c 100644 --- a/merge-blobs.c +++ b/merge-blobs.c @@ -36,7 +36,7 @@ static void *three_way_filemerge(struct index_state *istate, mmfile_t *their, unsigned long *size) { - int merge_status; + enum ll_merge_result merge_status; mmbuffer_t res; /* @@ -50,6 +50,9 @@ static void *three_way_filemerge(struct index_state *istate, istate, NULL); if (merge_status < 0) return NULL; + if (merge_status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + path, ".our", ".their"); *size = res.size; return res.ptr; diff --git a/merge-ort.c b/merge-ort.c index 0342f104836..c24da2ba3cb 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -1743,7 +1743,7 @@ static int merge_3way(struct merge_options *opt, mmfile_t orig, src1, src2; struct ll_merge_options ll_opts = {0}; char *base, *name1, *name2; - int merge_status; + enum ll_merge_result merge_status; if (!opt->priv->attr_index.initialized) initialize_attr_index(opt); @@ -1787,6 +1787,9 @@ static int merge_3way(struct merge_options *opt, merge_status = ll_merge(result_buf, path, &orig, base, &src1, name1, &src2, name2, &opt->priv->attr_index, &ll_opts); + if (merge_status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + path, name1, name2); free(base); free(name1); diff --git a/merge-recursive.c b/merge-recursive.c index d9457797dbb..bc73c52dd84 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1044,7 +1044,7 @@ static int merge_3way(struct merge_options *opt, mmfile_t orig, src1, src2; struct ll_merge_options ll_opts = {0}; char *base, *name1, *name2; - int merge_status; + enum ll_merge_result merge_status; ll_opts.renormalize = opt->renormalize; ll_opts.extra_marker_size = extra_marker_size; @@ -1090,6 +1090,9 @@ static int merge_3way(struct merge_options *opt, merge_status = ll_merge(result_buf, a->path, &orig, base, &src1, name1, &src2, name2, opt->repo->index, &ll_opts); + if (merge_status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + a->path, name1, name2); free(base); free(name1); diff --git a/notes-merge.c b/notes-merge.c index b4a3a903e86..01d596920ea 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -344,7 +344,7 @@ static int ll_merge_in_worktree(struct notes_merge_options *o, { mmbuffer_t result_buf; mmfile_t base, local, remote; - int status; + enum ll_merge_result status; read_mmblob(&base, &p->base); read_mmblob(&local, &p->local); @@ -358,6 +358,9 @@ static int ll_merge_in_worktree(struct notes_merge_options *o, free(local.ptr); free(remote.ptr); + if (status == LL_MERGE_BINARY_CONFLICT) + warning("Cannot merge binary files: %s (%s vs. %s)", + oid_to_hex(&p->obj), o->local_ref, o->remote_ref); if ((status < 0) || !result_buf.ptr) die("Failed to execute internal merge"); diff --git a/rerere.c b/rerere.c index d83d58df4fb..d26627c5932 100644 --- a/rerere.c +++ b/rerere.c @@ -609,19 +609,20 @@ static int try_merge(struct index_state *istate, const struct rerere_id *id, const char *path, mmfile_t *cur, mmbuffer_t *result) { - int ret; + enum ll_merge_result ret; mmfile_t base = {NULL, 0}, other = {NULL, 0}; if (read_mmfile(&base, rerere_path(id, "preimage")) || - read_mmfile(&other, rerere_path(id, "postimage"))) - ret = 1; - else + read_mmfile(&other, rerere_path(id, "postimage"))) { + ret = LL_MERGE_CONFLICT; + } else { /* * A three-way merge. Note that this honors user-customizable * low-level merge driver settings. */ ret = ll_merge(result, path, &base, NULL, cur, "", &other, "", istate, NULL); + } free(base.ptr); free(other.ptr); From patchwork Fri Jan 21 19:12:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720144 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 5F633C433EF for ; Fri, 21 Jan 2022 19:12:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231902AbiAUTMc (ORCPT ); Fri, 21 Jan 2022 14:12:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52886 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231400AbiAUTM2 (ORCPT ); Fri, 21 Jan 2022 14:12:28 -0500 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 E736EC061744 for ; Fri, 21 Jan 2022 11:12:27 -0800 (PST) Received: by mail-wr1-x430.google.com with SMTP id u15so1399301wrt.3 for ; Fri, 21 Jan 2022 11:12:27 -0800 (PST) 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=obkKWvubyxcsBWBqodq9GjqtIG2fyoJpZDBmj1ztp44=; b=p8RK3b6HA0umuMtzFD+ZbFOkIKY6vzI9YFfWOlXgzZPGXyvaam1asUcXhgi92VglGl n9E44UQ6QTXz4jydm0dRrQETWwqzv0RHUEikMdmhVHKsjOhgpDqPozkLeO/rspXknfys jYu2HaND5leE5oZ2+6w1c3qAQF7cNS5S1qTGOXW1eNluyhCnFMB5FK9KfrniOV9geYP7 4oSSO7fu1XIZ3g+3WMrHjeOHjJPIrU+oFR5dWMSbcRAN0VljwM36G5h0V3VabDOPnYag tlhR3X4wyUoZI0ErD5y5lDN5r51uOY7iBRQGfAkiascbdQzCi4hOxvgs6FaeU279qUmB iS+A== 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=obkKWvubyxcsBWBqodq9GjqtIG2fyoJpZDBmj1ztp44=; b=Le0dRY17A4vne0ejxTgELrBVPCERxw42b4ZJ+YF3vxtVotH0d5cO7TYoYZ2zOO/j3F 2TsSKcofKRA5JizDAAyKQ8uftyLO1XUzzahlmTAK6WB+WXQ3g1CgAqyS5lhpPcfAPupU 7TtxWhRXEKhAsAIDLWnfGJmnZcLBvdVdbA8RidHXezy2yMiLtz40jE2CHP+iPGLS24JZ XbZqW1A4zrOCrw4aDD89hS6Evv4OYHaPuNfZCQ9iiAXFk1oqR7zTOgXE8POErBBTpXsA GCpHTeswpsaFUzz8AcpQwAEf27T4OdKl50ZsgvOuOptG17p4m2JdlEtqPCFUZSbZkZ9/ 8+yw== X-Gm-Message-State: AOAM530oH5cKd7xOFIZFh17l7XzHbO6ricrxbQMmAzgGiKPVHCIxpsjP 5OvtORTdMlH9pkDEIurrEr6J6vE8a5U= X-Google-Smtp-Source: ABdhPJzRp8/sp4ukZh7dFAvN4N6RcQ4LkCvDKplf3rsP1YQtWeF88hzoBnVsjCwg+KIUBKUvCpGJgw== X-Received: by 2002:a5d:648e:: with SMTP id o14mr5058324wri.667.1642792346343; Fri, 21 Jan 2022 11:12:26 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m12sm7936453wrp.55.2022.01.21.11.12.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:25 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:14 +0000 Subject: [PATCH v4 04/10] merge-ort: capture and print ll-merge warnings in our preferred fashion Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Instead of immediately printing ll-merge warnings to stderr, we save them in our output strbuf. Besides allowing us to move these warnings to a special file for --remerge-diff, this has two other benefits for regular merges done by merge-ort: * The deferral of messages ensures we can print all messages about any given path together (merge-recursive was known to sometimes intersperse messages about other paths, particularly when renames were involved). * The deferral of messages means we can avoid printing spurious conflict messages when we just end up aborting due to local user modifications in the way. (In contrast to merge-recursive.c which prematurely checks for local modifications in the way via unpack_trees() and gets the check wrong both in terms of false positives and false negatives relative to renames, merge-ort does not perform the local modifications in the way check until the checkout() step after the full merge has been computed.) Signed-off-by: Elijah Newren --- merge-ort.c | 5 +++-- t/t6404-recursive-merge.sh | 9 +++++++-- t/t6406-merge-attr.sh | 9 +++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index c24da2ba3cb..a18f47e23c5 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -1788,8 +1788,9 @@ 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) - warning("Cannot merge binary files: %s (%s vs. %s)", - path, name1, name2); + path_msg(opt, path, 0, + "warning: Cannot merge binary files: %s (%s vs. %s)", + path, name1, name2); free(base); free(name1); diff --git a/t/t6404-recursive-merge.sh b/t/t6404-recursive-merge.sh index eaf48e941e2..b8735c6db4d 100755 --- a/t/t6404-recursive-merge.sh +++ b/t/t6404-recursive-merge.sh @@ -108,8 +108,13 @@ test_expect_success 'refuse to merge binary files' ' printf "\0\0" >binary-file && git add binary-file && git commit -m binary2 && - test_must_fail git merge F >merge.out 2>merge.err && - grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge.err + if test "$GIT_TEST_MERGE_ALGORITHM" = ort + then + test_must_fail git merge F >merge_output + else + test_must_fail git merge F 2>merge_output + fi && + grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge_output ' test_expect_success 'mark rename/delete as unmerged' ' diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 84946458371..c41584eb33e 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -221,8 +221,13 @@ test_expect_success 'binary files with union attribute' ' printf "two\0" >bin.txt && git commit -am two && - test_must_fail git merge bin-main 2>stderr && - grep -i "warning.*cannot merge.*HEAD vs. bin-main" stderr + if test "$GIT_TEST_MERGE_ALGORITHM" = ort + then + test_must_fail git merge bin-main >output + else + test_must_fail git merge bin-main 2>output + fi && + grep -i "warning.*cannot merge.*HEAD vs. bin-main" output ' test_done From patchwork Fri Jan 21 19:12:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720145 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 DECCEC433F5 for ; Fri, 21 Jan 2022 19:12:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231903AbiAUTMd (ORCPT ); Fri, 21 Jan 2022 14:12:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231539AbiAUTM3 (ORCPT ); Fri, 21 Jan 2022 14:12:29 -0500 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D18D1C061749 for ; Fri, 21 Jan 2022 11:12:28 -0800 (PST) Received: by mail-wr1-x42d.google.com with SMTP id a13so1409692wrh.9 for ; Fri, 21 Jan 2022 11:12:28 -0800 (PST) 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=3DjTSuxoeCeG9xk74b8MP4D3yFu5DTvO02bZbX9rQ60=; b=gzdQwQXSrCdkQ5dSzCN4tBuKc4+bk6EeIgLboYedKc0OSjoJDz+2VTNvEv0axL5Yb3 WK0EaQ54IPQRaV2WqmNYMZt/g3z7t/TviMYr7YGgfG/wuPSWFn/ebQ+iWa3XQ+09cU3c CNDC7lwfi+OG2cpuz+oCjGdvpggnYkCpY0jaaC6tQ6MuowRiKZ0AkTOL9mPFVV2ULJMq ub9cdZnv3av06i7dp9jyBKKnXw8F09L8bP7CzTyk+YoYGuFSRd9R0dGUMN0WFxZjTTDn QnPunij+lvK5iiW0TvwP+4D5PhDMI9uRzkD/H1z5z1rTooGL/d+xzK+MKHkRhPvUqJSV sshg== 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=3DjTSuxoeCeG9xk74b8MP4D3yFu5DTvO02bZbX9rQ60=; b=ritrDx7Adiej3aIucm2b+2BrZOcWh5rF5rC75hER9oZ11fHuV+fOKu+4cBriRxyd4q LHb6sx8IBxkXiDVXYLiA1v3Bdr15f8kdIxVm87kjxmtakEDhUFch2o/VRRc3H6qgtXAt aPx11VfhZjYrMi0QLoAeR+pqZPTwLk4ljcAvjmkwGMWkMW4Z5Gevn61rC0UIY1tT2W9B HHTq9cCq3fn51XfbDJ2NyTp87ycgJQRsylV1B/Bo6nRx+NHhg07r75+0Jzpxt8mgRbrh iav+fWc8lVczM3csXudQ8rMznkobC+FhLLDPKCvBuBy45y/AMuPrZyODW0cxKefACq5K P+1g== X-Gm-Message-State: AOAM532gCUNK84EIJzL6hOxfZTmTgJJ6S7gKbhTTorvdE/D2JfkVX0Jd 2rNBvy29VohN7wBalDK6rU/4W5xAnmo= X-Google-Smtp-Source: ABdhPJynK0ctyByAJfgIDSu/xry2TRNT183MIQVuC35tvoIP+7iyYponrgg8I7mldBSWKyvfNkAtGg== X-Received: by 2002:a5d:6da6:: with SMTP id u6mr5000789wrs.563.1642792347272; Fri, 21 Jan 2022 11:12:27 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m6sm7760247wms.34.2022.01.21.11.12.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:26 -0800 (PST) Message-Id: <6b535a4d55a864a0294ed0e881ecd035bd685117.1642792341.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:15 +0000 Subject: [PATCH v4 05/10] merge-ort: mark a few more conflict messages as omittable Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren path_msg() has the ability to mark messages as omittable, designed for remerge-diff where we'll instead be showing conflict messages as diff headers for a subsequent diff. While all these messages are very useful when trying to create a merge initially, early use with the --remerge-diff feature (the only user of this omittable conflict message capability), suggests that the particular messages marked in this commit are just noise when trying to see what changes users made to create a merge commit. Mark them as omittable. Note that there were already a few messages marked as omittable in merge-ort when doing a remerge-diff, because the development of --remerge-diff preceded the upstreaming of merge-ort and I was trying to ensure merge-ort could handle all the necessary requirements. See commit c5a6f65527 ("merge-ort: add modify/delete handling and delayed output processing", 2020-12-03) for the initial details. For some examples of already-marked-as-omittable messages, see either "Auto-merging " or some of the submodule update hints. This commit just adds two more messages that should also be omittable. Signed-off-by: Elijah Newren --- merge-ort.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index a18f47e23c5..998e92ec593 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -2420,7 +2420,7 @@ static void apply_directory_rename_modifications(struct merge_options *opt, */ ci->path_conflict = 1; if (pair->status == 'A') - path_msg(opt, new_path, 0, + path_msg(opt, new_path, 1, _("CONFLICT (file location): %s added in %s " "inside a directory that was renamed in %s, " "suggesting it should perhaps be moved to " @@ -2428,7 +2428,7 @@ 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, 0, + path_msg(opt, new_path, 1, _("CONFLICT (file location): %s renamed to %s " "in %s, inside a directory that was renamed " "in %s, suggesting it should perhaps be " From patchwork Fri Jan 21 19:12:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720146 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 D6EA0C433FE for ; Fri, 21 Jan 2022 19:12:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231906AbiAUTMe (ORCPT ); Fri, 21 Jan 2022 14:12:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231822AbiAUTMa (ORCPT ); Fri, 21 Jan 2022 14:12:30 -0500 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 A880FC06173B for ; Fri, 21 Jan 2022 11:12:29 -0800 (PST) Received: by mail-wr1-x431.google.com with SMTP id s4so500264wrb.0 for ; Fri, 21 Jan 2022 11:12:29 -0800 (PST) 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=Jt+pEdaNvy6+eLb7fLZGKq6uyZ8j2uRNVRhVEtft+jI=; b=LKEucIYQ5/Cg3BJiFTcDAAEZo/dnHDReoUBILaukasUCadShIhQEmErr9xa+uU+gpi 4Kc2+K6Fq5d8RRTlzUTBECPaWd5rh03SFoMG69je9/RgK05JMnAmG9Lqfs8iKZyNYtE1 DSMu5gqLoubLHeEfE8ygMVdzmpETOqXiZVq265Hekmc2fWK9uPO2CGbWqTCejenqVXgF XwDKKZxH+i1WbiM7n525LRdr+WKcne4WLarD8rPZGxj4fDl7PXkHhxeOtbN4uQ4RHdWn yQnPGZ54raxMqa8gVOShrjJ8ppiyAFezTB0PrKJmSUTE87SejTWUCIKO92vHopserZTJ jVJA== 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=Jt+pEdaNvy6+eLb7fLZGKq6uyZ8j2uRNVRhVEtft+jI=; b=TkcVhtU2ahzE5/7wTlLuSAJYR8u33a4zAUr5y9BkLrj/JQY4JdQyYoq8qfjgpTmavn 7wDVyDWgA+jbixeP7rrHKJpy/jQuSjkr/zcBsEEQJZA4Wy0+DBG1fcaHmqYSj3mSzxVh vldFxl+eaM/yT9PQxChpdhbyJ5KnRJBHBaKtJ++zS0ggDDNdmgIAI8/rqx1AB7danSYJ L2v7xggF6G7OHvkV43yC1SXM5PjnxtaC6c9T+bSkPjmsLWoiKfHJc2peMJ1LfNkc28xH HO2brjeEG9Me6jGS0Naj4HqJ7RgY/Ac1oXuhSKioT4S0fabc2pqwXPKWrM0VzQDQa5zM ktGw== X-Gm-Message-State: AOAM532/WHkgzcB7cpecoVH9/d1Gbdpu2puTO/DXvlqcKXurJmoNBjsq 7gmcCavkFpFupD+GVzhlm2PFg7zv9To= X-Google-Smtp-Source: ABdhPJzZH1knF2HXU+1SfdFK4z5y02isq7vvXAPWbgDOorQJ2R2hf1fh81xS3SoSrIEgtq8GaFLbqw== X-Received: by 2002:a05:6000:1548:: with SMTP id 8mr4967375wry.66.1642792348062; Fri, 21 Jan 2022 11:12:28 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id a18sm6887725wrw.5.2022.01.21.11.12.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:27 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:16 +0000 Subject: [PATCH v4 06/10] merge-ort: format messages slightly different for use in headers Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren When users run git show --remerge-diff $MERGE_COMMIT or git log -p --remerge-diff ... stdout is not an appropriate location to dump conflict messages, but we do want to provide them to users. We will include them in the diff headers instead...but for that to work, we need for any multiline messages to replace newlines with both a newline and a space. Add a new flag to signal when we want these messages modified in such a fashion, and use it in path_msg() to modify these messages this way. Also, allow a special prefix to be specified for these headers. Signed-off-by: Elijah Newren --- merge-ort.c | 42 ++++++++++++++++++++++++++++++++++++++++-- merge-recursive.c | 4 ++++ merge-recursive.h | 2 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/merge-ort.c b/merge-ort.c index 998e92ec593..481305d2bcf 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -634,17 +634,49 @@ static void path_msg(struct merge_options *opt, const char *fmt, ...) { va_list ap; - struct strbuf *sb = strmap_get(&opt->priv->output, path); + struct strbuf *sb, *dest; + struct strbuf tmp = STRBUF_INIT; + + if (opt->record_conflict_msgs_as_headers && omittable_hint) + return; /* Do not record mere hints in tree */ + sb = strmap_get(&opt->priv->output, path); if (!sb) { sb = xmalloc(sizeof(*sb)); strbuf_init(sb, 0); strmap_put(&opt->priv->output, path, sb); } + dest = (opt->record_conflict_msgs_as_headers ? &tmp : sb); + va_start(ap, fmt); - strbuf_vaddf(sb, fmt, ap); + strbuf_vaddf(dest, fmt, ap); va_end(ap); + 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); + + /* Copy tmp to sb, adding spaces after newlines */ + strbuf_grow(sb, sb->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]; + + /* If we copied a newline, add a space */ + if (tmp.buf[i_tmp] == '\n') + sb->buf[++i_sb] = ' '; + } + /* Update length and ensure it's NUL-terminated */ + sb->len += i_sb; + sb->buf[sb->len] = '\0'; + + strbuf_release(&tmp); + } + + /* Add final newline character to sb */ strbuf_addch(sb, '\n'); } @@ -4246,6 +4278,9 @@ void merge_switch_to_result(struct merge_options *opt, 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 */ @@ -4347,6 +4382,9 @@ static void merge_start(struct merge_options *opt, struct merge_result *result) assert(opt->recursive_variant >= MERGE_VARIANT_NORMAL && opt->recursive_variant <= MERGE_VARIANT_THEIRS); + if (opt->msg_header_prefix) + assert(opt->record_conflict_msgs_as_headers); + /* * detect_renames, verbosity, buffer_output, and obuf are ignored * fields that were used by "recursive" rather than "ort" -- but diff --git a/merge-recursive.c b/merge-recursive.c index bc73c52dd84..9ec1e6d043a 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -3714,6 +3714,10 @@ static int merge_start(struct merge_options *opt, struct tree *head) assert(opt->priv == NULL); + /* Not supported; option specific to merge-ort */ + assert(!opt->record_conflict_msgs_as_headers); + assert(!opt->msg_header_prefix); + /* Sanity check on repo state; index must match head */ if (repo_index_has_changes(opt->repo, head, &sb)) { err(opt, _("Your local changes to the following files would be overwritten by merge:\n %s"), diff --git a/merge-recursive.h b/merge-recursive.h index 0795a1d3ec1..b88000e3c25 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -46,6 +46,8 @@ struct merge_options { /* miscellaneous control options */ const char *subtree_shift; unsigned renormalize : 1; + unsigned record_conflict_msgs_as_headers : 1; + const char *msg_header_prefix; /* internal fields used by the implementation */ struct merge_options_internal *priv; From patchwork Fri Jan 21 19:12:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720147 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 7069DC433EF for ; Fri, 21 Jan 2022 19:12:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232008AbiAUTMg (ORCPT ); Fri, 21 Jan 2022 14:12:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231482AbiAUTMb (ORCPT ); Fri, 21 Jan 2022 14:12:31 -0500 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B32ADC06173D for ; Fri, 21 Jan 2022 11:12:30 -0800 (PST) Received: by mail-wm1-x32e.google.com with SMTP id o1-20020a1c4d01000000b0034d95625e1fso15443045wmh.4 for ; Fri, 21 Jan 2022 11:12:30 -0800 (PST) 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=2NmfFQRBnIwE//dIuq0V8oIvdy2aUwh7Fz41UnhXWvA=; b=HkHOAZkISTkU3Ij8RtW6zt9e7w22II7T85DSCzEyawRs1sTxQiArYgCjYGdx2RWW41 KkcetNL36feGmgvTGdHWHQMTuWsV1d4YRaILqCIo7/VZduBpPA95RZODvScVmK7nlhYx twlPDoxPMQAdI+BtgbdQN5Op3eJpVx1X3BkKdHGSGd5HMN6IZ/Jp2wolHch+5OrvRxf1 pde7M60xrQH8/PsGnBAxYbXh/erKWcagLXlgof0bxVqO0B+etxn37Bn7eNOaVxJwf8Aj 6zukOeyvMr4CCIyiZSGX/6pTb6s+NzKaqOLc02zaanEAO+VFujJph435gwSzQDbOk2EH t3EQ== 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=2NmfFQRBnIwE//dIuq0V8oIvdy2aUwh7Fz41UnhXWvA=; b=FRye7+qHwcEftRZStDT+/O0gmhw4nY+DBeIsbV1yqp0oC2TCOFL827fTS2IhO0HoQ9 ONqNjX3aD+lr3fe5j3oh0NxINLUkF7Equroy8J3z/0ZE03IkUBPOekueKsfREyrnMKD1 AoSeglE2/KRMaIczAWNlVu2++7VgpanmhGf0VfJbs8gBMxU94gzNh4lglVU5d0MOFGhY Mx3iVdH0MGwXwqtOOxq8k/8/4ebxDCuUjE8U1IPXXYCQu3t1AiNlHzpW0sUHZ7jWeG7m m4hoHBQBGcWs5F1P7lG13YB9VHGPGzdUL6bcSA0MHP2zSIPRyjR62fwF2sPvF2gmTpau hSbA== X-Gm-Message-State: AOAM532LRH6/SFFCwuMaSMJU0hjvuHIbg8xBL2TIWr6nkLfdIB49gSZR IdthbqVUl7gVcAiI+NxtPTzHDd6ZhrY= X-Google-Smtp-Source: ABdhPJzB/U7faHwAi7FXg27rP6N0zKImi1n2lAPmlVF8oJtMdmkJBlq9eYfiR24Qtl8wJ6g7Sr/ClQ== X-Received: by 2002:a05:600c:1987:: with SMTP id t7mr1948919wmq.124.1642792349052; Fri, 21 Jan 2022 11:12:29 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n14sm6929858wri.101.2022.01.21.11.12.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:28 -0800 (PST) Message-Id: <62734beb693a6a6256106f0ffad9519a76c9d6d8.1642792341.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:17 +0000 Subject: [PATCH v4 07/10] diff: add ability to insert additional headers for paths Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren When additional headers are provided, we need to * add diff_filepairs to diff_queued_diff for each paths in the additional headers map which, unless that path is part of another diff_filepair already found in diff_queued_diff * format the headers (colorization, line_prefix for --graph) * make sure the various codepaths that attempt to return early if there are "no changes" take into account the headers that need to be shown. Signed-off-by: Elijah Newren --- diff.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++-- diff.h | 3 +- log-tree.c | 2 +- 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/diff.c b/diff.c index 861282db1c3..1bfb01c18ec 100644 --- a/diff.c +++ b/diff.c @@ -27,6 +27,7 @@ #include "help.h" #include "promisor-remote.h" #include "dir.h" +#include "strmap.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -3406,6 +3407,31 @@ 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) +{ + 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, + const char *line_prefix, + const char *meta, + const char *reset) +{ + char *next, *newline; + + for (next = more_headers->buf; *next; next = newline) { + newline = strchrnul(next, '\n'); + strbuf_addf(msg, "%s%s%.*s%s\n", line_prefix, meta, + (int)(newline - next), next, reset); + if (*newline) + newline++; + } +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -3464,6 +3490,17 @@ static void builtin_diff(const char *name_a, b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + if (!DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two)) { + /* + * We should only reach this point for pairs from + * create_filepairs_for_header_only_notifications(). For + * these, we should avoid the "/dev/null" special casing + * above, meaning we avoid showing such pairs as either + * "new file" or "deleted file" below. + */ + lbl[0] = a_one; + lbl[1] = b_two; + } strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset); if (lbl[0][0] == '/') { /* /dev/null */ @@ -4328,6 +4365,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; *must_show_header = 1; strbuf_init(msg, PATH_MAX * 2 + 300); @@ -4364,6 +4402,11 @@ static void fill_metainfo(struct strbuf *msg, default: *must_show_header = 0; } + if ((more_headers = additional_headers(o, name))) { + add_formatted_headers(msg, more_headers, + line_prefix, set, reset); + *must_show_header = 1; + } if (one && two && !oideq(&one->oid, &two->oid)) { const unsigned hexsz = the_hash_algo->hexsz; int abbrev = o->abbrev ? o->abbrev : DEFAULT_ABBREV; @@ -5852,12 +5895,27 @@ int diff_unmodified_pair(struct diff_filepair *p) static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o) { - if (diff_unmodified_pair(p)) + int include_conflict_headers = + (additional_headers(o, p->one->path) && + (!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o))); + + /* + * Check if we can return early without showing a diff. Note that + * diff_filepair only stores {oid, path, mode, is_valid} + * information for each path, and thus diff_unmodified_pair() only + * considers those bits of info. However, we do not want pairs + * created by create_filepairs_for_header_only_notifications() + * (which always look like unmodified pairs) to be ignored, so + * return early if both p is unmodified AND we don't want to + * include_conflict_headers. + */ + if (diff_unmodified_pair(p) && !include_conflict_headers) return; + /* Actually, we can also return early to avoid showing tree diffs */ if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) - return; /* no tree diffs in patch format */ + return; run_diff(p, o); } @@ -5888,10 +5946,17 @@ static void diff_flush_checkdiff(struct diff_filepair *p, run_checkdiff(p, o); } -int diff_queue_is_empty(void) +int diff_queue_is_empty(struct diff_options *o) { struct diff_queue_struct *q = &diff_queued_diff; int i; + int include_conflict_headers = + (o->additional_path_headers && + (!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o))); + + if (include_conflict_headers) + return 0; + for (i = 0; i < q->nr; i++) if (!diff_unmodified_pair(q->queue[i])) return 0; @@ -6325,6 +6390,54 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc) warning(_(rename_limit_advice), varname, needed); } +static void create_filepairs_for_header_only_notifications(struct diff_options *o) +{ + struct strset present; + struct diff_queue_struct *q = &diff_queued_diff; + struct hashmap_iter iter; + struct strmap_entry *e; + int i; + + strset_init_with_options(&present, /*pool*/ NULL, /*strdup*/ 0); + + /* + * Find out which paths exist in diff_queued_diff, preferring + * one->path for any pair that has multiple paths. + */ + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + char *path = p->one->path ? p->one->path : p->two->path; + + if (strmap_contains(o->additional_path_headers, path)) + strset_add(&present, path); + } + + /* + * Loop over paths in additional_path_headers; for each NOT already + * in diff_queued_diff, create a synthetic filepair and insert that + * into diff_queued_diff. + */ + strmap_for_each_entry(o->additional_path_headers, &iter, e) { + if (!strset_contains(&present, e->key)) { + struct diff_filespec *one, *two; + struct diff_filepair *p; + + one = alloc_filespec(e->key); + two = alloc_filespec(e->key); + fill_filespec(one, null_oid(), 0, 0); + fill_filespec(two, null_oid(), 0, 0); + p = diff_queue(q, one, two); + p->status = DIFF_STATUS_MODIFIED; + } + } + + /* Re-sort the filepairs */ + diffcore_fix_diff_index(); + + /* Cleanup */ + strset_clear(&present); +} + static void diff_flush_patch_all_file_pairs(struct diff_options *o) { int i; @@ -6337,6 +6450,9 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) if (o->color_moved) o->emitted_symbols = &esm; + if (o->additional_path_headers) + create_filepairs_for_header_only_notifications(o); + for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (check_pair_status(p)) @@ -6413,7 +6529,7 @@ void diff_flush(struct diff_options *options) * Order: raw, stat, summary, patch * or: name/name-status/checkdiff (other bits clear) */ - if (!q->nr) + if (!q->nr && !options->additional_path_headers) goto free_queue; if (output_format & (DIFF_FORMAT_RAW | diff --git a/diff.h b/diff.h index 8ba85c5e605..ce9e2cf2e4f 100644 --- a/diff.h +++ b/diff.h @@ -395,6 +395,7 @@ struct diff_options { struct repository *repo; struct option *parseopts; + struct strmap *additional_path_headers; int no_free; }; @@ -593,7 +594,7 @@ void diffcore_fix_diff_index(void); " show all files diff when -S is used and hit is found.\n" \ " -a --text treat all files as text.\n" -int diff_queue_is_empty(void); +int diff_queue_is_empty(struct diff_options *o); void diff_flush(struct diff_options*); void diff_free(struct diff_options*); void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc); diff --git a/log-tree.c b/log-tree.c index d4655b63d75..33c28f537a6 100644 --- a/log-tree.c +++ b/log-tree.c @@ -850,7 +850,7 @@ int log_tree_diff_flush(struct rev_info *opt) opt->shown_dashes = 0; diffcore_std(&opt->diffopt); - if (diff_queue_is_empty()) { + if (diff_queue_is_empty(&opt->diffopt)) { int saved_fmt = opt->diffopt.output_format; opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; diff_flush(&opt->diffopt); From patchwork Fri Jan 21 19:12:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720148 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 638DBC433EF for ; Fri, 21 Jan 2022 19:12:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232270AbiAUTMk (ORCPT ); Fri, 21 Jan 2022 14:12:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52918 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231867AbiAUTMc (ORCPT ); Fri, 21 Jan 2022 14:12:32 -0500 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 B4C78C06173D for ; Fri, 21 Jan 2022 11:12:31 -0800 (PST) Received: by mail-wr1-x436.google.com with SMTP id q22so1411540wrc.5 for ; Fri, 21 Jan 2022 11:12:31 -0800 (PST) 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=TQX4ItZuNiKm8OI0It4i2/2ZCmlC3lFDheQASMMIr7c=; b=k9B1oHWO12gPovIwpgciEkvSSAhEr957ap+hbfQD2cRq0vNMqa04zJfkdouYeBOw+E w7yQUU1o+SIBozkOUZKY0hVzxfXnbxMlTNs4xT/lQyWApS/5fbHx17+lHncYjFo+fXWk vD947If8AUEUu46jWhk+oDXov5VeWOZnOS6pLm9PnutQzMu0Mx5posMXATyG67LCVfVB ita7l6pMVzfT30saipup04wQ4UZzK1voigAux/11DswN1aHi2ho4A5gTjJer5QHoSkAx MZRnAQhMXsA97mH0lQ65YpnpN2hMSL3TKamvG8yD7OcZxdlKCUdTSsZAqm8xF77EtHSb bQpQ== 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=TQX4ItZuNiKm8OI0It4i2/2ZCmlC3lFDheQASMMIr7c=; b=SzfNt8WTTLppe6VyK29mqQnzby8olcfCASgnOjaXSobMQtVp6DybekNof5040fafXb EsLAhC7LRYixaAjtkofg9/a1lI3759Kld/5XoHk8kFiSigdxGVwt3kdH4yjUxJgHYnLs NPOwauZaTG7BJZLv9l4qWYFq5uXVYV6aI4gtsdb0vTn4TEbQYc1iRSpVupS/W8xA37dM riLSX1wKeB0Ji15bUDibq5JiNX+t0vfw2o3bc9kgs9FbjiranQtcUbGQ/+1FuGCHyb10 qdlTmi8D075uXiQav1tyIPHPMutdS943hw3ff2i0+QjrQcsqd0oE2iCKmuV614Pjiy6q YXZA== X-Gm-Message-State: AOAM5311lOLgSz00zg98k/+bDnaydDCV1CXCVd2Ib+wZLAUcOjiRveVL A8ZVEXfv6t7a+7QbuvyJEYT5CVkCpX0= X-Google-Smtp-Source: ABdhPJx9OCnFP3W9TUxdfs3o4bEU4AE8VbVm6KgsJYgAd0k2UQE+KkTFyTnVQVP5UXw1TC6O8QGSww== X-Received: by 2002:a5d:5985:: with SMTP id n5mr4916150wri.309.1642792349983; Fri, 21 Jan 2022 11:12:29 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id y15sm7751896wrd.22.2022.01.21.11.12.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:29 -0800 (PST) Message-Id: <17eccf7e0d6daed2c0934c481d6a52c5a77a0d34.1642792341.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:18 +0000 Subject: [PATCH v4 08/10] show, log: include conflict/warning messages in --remerge-diff headers Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Conflicts such as modify/delete, rename/rename, or file/directory are not representable via content conflict markers, and the normal output messages notifying users about these were dropped with --remerge-diff. While we don't want these messages randomly shown before the commit and diff headers, we do want them to still be shown; include them as part of the diff headers instead. Signed-off-by: Elijah Newren --- log-tree.c | 51 ++++++++++++++ merge-ort.c | 1 + merge-ort.h | 10 +++ t/t4069-remerge-diff.sh | 144 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+) diff --git a/log-tree.c b/log-tree.c index 33c28f537a6..85bfd9e50d8 100644 --- a/log-tree.c +++ b/log-tree.c @@ -19,6 +19,7 @@ #include "line-log.h" #include "help.h" #include "range-diff.h" +#include "strmap.h" static struct decoration name_decoration = { "object names" }; static int decoration_loaded; @@ -905,6 +906,52 @@ static int do_diff_combined(struct rev_info *opt, struct commit *commit) return !opt->loginfo; } +static void setup_additional_headers(struct diff_options *o, + struct strmap *all_headers) +{ + struct hashmap_iter iter; + struct strmap_entry *entry; + + /* + * Make o->additional_path_headers contain the subset of all_headers + * that match o->pathspec. If there aren't any that match o->pathspec, + * then make o->additional_path_headers be NULL. + */ + + if (!o->pathspec.nr) { + o->additional_path_headers = all_headers; + return; + } + + o->additional_path_headers = xmalloc(sizeof(struct strmap)); + strmap_init_with_options(o->additional_path_headers, NULL, 0); + strmap_for_each_entry(all_headers, &iter, entry) { + if (match_pathspec(the_repository->index, &o->pathspec, + entry->key, strlen(entry->key), + 0 /* prefix */, NULL /* seen */, + 0 /* is_dir */)) + strmap_put(o->additional_path_headers, + entry->key, entry->value); + } + if (!strmap_get_size(o->additional_path_headers)) { + strmap_clear(o->additional_path_headers, 0); + FREE_AND_NULL(o->additional_path_headers); + } +} + +static void cleanup_additional_headers(struct diff_options *o) +{ + if (!o->pathspec.nr) { + o->additional_path_headers = NULL; + return; + } + if (!o->additional_path_headers) + return; + + strmap_clear(o->additional_path_headers, 0); + FREE_AND_NULL(o->additional_path_headers); +} + static int do_remerge_diff(struct rev_info *opt, struct commit_list *parents, struct object_id *oid, @@ -922,6 +969,8 @@ static int do_remerge_diff(struct rev_info *opt, /* Setup merge options */ init_merge_options(&o, the_repository); o.show_rename_progress = 0; + o.record_conflict_msgs_as_headers = 1; + o.msg_header_prefix = "remerge"; ctx.abbrev = DEFAULT_ABBREV; format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx); @@ -938,10 +987,12 @@ static int do_remerge_diff(struct rev_info *opt, merge_incore_recursive(&o, bases, parent1, parent2, &res); /* Show the diff */ + setup_additional_headers(&opt->diffopt, res.path_messages); diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt); log_tree_diff_flush(opt); /* Cleanup */ + cleanup_additional_headers(&opt->diffopt); strbuf_release(&parent1_desc); strbuf_release(&parent2_desc); merge_finalize(&o, &res); diff --git a/merge-ort.c b/merge-ort.c index 481305d2bcf..43f980d2586 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4585,6 +4585,7 @@ redo: trace2_region_leave("merge", "process_entries", opt->repo); /* Set return values */ + result->path_messages = &opt->priv->output; 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 c011864ffeb..fe599b87868 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -5,6 +5,7 @@ struct commit; struct tree; +struct strmap; struct merge_result { /* @@ -23,6 +24,15 @@ struct merge_result { */ struct tree *tree; + /* + * Special messages and conflict notices for various paths + * + * 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. + */ + struct strmap *path_messages; + /* * Additional metadata used by merge_switch_to_result() or future calls * to merge_incore_*(). Includes data needed to update the index (if diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh index 5ef191f4fc9..86c5a33bd77 100755 --- a/t/t4069-remerge-diff.sh +++ b/t/t4069-remerge-diff.sh @@ -59,6 +59,7 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated git log -1 --oneline ab_resolution >tmp && cat <<-EOF >>tmp && diff --git a/numbers b/numbers + remerge CONFLICT (content): Merge conflict in numbers index a1fb731..6875544 100644 --- a/numbers +++ b/numbers @@ -87,4 +88,147 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated test_cmp expect actual ' +test_expect_success 'setup non-content conflicts' ' + git switch --orphan base && + + test_write_lines 1 2 3 4 5 6 7 8 9 >numbers && + test_write_lines a b c d e f g h i >letters && + test_write_lines in the way >content && + git add numbers letters content && + git commit -m base && + + git branch side1 && + git branch side2 && + + git checkout side1 && + test_write_lines 1 2 three 4 5 6 7 8 9 >numbers && + git mv letters letters_side1 && + git mv content file_or_directory && + git add numbers && + git commit -m side1 && + + git checkout side2 && + git rm numbers && + git mv letters letters_side2 && + mkdir file_or_directory && + echo hello >file_or_directory/world && + git add file_or_directory/world && + git commit -m side2 && + + git checkout -b resolution side1 && + test_must_fail git merge side2 && + test_write_lines 1 2 three 4 5 6 7 8 9 >numbers && + git add numbers && + git add letters_side1 && + git rm letters && + git rm letters_side2 && + git add file_or_directory~HEAD && + git mv file_or_directory~HEAD wanted_content && + git commit -m resolved +' + +test_expect_success 'remerge-diff with non-content conflicts' ' + git log -1 --oneline resolution >tmp && + cat <<-EOF >>tmp && + diff --git a/file_or_directory~HASH (side1) b/wanted_content + similarity index 100% + rename from file_or_directory~HASH (side1) + rename to wanted_content + remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead. + diff --git a/letters b/letters + remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2). + diff --git a/letters_side2 b/letters_side2 + deleted file mode 100644 + index b236ae5..0000000 + --- a/letters_side2 + +++ /dev/null + @@ -1,9 +0,0 @@ + -a + -b + -c + -d + -e + -f + -g + -h + -i + diff --git a/numbers b/numbers + remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree. + EOF + # We still have some sha1 hashes above; rip them out so test works + # with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff resolution >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + +test_expect_success 'remerge-diff w/ diff-filter=U: all conflict headers, no diff content' ' + git log -1 --oneline resolution >tmp && + cat <<-EOF >>tmp && + diff --git a/file_or_directory~HASH (side1) b/file_or_directory~HASH (side1) + remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead. + diff --git a/letters b/letters + remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2). + diff --git a/numbers b/numbers + remerge CONFLICT (modify/delete): numbers deleted in HASH (side2) and modified in HASH (side1). Version HASH (side1) of numbers left in tree. + EOF + # We still have some sha1 hashes above; rip them out so test works + # with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff --diff-filter=U resolution >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + +test_expect_success 'remerge-diff w/ diff-filter=R: relevant file + conflict header' ' + git log -1 --oneline resolution >tmp && + cat <<-EOF >>tmp && + diff --git a/file_or_directory~HASH (side1) b/wanted_content + similarity index 100% + rename from file_or_directory~HASH (side1) + rename to wanted_content + remerge CONFLICT (file/directory): directory in the way of file_or_directory from HASH (side1); moving it to file_or_directory~HASH (side1) instead. + EOF + # We still have some sha1 hashes above; rip them out so test works + # with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff --diff-filter=R resolution >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + +test_expect_success 'remerge-diff w/ pathspec: limits to relevant file including conflict header' ' + git log -1 --oneline resolution >tmp && + cat <<-EOF >>tmp && + diff --git a/letters b/letters + remerge CONFLICT (rename/rename): letters renamed to letters_side1 in HASH (side1) and to letters_side2 in HASH (side2). + diff --git a/letters_side2 b/letters_side2 + deleted file mode 100644 + index b236ae5..0000000 + --- a/letters_side2 + +++ /dev/null + @@ -1,9 +0,0 @@ + -a + -b + -c + -d + -e + -f + -g + -h + -i + EOF + # We still have some sha1 hashes above; rip them out so test works + # with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff --full-history resolution -- "letters*" >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + test_done From patchwork Fri Jan 21 19:12:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720149 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 55769C433F5 for ; Fri, 21 Jan 2022 19:12:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231995AbiAUTMn (ORCPT ); Fri, 21 Jan 2022 14:12:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52946 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232022AbiAUTMh (ORCPT ); Fri, 21 Jan 2022 14:12:37 -0500 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CCDFAC061749 for ; Fri, 21 Jan 2022 11:12:32 -0800 (PST) Received: by mail-wr1-x42a.google.com with SMTP id ba4so1402496wrb.4 for ; Fri, 21 Jan 2022 11:12:32 -0800 (PST) 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=rB1GXXgaPG4nqGNrl25zZ0WJDHbu4Z/7BmEvF3+puqs=; b=Netui/c1wW9OvewIOxyTIs8oXoryw5Bo7gYC0Yt9SNQjCPes0CwDaTYiqMboqTqKFI LSEw3EBcJi9sgZUMOzmDHj4WYxgssK5lfWo7/ffktMPqo+w0gxBUYlSrQxItXdeZF4Gm MtcD3ZQ5E6x1D5/lzBHU/HLivBzRrXsXl9fuw36jn8JWxfkKf4WQ6G8Hq9ZBa+PW6k0c jhQyMPpjpqvhogRy5ujjClu4a4AND+lhBeJP6MTW17FzzCQlQM7pwgQgEyHRECeHEbHW f1JAlJPu3m4CG3LpkK3xDjUT5561b4pJsQqgW1LRagwqqM+N7Hh+RHVDIwu31Xg7SgpR WWJw== 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=rB1GXXgaPG4nqGNrl25zZ0WJDHbu4Z/7BmEvF3+puqs=; b=zE9VPrTDuWXe0QhAX2lll4kSw1M2LXFOVAHq3xgpIJVi7eztBGqUYOp5djNDcedXEp bvPIlFX8TPKRq+tudd8hHIc94OIAMFa2C7wiaSPft0SbJLMMhJBkt3H6ups/QHK2xJLl rYluIszTl6r9qeUD76KL3NcDJxSHfE/k5WO1MpflMsg2W5W+H9q0Q9ue+e1EoOKobj6k rPLLuH3EwkTrrCfR4DQT8ZdSfXPBKpj93mxiYG5HeNXh4t/ErLRB2Xcq0DqVu2PBvhqP tFtG8UzghZLzzoVYCuWjR4dZhDpWDbix55YZa3KDFPd5V245ZUUODNZQXicKtGkMb9+e Bmlg== X-Gm-Message-State: AOAM532D9QD5I5q+1WCp4bosxq2eUr1KmaGpGKLjtkuATPEdWejC0FSS UGjatpzlTcJQZ7urEXi2NuKCcVsfy+Q= X-Google-Smtp-Source: ABdhPJyeYSHVKTjMjdcVu2P0rSBIRXBwhVUBW2pMBuMc5WKRJMprt7HI424l2uBCsD2FX/ara+auHA== X-Received: by 2002:a05:6000:1686:: with SMTP id y6mr5019950wrd.205.1642792351307; Fri, 21 Jan 2022 11:12:31 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z23sm5591990wmk.46.2022.01.21.11.12.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:30 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:19 +0000 Subject: [PATCH v4 09/10] merge-ort: mark conflict/warning messages from inner merges as omittable Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren A recursive merge involves merging the merge bases of the two branches being merged. Such an inner merge can itself generate conflict notices. While such notices may be useful when initially trying to create a merge, they seem to just be noise when investigating merges later with --remerge-diff. (Especially when both sides of the outer merge resolved the conflict the same way leading to no overall conflict.) Remove them. Signed-off-by: Elijah Newren --- merge-ort.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/merge-ort.c b/merge-ort.c index 43f980d2586..9bf15a01db8 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -638,7 +638,9 @@ static void path_msg(struct merge_options *opt, struct strbuf tmp = STRBUF_INIT; if (opt->record_conflict_msgs_as_headers && omittable_hint) - return; /* Do not record mere hints in tree */ + return; /* Do not record mere hints in headers */ + if (opt->record_conflict_msgs_as_headers && opt->priv->call_depth) + return; /* Do not record inner merge issues in headers */ sb = strmap_get(&opt->priv->output, path); if (!sb) { sb = xmalloc(sizeof(*sb)); From patchwork Fri Jan 21 19:12:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 12720150 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 2A80FC433EF for ; Fri, 21 Jan 2022 19:12:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232110AbiAUTMo (ORCPT ); Fri, 21 Jan 2022 14:12:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232082AbiAUTMi (ORCPT ); Fri, 21 Jan 2022 14:12:38 -0500 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C0D9BC061753 for ; Fri, 21 Jan 2022 11:12:33 -0800 (PST) Received: by mail-wr1-x42f.google.com with SMTP id r14so1409687wrp.2 for ; Fri, 21 Jan 2022 11:12:33 -0800 (PST) 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=s2JPqRuN+jwFI7QheNwS1Q7ImdG548HewkzmJnYY9u8=; b=YSxSHOl6ARLKMOui45hVHfteqkGPEy/dmT6cz3clX+0Y7GkA6lj6H1HXsJPTQA7ybQ +hWhTCGKQE+cGVak22TZOET86Ya8jnS50yzV1tSKaeaTVeSDjS5o8Lo5IpPId+JyQrTa vQr8VHng9xTpqD2NNMcEfFvUpStY9eH4WHcu4W+9ks32sH0iKiVQaKMw3psY05RwwCQl u3hU3mRmRruWUEKBh+IDmU6RSovchTkfgwJ6Hi0aGSgxgvnA4N/LvvJRpaUs7EOrnAcW gXsm4718Jg7GLa4oZcjKBGWTP58W/FmcceNvlyCdwsn1W311GZhRUwMwTozGmXC+vweN 192g== 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=s2JPqRuN+jwFI7QheNwS1Q7ImdG548HewkzmJnYY9u8=; b=dhjQ5xA+H0UhSxU1gUXIwr/h0Ax2vXec2t0lag+mHOZSrj0RBnLyh6Fl5x2oAiilEu 9ZbF5bc08QB52f2iFos2FsUlruxG2B5UiD5aERQ7IdbjRrWdgprA6Kvisu/oItuApUi6 io5l+oVo32x5Kdo6ZgRLep32W1OgPpIbU1+Zn0z4SwlT2BGWe7cif7fCw0KJlwZHMOT8 A/KFWk81B4qTJcaQ5jXLcIFFY4Gh5y0UGBfW8BNOyS4A4qBuCKiKA46RMKd+zndAEjAc wpl5pH/CQHMFbxdRzSm3XNtIX6+jlQ3bBcoMFtwGqT4j7i+arrrP3YfFoxoyZSI53hZS pTUw== X-Gm-Message-State: AOAM5334tOh0ie4iBvEIVDZRHf+CHsy7YRdApxkkkl3kN8tUo/ERb+0G eSWXizwuhcssbqIYRgOspDsOEDJNkmk= X-Google-Smtp-Source: ABdhPJzH0WwjHX720mplRKwGuETVcf3JVgSfEn4rsH4A+dbBttNQax9n0RCflp/Q2Z4LaY8QmdhBBQ== X-Received: by 2002:a05:6000:1549:: with SMTP id 9mr4862979wry.704.1642792352201; Fri, 21 Jan 2022 11:12:32 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i19sm5731146wml.29.2022.01.21.11.12.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jan 2022 11:12:31 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 21 Jan 2022 19:12:20 +0000 Subject: [PATCH v4 10/10] diff-merges: avoid history simplifications when diffing merges Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Jonathan Nieder , Sergey Organov , Bagas Sanjaya , Elijah Newren , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Neeraj Singh , Johannes Altmanninger , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Doing diffs for merges are special; they should typically avoid history simplification. For example, with git log --diff-merges=first-parent -- path the default history simplification would remove merge commits from consideration if the file "path" matched the second parent. That is counter to what the user wants when looking for first-parent diffs. Similar comments can be made for --diff-merges=separate (which diffs against both parents) and --diff-merges=remerge (which diffs against a remerge of the merge commit). However, history simplification still makes sense if not doing diffing merges, and it also makes sense for the combined and dense-combined forms of diffing merges (because both of those are defined to only show a diff when the merge result at the relevant paths differs from *both* parents). So, for separate, first-parent, and remerge styles of diff-merges, turn off history simplification. Signed-off-by: Elijah Newren --- diff-merges.c | 2 ++ t/t4069-remerge-diff.sh | 58 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/diff-merges.c b/diff-merges.c index 0af4b3f9191..a833fd747ad 100644 --- a/diff-merges.c +++ b/diff-merges.c @@ -24,6 +24,7 @@ static void set_separate(struct rev_info *revs) { suppress(revs); revs->separate_merges = 1; + revs->simplify_history = 0; } static void set_first_parent(struct rev_info *revs) @@ -50,6 +51,7 @@ static void set_remerge_diff(struct rev_info *revs) { suppress(revs); revs->remerge_diff = 1; + revs->simplify_history = 0; } static diff_merges_setup_func_t func_by_opt(const char *optarg) diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh index 86c5a33bd77..962888cc7fb 100755 --- a/t/t4069-remerge-diff.sh +++ b/t/t4069-remerge-diff.sh @@ -226,7 +226,63 @@ test_expect_success 'remerge-diff w/ pathspec: limits to relevant file including # with sha256 sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && - git show --oneline --remerge-diff --full-history resolution -- "letters*" >tmp && + git show --oneline --remerge-diff resolution -- "letters*" >tmp && + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && + test_cmp expect actual +' + +test_expect_success 'setup non-content conflicts' ' + git switch --orphan newbase && + + test_write_lines 1 2 3 4 5 6 7 8 9 >numbers && + git add numbers && + git commit -m base && + + git branch newside1 && + git branch newside2 && + + git checkout newside1 && + test_write_lines 1 2 three 4 5 6 7 8 9 >numbers && + git add numbers && + git commit -m side1 && + + git checkout newside2 && + test_write_lines 1 2 drei 4 5 6 7 8 9 >numbers && + git add numbers && + git commit -m side2 && + + git checkout -b newresolution newside1 && + test_must_fail git merge newside2 && + git checkout --theirs numbers && + git add -u numbers && + git commit -m resolved +' + +test_expect_success 'remerge-diff turns off history simplification' ' + git log -1 --oneline newresolution >tmp && + cat <<-EOF >>tmp && + diff --git a/numbers b/numbers + remerge CONFLICT (content): Merge conflict in numbers + index 070e9e7..5335e78 100644 + --- a/numbers + +++ b/numbers + @@ -1,10 +1,6 @@ + 1 + 2 + -<<<<<<< 96f1e45 (side1) + -three + -======= + drei + ->>>>>>> 4fd522f (side2) + 4 + 5 + 6 + EOF + # We still have some sha1 hashes above; rip them out so test works + # with sha256 + sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect && + + git show --oneline --remerge-diff newresolution -- numbers >tmp && sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual && test_cmp expect actual '