From patchwork Tue Sep 1 10:56:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747891 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A6551667 for ; Tue, 1 Sep 2020 11:01:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4B0CA206EF for ; Tue, 1 Sep 2020 11:01:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CHVZi6Om" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726326AbgIAK6O (ORCPT ); Tue, 1 Sep 2020 06:58:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40378 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725989AbgIAK6L (ORCPT ); Tue, 1 Sep 2020 06:58:11 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC068C061245 for ; Tue, 1 Sep 2020 03:58:10 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id b79so700875wmb.4 for ; Tue, 01 Sep 2020 03:58:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CLVtIX3yBCG3bHaRqEUcybh6RsscPvkDjj+OpK0wslg=; b=CHVZi6OmdLVuXpx8Py2AQzVH/iETRZA4ebxxq5Mi+vX6ZabK4JGSONKBrv96/CZhmw q4QZ0OVBjPYcSIeBQ2um5jbbPCJVHgp7OR3xdIOhy2ydMZERNRQJUpMN49OQrhUw6JYP qOqk/+XyeX5xrXmzJ6anWZ/Jnu9X0EcZUDj93f2Tgi/qcFwC7/Qt6z+Zuf5db7HBqcyv /2Buu8VkVWr6ZnkJgSPEZeJ7s2MdbaNrGz7nEyvzTCAmLWl0gQiKPWA1yXWhcq+bkYcG DW69/61/VGHlkvPiQdr3mfkwXnsguSTSRxBzei676xYcFa8BMm/Ea0Y/mV6fOqBkzfNo 8UyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CLVtIX3yBCG3bHaRqEUcybh6RsscPvkDjj+OpK0wslg=; b=CLsq2+rTe6AuYV3c1cX2TbK7jyVqyTe3NAncucu7KDZ4pu1hzIpriS5estVtTUV9bk CBmo/TZoU9b5U5ECgxNOZi5pMMG48aQdlUyPHT+LVMCegOxwo8SSc+FTvcfS7u6KeMJy QzQOVM4PFVkkXcN6s72U31Ss4xfJwjXaQB1edVIbnlY/dvV+GyH/oai9LU0SqVEalqQC 0y7Oo0VVpeqMGo8KaPiCLybr9HFOkZJF/z/UcHpOcczK2EoSnMCeEzkxmAgMhubpY2Nc ewEyzegwWAup8OQy3xus7XRvvisu1lzfsnPoFkxs8/ktfIMP1awzEh0MsM+pMWoKtp5Q ds9A== X-Gm-Message-State: AOAM530uEhjdu2yEXcgUT1F83Voe9XbZxLAzDHMjTIyx286EE6Rsxj6t 9z8IlVHRXbithDiaM4UdTFbO+k3Y6Gc= X-Google-Smtp-Source: ABdhPJwfmAIsqmW1tZw/B0IfvfoI1ZXy+P+FInxIpLFc6YwXa7AueFCRoBFUJg+4czb7u3p6LOD80Q== X-Received: by 2002:a7b:c359:: with SMTP id l25mr1154308wmj.187.1598957889130; Tue, 01 Sep 2020 03:58:09 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:08 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 01/11] t6027: modernise tests Date: Tue, 1 Sep 2020 12:56:55 +0200 Message-Id: <20200901105705.6059-2-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Some tests in t6027 uses a if/then/else to check if a command failed or not, but we have the `test_must_fail' function to do it correctly for us nowadays. Signed-off-by: Alban Gruin --- t/t6407-merge-binary.sh | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh index 4e6c7cb77e..071d3f7343 100755 --- a/t/t6407-merge-binary.sh +++ b/t/t6407-merge-binary.sh @@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files' . ./test-lib.sh test_expect_success setup ' - cat "$TEST_DIRECTORY"/test-binary-1.png >m && git add m && git ls-files -s | sed -e "s/ 0 / 1 /" >E1 && @@ -35,33 +34,19 @@ test_expect_success setup ' ' test_expect_success resolve ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s resolve master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s resolve master && + git ls-files -s >current && + test_cmp expect current ' test_expect_success recursive ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s recursive master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s recursive master && + git ls-files -s >current && + test_cmp expect current ' test_done From patchwork Tue Sep 1 10:56:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747897 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1C859109B for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E8C11207BC for ; Tue, 1 Sep 2020 11:01:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NSgnKE5D" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726543AbgIAK7H (ORCPT ); Tue, 1 Sep 2020 06:59:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726311AbgIAK6O (ORCPT ); Tue, 1 Sep 2020 06:58:14 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AB09AC061246 for ; Tue, 1 Sep 2020 03:58:12 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id e11so706976wme.0 for ; Tue, 01 Sep 2020 03:58:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=LSj3uVpKPZPG/QuwYARwrA0Lq4Fsgdnn6Ppaf+VM6Jg=; b=NSgnKE5Dtpe6asFLJuIPG+Fb1olafNOdD6KdWEkmZvusGAzQwcH0pbPt8j5zDNh6Jp EmEhWpV1Ka+5SnNZ3R4SrDXhhylLSckWyJX2UUXdzv0sCQEoMtJXhO1QEl1LZuUs9QMx mqAO1+ArTRUODmR8lXawjdSPKYwYkDk1WVkuBLpnnketmM6YbIc8WXY8z67Pmrz+kegu KMX7VoZV5XCoJEOQQUfPhx3gSWkk1UImZDYb4zyZ3c/ws5w5/Fo6nSoSgTV2faIwRdSb Lpl/9Q9IKX7j0pJCWmw2UULb0KRGOoxsaqde4rZx+TtZLHBLJFfNIBZY7QaRGqS6A5q4 vD8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LSj3uVpKPZPG/QuwYARwrA0Lq4Fsgdnn6Ppaf+VM6Jg=; b=GtH7DIzL25rPhU6dRyJ4bHgdCqhiK4tJBi0/hC8fPthDYHP5Yf5iba/fh3+O/yx9bb rQ9XkWVZny2u8n5v1SP6a2HzhW4YPWUITwnFjBF+AdJu6NXnFI9k04Egqd6PMzZKoJZ+ Q7n4BhzLO6liOQs4S9r5xTejgYvOe/f/yKXzBpO2GoRjxrTVVJCtO9GY9wFYHR6eWR2R XdysonEFkw2x0BUVRjo7pVE1DhDK9WLTOymPE4J2Y6mypjksZ9VEyv0YVgDmnBosrh66 ATBPDpDGJsltbKzcxqIu5Xu2Cs/s2U5kUSApHjWeSCYUqJ5wU+5aLY0T/X6bVK4d1fNt im7g== X-Gm-Message-State: AOAM5320FtcEAPBDdHHxibctJfTP2M2dntK/giUGXvUKUtDC2RmdOn5M xREoKxDdgLn6keCqJmnn5Gy8r33W/SQ= X-Google-Smtp-Source: ABdhPJw4EFJYCB7g3knXXaJppa1dCHu3hMjF/DhWtdhrQdW9JhmyUgXhaYMsrkcHNHGewvwljaUUgA== X-Received: by 2002:a7b:cb4d:: with SMTP id v13mr1303056wmj.56.1598957890588; Tue, 01 Sep 2020 03:58:10 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:10 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 02/11] merge-one-file: rewrite in C Date: Tue, 1 Sep 2020 12:56:56 +0200 Message-Id: <20200901105705.6059-3-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-one-file' from shell to C. This port is not completely straightforward: to save precious cycles by avoiding reading and flushing the index repeatedly, write temporary files when an operation can be performed in-memory, or allow other function to use the rewrite without forking nor worrying about the index, the calls to external processes are replaced by calls to functions in libgit.a: - calls to `update-index --add --cacheinfo' are replaced by calls to add_cache_entry(); - calls to `update-index --remove' are replaced by calls to remove_file_from_cache(); - calls to `checkout-index -u -f' are replaced by calls to checkout_entry(); - calls to `unpack-file' and `merge-files' are replaced by calls to read_mmblob() and ll_merge(), respectively, to merge files in-memory; - calls to `checkout-index -f --stage=2' are replaced by calls to cache_file_exists(); - calls to `update-index' are replaced by calls to add_file_to_cache(). The bulk of the rewrite is done in a new file in libgit.a, merge-strategies.c. This will enable the resolve and octopus strategies to directly call it instead of forking. This also fixes a bug present in the original script: instead of checking if a _regular_ file exists when a file exists in the branch to merge, but not in our branch, the rewritten version checks if a file of any kind (ie. a directory, ...) exists. This fixes the tests t6035.14, where the branch to merge had a new file, `a/b', but our branch had a directory there; it should have failed because a directory exists, but it did not because there was no regular file called `a/b'. This test is now marked as successful. Signed-off-by: Alban Gruin --- Makefile | 3 +- builtin.h | 1 + builtin/merge-one-file.c | 85 ++++++++++++++ git-merge-one-file.sh | 167 --------------------------- git.c | 1 + merge-strategies.c | 199 ++++++++++++++++++++++++++++++++ merge-strategies.h | 13 +++ t/t6415-merge-dir-to-symlink.sh | 2 +- 8 files changed, 302 insertions(+), 169 deletions(-) create mode 100644 builtin/merge-one-file.c delete mode 100755 git-merge-one-file.sh create mode 100644 merge-strategies.c create mode 100644 merge-strategies.h diff --git a/Makefile b/Makefile index 65f8cfb236..8849d54063 100644 --- a/Makefile +++ b/Makefile @@ -596,7 +596,6 @@ SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-merge-octopus.sh -SCRIPT_SH += git-merge-one-file.sh SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh @@ -911,6 +910,7 @@ LIB_OBJS += match-trees.o LIB_OBJS += mem-pool.o LIB_OBJS += merge-blobs.o LIB_OBJS += merge-recursive.o +LIB_OBJS += merge-strategies.o LIB_OBJS += merge.o LIB_OBJS += mergesort.o LIB_OBJS += midx.o @@ -1089,6 +1089,7 @@ BUILTIN_OBJS += builtin/mailsplit.o BUILTIN_OBJS += builtin/merge-base.o BUILTIN_OBJS += builtin/merge-file.o BUILTIN_OBJS += builtin/merge-index.o +BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o BUILTIN_OBJS += builtin/merge-tree.o diff --git a/builtin.h b/builtin.h index a5ae15bfe5..9205d5ecdc 100644 --- a/builtin.h +++ b/builtin.h @@ -172,6 +172,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix); int cmd_merge_index(int argc, const char **argv, const char *prefix); int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); +int cmd_merge_one_file(int argc, const char **argv, const char *prefix); int cmd_merge_recursive(int argc, const char **argv, const char *prefix); int cmd_merge_tree(int argc, const char **argv, const char *prefix); int cmd_mktag(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c new file mode 100644 index 0000000000..306a86c2f0 --- /dev/null +++ b/builtin/merge-one-file.c @@ -0,0 +1,85 @@ +/* + * Builtin "git merge-one-file" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-one-file.sh, written by Linus Torvalds. + * + * This is the git per-file merge utility, called with + * + * argv[1] - original file SHA1 (or empty) + * argv[2] - file in branch1 SHA1 (or empty) + * argv[3] - file in branch2 SHA1 (or empty) + * argv[4] - pathname in repository + * argv[5] - original file mode (or empty) + * argv[6] - file in branch1 mode (or empty) + * argv[7] - file in branch2 mode (or empty) + * + * Handle some trivial cases. The _really_ trivial cases have been + * handled already by git read-tree, but that one doesn't do any merges + * that might change the tree layout. + */ + +#include "cache.h" +#include "builtin.h" +#include "lockfile.h" +#include "merge-strategies.h" + +static const char builtin_merge_one_file_usage[] = + "git merge-one-file " + " \n\n" + "Blob ids and modes should be empty for missing files."; + +int cmd_merge_one_file(int argc, const char **argv, const char *prefix) +{ + struct object_id orig_blob, our_blob, their_blob, + *p_orig_blob = NULL, *p_our_blob = NULL, *p_their_blob = NULL; + unsigned int orig_mode = 0, our_mode = 0, their_mode = 0, ret = 0; + struct lock_file lock = LOCK_INIT; + + if (argc != 8) + usage(builtin_merge_one_file_usage); + + if (repo_read_index(the_repository) < 0) + die("invalid index"); + + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); + + if (!get_oid(argv[1], &orig_blob)) { + p_orig_blob = &orig_blob; + orig_mode = strtol(argv[5], NULL, 8); + + if (!(S_ISREG(orig_mode) || S_ISDIR(orig_mode) || S_ISLNK(orig_mode))) + ret |= error(_("invalid 'orig' mode: %o"), orig_mode); + } + + if (!get_oid(argv[2], &our_blob)) { + p_our_blob = &our_blob; + our_mode = strtol(argv[6], NULL, 8); + + if (!(S_ISREG(our_mode) || S_ISDIR(our_mode) || S_ISLNK(our_mode))) + ret |= error(_("invalid 'our' mode: %o"), our_mode); + } + + if (!get_oid(argv[3], &their_blob)) { + p_their_blob = &their_blob; + their_mode = strtol(argv[7], NULL, 8); + + if (!(S_ISREG(their_mode) || S_ISDIR(their_mode) || S_ISLNK(their_mode))) + ret = error(_("invalid 'their' mode: %o"), their_mode); + } + + if (ret) + return ret; + + ret = merge_strategies_one_file(the_repository, + p_orig_blob, p_our_blob, p_their_blob, argv[4], + orig_mode, our_mode, their_mode); + + if (ret) { + rollback_lock_file(&lock); + return ret; + } + + return write_locked_index(the_repository->index, &lock, COMMIT_LOCK); +} diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh deleted file mode 100755 index f6d9852d2f..0000000000 --- a/git-merge-one-file.sh +++ /dev/null @@ -1,167 +0,0 @@ -#!/bin/sh -# -# Copyright (c) Linus Torvalds, 2005 -# -# This is the git per-file merge script, called with -# -# $1 - original file SHA1 (or empty) -# $2 - file in branch1 SHA1 (or empty) -# $3 - file in branch2 SHA1 (or empty) -# $4 - pathname in repository -# $5 - original file mode (or empty) -# $6 - file in branch1 mode (or empty) -# $7 - file in branch2 mode (or empty) -# -# Handle some trivial cases.. The _really_ trivial cases have -# been handled already by git read-tree, but that one doesn't -# do any merges that might change the tree layout. - -USAGE=' ' -USAGE="$USAGE " -LONG_USAGE="usage: git merge-one-file $USAGE - -Blob ids and modes should be empty for missing files." - -SUBDIRECTORY_OK=Yes -. git-sh-setup -cd_to_toplevel -require_work_tree - -if test $# != 7 -then - echo "$LONG_USAGE" - exit 1 -fi - -case "${1:-.}${2:-.}${3:-.}" in -# -# Deleted in both or deleted in one and unchanged in the other -# -"$1.." | "$1.$1" | "$1$1.") - if { test -z "$6" && test "$5" != "$7"; } || - { test -z "$7" && test "$5" != "$6"; } - then - echo "ERROR: File $4 deleted on one branch but had its" >&2 - echo "ERROR: permissions changed on the other." >&2 - exit 1 - fi - - if test -n "$2" - then - echo "Removing $4" - else - # read-tree checked that index matches HEAD already, - # so we know we do not have this path tracked. - # there may be an unrelated working tree file here, - # which we should just leave unmolested. Make sure - # we do not have it in the index, though. - exec git update-index --remove -- "$4" - fi - if test -f "$4" - then - rm -f -- "$4" && - rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || : - fi && - exec git update-index --remove -- "$4" - ;; - -# -# Added in one. -# -".$2.") - # the other side did not add and we added so there is nothing - # to be done, except making the path merged. - exec git update-index --add --cacheinfo "$6" "$2" "$4" - ;; -"..$3") - echo "Adding $4" - if test -f "$4" - then - echo "ERROR: untracked $4 is overwritten by the merge." >&2 - exit 1 - fi - git update-index --add --cacheinfo "$7" "$3" "$4" && - exec git checkout-index -u -f -- "$4" - ;; - -# -# Added in both, identically (check for same permissions). -# -".$3$2") - if test "$6" != "$7" - then - echo "ERROR: File $4 added identically in both branches," >&2 - echo "ERROR: but permissions conflict $6->$7." >&2 - exit 1 - fi - echo "Adding $4" - git update-index --add --cacheinfo "$6" "$2" "$4" && - exec git checkout-index -u -f -- "$4" - ;; - -# -# Modified in both, but differently. -# -"$1$2$3" | ".$2$3") - - case ",$6,$7," in - *,120000,*) - echo "ERROR: $4: Not merging symbolic link changes." >&2 - exit 1 - ;; - *,160000,*) - echo "ERROR: $4: Not merging conflicting submodule changes." >&2 - exit 1 - ;; - esac - - src1=$(git unpack-file $2) - src2=$(git unpack-file $3) - case "$1" in - '') - echo "Added $4 in both, but differently." - orig=$(git unpack-file $(git hash-object /dev/null)) - ;; - *) - echo "Auto-merging $4" - orig=$(git unpack-file $1) - ;; - esac - - git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if test $ret != 0 || test -z "$1" - then - msg='content conflict' - ret=1 - fi - - # Create the working tree file, using "our tree" version from the - # index, and then store the result of the merge. - git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1 - rm -f -- "$orig" "$src1" "$src2" - - if test "$6" != "$7" - then - if test -n "$msg" - then - msg="$msg, " - fi - msg="${msg}permissions conflict: $5->$6,$7" - ret=1 - fi - - if test $ret != 0 - then - echo "ERROR: $msg in $4" >&2 - exit 1 - fi - exec git update-index -- "$4" - ;; - -*) - echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2 - ;; -esac -exit 1 diff --git a/git.c b/git.c index 8bd1d7551d..c97fea36c1 100644 --- a/git.c +++ b/git.c @@ -534,6 +534,7 @@ static struct cmd_struct commands[] = { { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, + { "merge-one-file", cmd_merge_one_file, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c new file mode 100644 index 0000000000..f2af4a894d --- /dev/null +++ b/merge-strategies.c @@ -0,0 +1,199 @@ +#include "cache.h" +#include "dir.h" +#include "ll-merge.h" +#include "merge-strategies.h" +#include "xdiff-interface.h" + +static int add_to_index_cacheinfo(struct index_state *istate, + unsigned int mode, + const struct object_id *oid, const char *path) +{ + struct cache_entry *ce; + int len, option; + + if (!verify_path(path, mode)) + return error(_("Invalid path '%s'"), path); + + len = strlen(path); + ce = make_empty_cache_entry(istate, len); + + oidcpy(&ce->oid, oid); + memcpy(ce->name, path, len); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; + ce->ce_mode = create_ce_mode(mode); + if (assume_unchanged) + ce->ce_flags |= CE_VALID; + option = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; + if (add_index_entry(istate, ce, option)) + return error(_("%s: cannot add to the index"), path); + + return 0; +} + +static int checkout_from_index(struct index_state *istate, const char *path) +{ + struct checkout state = CHECKOUT_INIT; + struct cache_entry *ce; + + state.istate = istate; + state.force = 1; + state.base_dir = ""; + state.base_dir_len = 0; + + ce = index_file_exists(istate, path, strlen(path), 0); + if (checkout_entry(ce, &state, NULL, NULL) < 0) + return error(_("%s: cannot checkout file"), path); + return 0; +} + +static int merge_one_file_deleted(struct index_state *istate, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + if ((our_blob && orig_mode != our_mode) || + (their_blob && orig_mode != their_mode)) + return error(_("File %s deleted on one branch but had its " + "permissions changed on the other."), path); + + if (our_blob) { + printf(_("Removing %s\n"), path); + + if (file_exists(path)) + remove_path(path); + } + + if (remove_file_from_index(istate, path)) + return error("%s: cannot remove from the index", path); + return 0; +} + +static int do_merge_one_file(struct index_state *istate, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + int ret, i, dest; + mmbuffer_t result = {NULL, 0}; + mmfile_t mmfs[3]; + struct ll_merge_options merge_opts = {0}; + struct cache_entry *ce; + + if (our_mode == S_IFLNK || their_mode == S_IFLNK) + return error(_("%s: Not merging symbolic link changes."), path); + else if (our_mode == S_IFGITLINK || their_mode == S_IFGITLINK) + return error(_("%s: Not merging conflicting submodule changes."), path); + + read_mmblob(mmfs + 1, our_blob); + read_mmblob(mmfs + 2, their_blob); + + if (orig_blob) { + printf(_("Auto-merging %s\n"), path); + read_mmblob(mmfs + 0, orig_blob); + } else { + printf(_("Added %s in both, but differently.\n"), path); + read_mmblob(mmfs + 0, &null_oid); + } + + merge_opts.xdl_opts = XDL_MERGE_ZEALOUS_ALNUM; + ret = ll_merge(&result, path, + mmfs + 0, "orig", + mmfs + 1, "our", + mmfs + 2, "their", + istate, &merge_opts); + + for (i = 0; i < 3; i++) + free(mmfs[i].ptr); + + if (ret > 127 || !orig_blob) + ret = error(_("content conflict in %s"), path); + + /* Create the working tree file, using "our tree" version from + the index, and then store the result of the merge. */ + ce = index_file_exists(istate, path, strlen(path), 0); + if (!ce) + BUG("file is not present in the cache?"); + + unlink(path); + dest = open(path, O_WRONLY | O_CREAT, ce->ce_mode); + write_in_full(dest, result.ptr, result.size); + close(dest); + + free(result.ptr); + + if (ret && our_mode != their_mode) + return error(_("permission conflict: %o->%o,%o in %s"), + orig_mode, our_mode, their_mode, path); + if (ret) + return 1; + + return add_file_to_index(istate, path, 0); +} + +int merge_strategies_one_file(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, + unsigned int their_mode) +{ + if (orig_blob && + ((!their_blob && our_blob && oideq(orig_blob, our_blob)) || + (!our_blob && their_blob && oideq(orig_blob, their_blob)))) + /* Deleted in both or deleted in one and unchanged in + the other */ + return merge_one_file_deleted(r->index, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else if (!orig_blob && our_blob && !their_blob) { + /* Added in one. The other side did not add and we + added so there is nothing to be done, except making + the path merged. */ + return add_to_index_cacheinfo(r->index, our_mode, our_blob, path); + } else if (!orig_blob && !our_blob && their_blob) { + printf(_("Adding %s\n"), path); + + if (file_exists(path)) + return error(_("untracked %s is overwritten by the merge."), path); + + if (add_to_index_cacheinfo(r->index, their_mode, their_blob, path)) + return 1; + return checkout_from_index(r->index, path); + } else if (!orig_blob && our_blob && their_blob && + oideq(our_blob, their_blob)) { + /* Added in both, identically (check for same + permissions). */ + if (our_mode != their_mode) + return error(_("File %s added identically in both branches, " + "but permissions conflict %o->%o."), + path, our_mode, their_mode); + + printf(_("Adding %s\n"), path); + + if (add_to_index_cacheinfo(r->index, our_mode, our_blob, path)) + return 1; + return checkout_from_index(r->index, path); + } else if (our_blob && their_blob) + /* Modified in both, but differently. */ + return do_merge_one_file(r->index, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + else { + char *orig_hex = "", *our_hex = "", *their_hex = ""; + + if (orig_blob) + orig_hex = oid_to_hex(orig_blob); + if (our_blob) + our_hex = oid_to_hex(our_blob); + if (their_blob) + their_hex = oid_to_hex(their_blob); + + return error(_("%s: Not handling case %s -> %s -> %s"), + path, orig_hex, our_hex, their_hex); + } + + return 0; +} diff --git a/merge-strategies.h b/merge-strategies.h new file mode 100644 index 0000000000..b527d145c7 --- /dev/null +++ b/merge-strategies.h @@ -0,0 +1,13 @@ +#ifndef MERGE_STRATEGIES_H +#define MERGE_STRATEGIES_H + +#include "object.h" + +int merge_strategies_one_file(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, + unsigned int their_mode); + +#endif /* MERGE_STRATEGIES_H */ diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2eddcc7664..5fb74e39a0 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -94,7 +94,7 @@ test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test -h a/b ' -test_expect_failure 'do not lose untracked in merge (resolve)' ' +test_expect_success 'do not lose untracked in merge (resolve)' ' git reset --hard && git checkout baseline^0 && >a/b/c/e && From patchwork Tue Sep 1 10:56:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747913 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E56D413B6 for ; Tue, 1 Sep 2020 11:02:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BE6402083B for ; Tue, 1 Sep 2020 11:02:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Tka0Ly/D" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726419AbgIALCH (ORCPT ); Tue, 1 Sep 2020 07:02:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726355AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5DF93C061249 for ; Tue, 1 Sep 2020 03:58:16 -0700 (PDT) Received: by mail-wr1-x441.google.com with SMTP id z1so1014392wrt.3 for ; Tue, 01 Sep 2020 03:58:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=j7siHblmT3Fve+Txumf4Gb9yaF4pMwR81p9zh4wQF5A=; b=Tka0Ly/D4jaIpU31pQpoZCoY5/6EKUcNaVr+WuFko7B1E2IAu5k6gU1Gis9cQ91TLy H7+RloBQiY5WXnOCkT6YrprYkr5y7ZBo1DSX02uC083nHENk4dse/qAH/tWiPK4ATp// 6X4btfHLqB9KCJR5JJO2+hx7bqdKTqbu+e2h6eczaCm0spIEzeZ7HqtVhQY7lpR/2okX 9yZ8RjHp/lmsf5TyTkFHgJnPhDc7bQkboMTjKoIF2xfLTaK9PmuXg6sz2FykwHML71iF hOV7zvEVorezufvwg9ddNE5sOrLTO/HVVlbaVHKgP6pq3gNaJLIq7FWWvezuVBCGfOJ3 u7IQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=j7siHblmT3Fve+Txumf4Gb9yaF4pMwR81p9zh4wQF5A=; b=SE4cLWrd1GiA0mA0fJPoJas0zJlGEkOj3oy9boay5zk0skB9RxhL1GFdyXC9PSVDoY ULzFImi/caDxmQxB4fckzP0VwwQGOzVOKZky/IDCl/6RUwiDwu90R1ZX67I1+DlOt96N TVyGOv5l+bz4n2S93ZujcjKuWU5c/KXZT2KfTzQg8jRYmh2qCEJHXNXR2b/u90hMuMH2 g7Nv/KdLv+f/ciZUzeiZAij+67lnYKCNxPoHyc+mKfKzLBDrry5twiTV16JxkOtAmlz7 W/re7TYnrTVYvIdWGArxL+pP0YRUoRFUYxozGSBCxJrfCySQGCnrJBGabAQGrBpp0Kbq Piww== X-Gm-Message-State: AOAM5312LeUyX1Opb3aZ5eyoC4YrnEsd8U2/YJEQVyOL1aiZPNhUOLaa 0z5NSYEn6NjYzzzAJ5Lu+aeJ5kK4SSM= X-Google-Smtp-Source: ABdhPJyKQael+JwYM3mQgb3guFS7PQgEzsBJ5Wg0JWAeikTlO769mWUFUWw52CnoVUFBzydT6i4a9A== X-Received: by 2002:adf:94c1:: with SMTP id 59mr1368794wrr.29.1598957894573; Tue, 01 Sep 2020 03:58:14 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:14 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 05/11] merge-resolve: rewrite in C Date: Tue, 1 Sep 2020 12:56:59 +0200 Message-Id: <20200901105705.6059-6-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-resolve' from shell to C. As for `git merge-one-file', this port is not completely straightforward and removes calls to external processes to avoid reading and writing the index over and over again. - The call to `update-index -q --refresh' is replaced by a call to refresh_index(). - The call to `read-tree' is replaced by a call to unpack_trees() (and all the setup needed). - The call to `write-tree' is replaced by a call to write_index_as_tree(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to the new merge_all() function. A callback function, merge_one_file_cb(), is added to allow it to call merge_one_file() without forking. Here too, the index is read in cmd_merge_resolve(), but merge_strategies_resolve() takes care of writing it back to the disk. The parameters of merge_strategies_resolve() will be surprising at first glance: why using a commit list for `bases' and `remote', where we could use an oid array, and a pointer to an oid? Because, in a later commit, try_merge_strategy() will be able to call merge_strategies_resolve() directly, and it already uses a commit list for `bases' (`common') and `remote' (`remoteheads'), and a string for `head_arg'. To reduce frictions later, merge_strategies_resolve() takes the same types of parameters. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-resolve.c | 69 +++++++++++++++++++++++++++++++++ git-merge-resolve.sh | 54 -------------------------- git.c | 1 + merge-strategies.c | 85 +++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 5 +++ 7 files changed, 162 insertions(+), 55 deletions(-) create mode 100644 builtin/merge-resolve.c delete mode 100755 git-merge-resolve.sh diff --git a/Makefile b/Makefile index 8849d54063..929c3dc3eb 100644 --- a/Makefile +++ b/Makefile @@ -596,7 +596,6 @@ SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-merge-octopus.sh -SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-request-pull.sh @@ -1092,6 +1091,7 @@ BUILTIN_OBJS += builtin/merge-index.o BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o +BUILTIN_OBJS += builtin/merge-resolve.o BUILTIN_OBJS += builtin/merge-tree.o BUILTIN_OBJS += builtin/merge.o BUILTIN_OBJS += builtin/mktag.o diff --git a/builtin.h b/builtin.h index 9205d5ecdc..6ea207c9fd 100644 --- a/builtin.h +++ b/builtin.h @@ -174,6 +174,7 @@ int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); int cmd_merge_one_file(int argc, const char **argv, const char *prefix); int cmd_merge_recursive(int argc, const char **argv, const char *prefix); +int cmd_merge_resolve(int argc, const char **argv, const char *prefix); int cmd_merge_tree(int argc, const char **argv, const char *prefix); int cmd_mktag(int argc, const char **argv, const char *prefix); int cmd_mktree(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-resolve.c b/builtin/merge-resolve.c new file mode 100644 index 0000000000..59f734473b --- /dev/null +++ b/builtin/merge-resolve.c @@ -0,0 +1,69 @@ +/* + * Builtin "git merge-resolve" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-resolve.sh, written by Linus Torvalds and Junio C + * Hamano. + * + * Resolve two trees, using enhanced multi-base read-tree. + */ + +#include "cache.h" +#include "builtin.h" +#include "merge-strategies.h" + +static const char builtin_merge_resolve_usage[] = + "git merge-resolve ... -- "; + +int cmd_merge_resolve(int argc, const char **argv, const char *prefix) +{ + int i, is_baseless = 1, sep_seen = 0; + const char *head = NULL; + struct commit_list *bases = NULL, *remote = NULL; + struct commit_list **next_base = &bases; + + if (argc < 5) + usage(builtin_merge_resolve_usage); + + setup_work_tree(); + if (repo_read_index(the_repository) < 0) + die("invalid index"); + + /* The first parameters up to -- are merge bases; the rest are + * heads. */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--") == 0) + sep_seen = 1; + else if (strcmp(argv[i], "-h") == 0) + usage(builtin_merge_resolve_usage); + else if (sep_seen && !head) + head = argv[i]; + else if (remote) { + /* Give up if we are given two or more remotes. + * Not handling octopus. */ + return 2; + } else { + struct object_id oid; + + get_oid(argv[i], &oid); + is_baseless &= sep_seen; + + if (!oideq(&oid, the_hash_algo->empty_tree)) { + struct commit *commit; + commit = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + commit_list_append(commit, &remote); + else + next_base = commit_list_append(commit, next_base); + } + } + } + + /* Give up if this is a baseless merge. */ + if (is_baseless) + return 2; + + return merge_strategies_resolve(the_repository, bases, head, remote); +} diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh deleted file mode 100755 index 343fe7bccd..0000000000 --- a/git-merge-resolve.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two trees, using enhanced multi-base read-tree. - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Give up if we are given two or more remotes -- not handling octopus. -case "$remotes" in -?*' '?*) - exit 2 ;; -esac - -# Give up if this is a baseless merge. -if test '' = "$bases" -then - exit 2 -fi - -git update-index -q --refresh -git read-tree -u -m --aggressive $bases $head $remotes || exit 2 -echo "Trying simple merge." -if result_tree=$(git write-tree 2>/dev/null) -then - exit 0 -else - echo "Simple merge failed, trying Automatic merge." - if git merge-index -o git-merge-one-file -a - then - exit 0 - else - exit 1 - fi -fi diff --git a/git.c b/git.c index c97fea36c1..794ca6e9f0 100644 --- a/git.c +++ b/git.c @@ -538,6 +538,7 @@ static struct cmd_struct commands[] = { { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-resolve", cmd_merge_resolve, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT }, { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c index 00738863e4..6b905dfc38 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,8 +1,11 @@ #include "cache.h" +#include "cache-tree.h" #include "dir.h" #include "ll-merge.h" +#include "lockfile.h" #include "merge-strategies.h" #include "run-command.h" +#include "unpack-trees.h" #include "xdiff-interface.h" static int add_to_index_cacheinfo(struct index_state *istate, @@ -307,3 +310,85 @@ int merge_all(struct index_state *istate, int oneshot, int quiet, return err; } + +static int add_tree(const struct object_id *oid, struct tree_desc *t) +{ + struct tree *tree; + + tree = parse_tree_indirect(oid); + if (parse_tree(tree)) + return -1; + + init_tree_desc(t, tree->buffer, tree->size); + return 0; +} + +int merge_strategies_resolve(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote) +{ + int i = 0; + struct lock_file lock = LOCK_INIT; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct object_id head, oid; + struct commit_list *j; + + if (head_arg) + get_oid(head_arg, &head); + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + refresh_index(r->index, 0, NULL, NULL, NULL); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = r->index; + opts.dst_index = r->index; + opts.update = 1; + opts.merge = 1; + opts.aggressive = 1; + + for (j = bases; j && j->item; j = j->next) { + if (add_tree(&j->item->object.oid, t + (i++))) + goto out; + } + + if (head_arg && add_tree(&head, t + (i++))) + goto out; + if (remote && add_tree(&remote->item->object.oid, t + (i++))) + goto out; + + if (i == 1) + opts.fn = oneway_merge; + else if (i == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(r->index); + } else if (i >= 3) { + opts.fn = threeway_merge; + opts.head_idx = i - 1; + } + + if (unpack_trees(i, t, &opts)) + goto out; + + puts(_("Trying simple merge.")); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + if (write_index_as_tree(&oid, r->index, r->index_file, + WRITE_TREE_SILENT, NULL)) { + int ret; + + puts(_("Simple merge failed, trying Automatic merge.")); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = merge_all(r->index, 0, 0, merge_one_file_cb, r); + + write_locked_index(r->index, &lock, COMMIT_LOCK); + return !!ret; + } + + return 0; + + out: + rollback_lock_file(&lock); + return 2; +} diff --git a/merge-strategies.h b/merge-strategies.h index 40e175ca39..778f8ce9d6 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -1,6 +1,7 @@ #ifndef MERGE_STRATEGIES_H #define MERGE_STRATEGIES_H +#include "commit.h" #include "object.h" int merge_strategies_one_file(struct repository *r, @@ -33,4 +34,8 @@ int merge_one_path(struct index_state *istate, int oneshot, int quiet, int merge_all(struct index_state *istate, int oneshot, int quiet, merge_cb cb, void *data); +int merge_strategies_resolve(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote); + #endif /* MERGE_STRATEGIES_H */ From patchwork Tue Sep 1 10:57:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747899 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 47CE417D0 for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 26C6A207BC for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uLyO2LzU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726594AbgIAK7S (ORCPT ); Tue, 1 Sep 2020 06:59:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726419AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CCEEC06124F for ; Tue, 1 Sep 2020 03:58:17 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id t10so167156wrv.1 for ; Tue, 01 Sep 2020 03:58:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1pPjLdjLHw6XH236q6sVPtEcsHTz241ZzunGG6JLbsI=; b=uLyO2LzUoZvXNEGfHaxFFSlU1cmXWY2wSdTrdJnIXy5gU3QKOuNtbEZA77TuvwbkvJ QPr292vVJ5hhLbRPfJCfuRsjCLrvbrF2ASip0VCQ7NaLM0JQFO9vzni6wi0dHrgOZxue yS3mJnLl72A/k/EjNmM7hOB5sTVif8r5J38NWi15/MMQW3dS14swWjViXdvaYtvUxpUM I7agNbZ6djN69faq/AU6XwXVK4CNaCOQRF4Rd2O3XVOIx4ik8HQODgPHfauUwuwV9M6M wvLSAr2vI7YoS9abn1MrqizPQNJesQzcoAhStT35oUUpuFVuy1RpL+rMK7/SL+zeh0lR 0LzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1pPjLdjLHw6XH236q6sVPtEcsHTz241ZzunGG6JLbsI=; b=nai1eK9HVZZpGhQRhgbXj4NTi8nGJ45YwMBsu/5a1wjKBFDA1uXq9aTVG1mlWkhvbJ Bf6cSNgPN423ZhvgR9NGJk2Dn7CSxH7E1O8vcmF21l7ogykhgZWqwxcF5qi1BQDKIs/h 6L59OXvrLeN8j6gd7XjZ6PiN5TsCKjIeBzrIDLYQvrUvLRZQt9lsvXWiNR6A0FSTqTi8 fpILqfD4Vn8dS+bS0QFLo9Bmgwg3e8lgOkxyLmfr29eR60Sof49nbzmyuuSlPaS0dUC3 mpb47Ivku42AALB2U1lI1MBsyDNylKO74sAvAM1veJYjP+1KFsC/grOvCwNgPOcbD8x+ XdGQ== X-Gm-Message-State: AOAM532VQa6hjwcfJd3b+gdJDRDtXo98w1tXQEKCO4rBquakchfrPGla /0UWlVMUcDl+V0hkK8RRZav1bqr0oSo= X-Google-Smtp-Source: ABdhPJwhtfqykXHG9ysQcn/rroPRsEWS4CD4FqRhSMTlvHQ0JS/ZzX78fJe4xT5xQ5EgGZls5HJAAQ== X-Received: by 2002:adf:81e6:: with SMTP id 93mr616322wra.412.1598957895640; Tue, 01 Sep 2020 03:58:15 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:15 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 06/11] merge-recursive: move better_branch_name() to merge.c Date: Tue, 1 Sep 2020 12:57:00 +0200 Message-Id: <20200901105705.6059-7-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org get_better_branch_name() will be used by rebase-octopus once it is rewritten in C, so instead of duplicating it, this moves this function preventively inside an appropriate file in libgit.a. This function is also renamed to reflect its usage by merge strategies. Signed-off-by: Alban Gruin --- builtin/merge-recursive.c | 16 ++-------------- cache.h | 2 +- merge.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index a4bfd8fc51..972243b5e9 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -8,18 +8,6 @@ static const char builtin_merge_recursive_usage[] = "git %s ... -- ..."; -static char *better_branch_name(const char *branch) -{ - static char githead_env[8 + GIT_MAX_HEXSZ + 1]; - char *name; - - if (strlen(branch) != the_hash_algo->hexsz) - return xstrdup(branch); - xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); - name = getenv(githead_env); - return xstrdup(name ? name : branch); -} - int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { const struct object_id *bases[21]; @@ -75,8 +63,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (get_oid(o.branch2, &h2)) die(_("could not resolve ref '%s'"), o.branch2); - o.branch1 = better1 = better_branch_name(o.branch1); - o.branch2 = better2 = better_branch_name(o.branch2); + o.branch1 = better1 = merge_get_better_branch_name(o.branch1); + o.branch2 = better2 = merge_get_better_branch_name(o.branch2); if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); diff --git a/cache.h b/cache.h index 4cad61ffa4..a926b0bc87 100644 --- a/cache.h +++ b/cache.h @@ -1917,7 +1917,7 @@ int checkout_fast_forward(struct repository *r, const struct object_id *from, const struct object_id *to, int overwrite_ignore); - +char *merge_get_better_branch_name(const char *branch); int sane_execvp(const char *file, char *const argv[]); diff --git a/merge.c b/merge.c index 5fb88af102..801d673c5f 100644 --- a/merge.c +++ b/merge.c @@ -109,3 +109,15 @@ int checkout_fast_forward(struct repository *r, return error(_("unable to write new index file")); return 0; } + +char *merge_get_better_branch_name(const char *branch) +{ + static char githead_env[8 + GIT_MAX_HEXSZ + 1]; + char *name; + + if (strlen(branch) != the_hash_algo->hexsz) + return xstrdup(branch); + xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); + name = getenv(githead_env); + return xstrdup(name ? name : branch); +} From patchwork Tue Sep 1 10:57:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747911 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CD8AE1667 for ; Tue, 1 Sep 2020 11:02:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ABDCD2083B for ; Tue, 1 Sep 2020 11:02:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pjqOjqy8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726091AbgIALBz (ORCPT ); Tue, 1 Sep 2020 07:01:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40448 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726467AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 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 0C408C061244 for ; Tue, 1 Sep 2020 03:58:28 -0700 (PDT) Received: by mail-wr1-x42d.google.com with SMTP id z4so1014663wrr.4 for ; Tue, 01 Sep 2020 03:58:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0pr1Gd+Ek5pDCQCmeXlkHdr6MiTLqu52D33OKTohdKA=; b=pjqOjqy83UgMV2g0oQN0+A6/83Yga8UWunhgJn1z5QbQ7ffLe7nxz1HrDLTQT7sWV2 w62bzXkFQDp/2BGZHt/jYBxOEuObKOyWMmVXa1WcOoSxPSffr6ZDqtths4lHk7YK+u8d 8oVUUf14zWUR0hPlYZaNHLli3GBeZDqrVWA3C5/UvLbFluipL4YBOv1jUqw7bJCEqGP6 mKPTfnTbqtuX/OL8MPc8jZFtJFwyfF03AN9rSoq90h1E5Zs9FovhJFhD237/c0QkRjS/ W37sf9y9JEI9w2gtIPXpf8vNfYMtsRqq4xGPpxt/VSccijVx1brgpzAqxc0/1y5NJT83 ++HA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0pr1Gd+Ek5pDCQCmeXlkHdr6MiTLqu52D33OKTohdKA=; b=D6kPjUQW6aHpET5IIVWKV13N9L9hWDftro7QCDmn6BkaS3n9+Z8QfDpTPOydGfDChX /n1E3BSvVV6ze+66XDNjYROgAn6/dj1UUFXZ9ZT5pL8Dw2+aNNzHdEIhnTOxifc10ApP nIjFntcVIZBGKxQ1AZfdBtjxTs6PD1/ATBHOEclDMMfliQIwmIwaK0ZsEHgHnzeVq/yy ib3B2Ngb/CvBg1KJUOZf0iS59lG6oyfXQsSAPH+j7qv1pEDp3IBsxWjg8S4Wi1QsfRsd 3zjflwryP2/zoKBeQnCkikBMsjh+2N+yOw/HDwmUQ+a0Sad6U4s5anrUCJ8RWoACLKmf YfxQ== X-Gm-Message-State: AOAM532Nic+I2NcWJEeSUULVhpGFmTg1CWPLV4KhK2l12qlzeNrvs9fE LCDpKQfcffz45uTwqTxQMR/+LlWIg34= X-Google-Smtp-Source: ABdhPJwPZMStdGoxFsSnhHCoJz5SFj4DZ1rzG+A6GLk6Dq6var4sXQos+wQsqBP/dgCoKRF/2Q6YEA== X-Received: by 2002:a5d:5150:: with SMTP id u16mr1236219wrt.197.1598957897185; Tue, 01 Sep 2020 03:58:17 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:16 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 07/11] merge-octopus: rewrite in C Date: Tue, 1 Sep 2020 12:57:01 +0200 Message-Id: <20200901105705.6059-8-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This rewrites `git merge-octopus' from shell to C. As for the two last conversions, this port removes calls to external processes to avoid reading and writing the index over and over again. - Calls to `read-tree -u -m (--aggressive)?' are replaced by calls to unpack_trees(). - The call to `write-tree' is replaced by a call to write_index_as_tree(). - The call to `diff-index ...' is replaced by a call to repo_index_has_changes(), and is moved from cmd_merge_octopus() to merge_octopus(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to merge_all(). The index is read in cmd_merge_octopus(), and is wrote back by merge_strategies_octopus(). Here to, merge_strategies_octopus() takes two commit lists and a string to reduce frictions when try_merge_strategies() will be modified to call it directly. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-octopus.c | 65 +++++++++++++ git-merge-octopus.sh | 112 ---------------------- git.c | 1 + merge-strategies.c | 200 ++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 3 + 7 files changed, 271 insertions(+), 113 deletions(-) create mode 100644 builtin/merge-octopus.c delete mode 100755 git-merge-octopus.sh diff --git a/Makefile b/Makefile index 929c3dc3eb..2fb26d9692 100644 --- a/Makefile +++ b/Makefile @@ -595,7 +595,6 @@ unexport CDPATH SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-difftool--helper.sh SCRIPT_SH += git-filter-branch.sh -SCRIPT_SH += git-merge-octopus.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-request-pull.sh @@ -1088,6 +1087,7 @@ BUILTIN_OBJS += builtin/mailsplit.o BUILTIN_OBJS += builtin/merge-base.o BUILTIN_OBJS += builtin/merge-file.o BUILTIN_OBJS += builtin/merge-index.o +BUILTIN_OBJS += builtin/merge-octopus.o BUILTIN_OBJS += builtin/merge-one-file.o BUILTIN_OBJS += builtin/merge-ours.o BUILTIN_OBJS += builtin/merge-recursive.o diff --git a/builtin.h b/builtin.h index 6ea207c9fd..5a587ab70c 100644 --- a/builtin.h +++ b/builtin.h @@ -170,6 +170,7 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix); int cmd_merge(int argc, const char **argv, const char *prefix); int cmd_merge_base(int argc, const char **argv, const char *prefix); int cmd_merge_index(int argc, const char **argv, const char *prefix); +int cmd_merge_octopus(int argc, const char **argv, const char *prefix); int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); int cmd_merge_one_file(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-octopus.c b/builtin/merge-octopus.c new file mode 100644 index 0000000000..37bbdf11cc --- /dev/null +++ b/builtin/merge-octopus.c @@ -0,0 +1,65 @@ +/* + * Builtin "git merge-octopus" + * + * Copyright (c) 2020 Alban Gruin + * + * Based on git-merge-octopus.sh, written by Junio C Hamano. + * + * Resolve two or more trees. + */ + +#include "cache.h" +#include "builtin.h" +#include "commit.h" +#include "merge-strategies.h" + +static const char builtin_merge_octopus_usage[] = + "git merge-octopus [...] -- [...]"; + +int cmd_merge_octopus(int argc, const char **argv, const char *prefix) +{ + int i, sep_seen = 0; + struct commit_list *bases = NULL, *remotes = NULL; + struct commit_list **next_base = &bases, **next_remote = &remotes; + const char *head_arg = NULL; + + if (argc < 5) + usage(builtin_merge_octopus_usage); + + setup_work_tree(); + if (repo_read_index(the_repository) < 0) + die("corrupted cache"); + + /* The first parameters up to -- are merge bases; the rest are + * heads. */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--") == 0) + sep_seen = 1; + else if (strcmp(argv[i], "-h") == 0) + usage(builtin_merge_octopus_usage); + else if (sep_seen && !head_arg) + head_arg = argv[i]; + else { + struct object_id oid; + + get_oid(argv[i], &oid); + + if (!oideq(&oid, the_hash_algo->empty_tree)) { + struct commit *commit; + commit = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + next_remote = commit_list_append(commit, next_remote); + else + next_base = commit_list_append(commit, next_base); + } + } + } + + /* Reject if this is not an octopus -- resolve should be used + * instead. */ + if (commit_list_count(remotes) < 2) + return 2; + + return merge_strategies_octopus(the_repository, bases, head_arg, remotes); +} diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh deleted file mode 100755 index 7d19d37951..0000000000 --- a/git-merge-octopus.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two or more trees. -# - -. git-sh-setup - -LF=' -' - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Reject if this is not an octopus -- resolve should be used instead. -case "$remotes" in -?*' '?*) - ;; -*) - exit 2 ;; -esac - -# MRC is the current "merge reference commit" -# MRT is the current "merge result tree" - -if ! git diff-index --quiet --cached HEAD -- -then - gettextln "Error: Your local changes to the following files would be overwritten by merge" - git diff-index --cached --name-only HEAD -- | sed -e 's/^/ /' - exit 2 -fi -MRC=$(git rev-parse --verify -q $head) -MRT=$(git write-tree) -NON_FF_MERGE=0 -OCTOPUS_FAILURE=0 -for SHA1 in $remotes -do - case "$OCTOPUS_FAILURE" in - 1) - # We allow only last one to have a hand-resolvable - # conflicts. Last round failed and we still had - # a head to merge. - gettextln "Automated merge did not work." - gettextln "Should not be doing an octopus." - exit 2 - esac - - eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} - if test "$SHA1" = "$pretty_name" - then - SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)" - eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} - fi - common=$(git merge-base --all $SHA1 $MRC) || - die "$(eval_gettext "Unable to find common commit with \$pretty_name")" - - case "$LF$common$LF" in - *"$LF$SHA1$LF"*) - eval_gettextln "Already up to date with \$pretty_name" - continue - ;; - esac - - if test "$common,$NON_FF_MERGE" = "$MRC,0" - then - # The first head being merged was a fast-forward. - # Advance MRC to the head being merged, and use that - # tree as the intermediate result of the merge. - # We still need to count this as part of the parent set. - - eval_gettextln "Fast-forwarding to: \$pretty_name" - git read-tree -u -m $head $SHA1 || exit - MRC=$SHA1 MRT=$(git write-tree) - continue - fi - - NON_FF_MERGE=1 - - eval_gettextln "Trying simple merge with \$pretty_name" - git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2 - next=$(git write-tree 2>/dev/null) - if test $? -ne 0 - then - gettextln "Simple merge did not work, trying automatic merge." - git merge-index -o git-merge-one-file -a || - OCTOPUS_FAILURE=1 - next=$(git write-tree 2>/dev/null) - fi - - MRC="$MRC $SHA1" - MRT=$next -done - -exit "$OCTOPUS_FAILURE" diff --git a/git.c b/git.c index 794ca6e9f0..df0bebdafc 100644 --- a/git.c +++ b/git.c @@ -533,6 +533,7 @@ static struct cmd_struct commands[] = { { "merge-base", cmd_merge_base, RUN_SETUP }, { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, + { "merge-octopus", cmd_merge_octopus, RUN_SETUP | NO_PARSEOPT }, { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, { "merge-one-file", cmd_merge_one_file, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c index 6b905dfc38..dee86389e3 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,5 +1,6 @@ #include "cache.h" #include "cache-tree.h" +#include "commit-reach.h" #include "dir.h" #include "ll-merge.h" #include "lockfile.h" @@ -392,3 +393,202 @@ int merge_strategies_resolve(struct repository *r, rollback_lock_file(&lock); return 2; } + +static int fast_forward(struct repository *r, const struct object_id *oids, + int nr, int aggressive) +{ + int i; + struct tree_desc t[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct lock_file lock = LOCK_INIT; + + repo_read_index_preload(r, NULL, 0); + if (refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL)) + return -1; + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = r->index; + opts.dst_index = r->index; + opts.merge = 1; + opts.update = 1; + opts.aggressive = aggressive; + + for (i = 0; i < nr; i++) { + struct tree *tree; + tree = parse_tree_indirect(oids + i); + if (parse_tree(tree)) + return -1; + init_tree_desc(t + i, tree->buffer, tree->size); + } + + if (nr == 1) + opts.fn = oneway_merge; + else if (nr == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(r->index); + } else if (nr >= 3) { + opts.fn = threeway_merge; + opts.head_idx = nr - 1; + } + + if (unpack_trees(nr, t, &opts)) + return -1; + + if (write_locked_index(r->index, &lock, COMMIT_LOCK)) + return error(_("unable to write new index file")); + + return 0; +} + +static int write_tree(struct repository *r, struct tree **reference_tree) +{ + struct object_id oid; + int ret; + + ret = write_index_as_tree(&oid, r->index, r->index_file, 0, NULL); + if (!ret) + *reference_tree = lookup_tree(r, &oid); + + return ret; +} + +int merge_strategies_octopus(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remotes) +{ + int non_ff_merge = 0, ret = 0, references = 1; + struct commit **reference_commit; + struct tree *reference_tree; + struct commit_list *j; + struct object_id head; + struct strbuf sb = STRBUF_INIT; + + get_oid(head_arg, &head); + + reference_commit = xcalloc(commit_list_count(remotes) + 1, sizeof(struct commit *)); + reference_commit[0] = lookup_commit_reference(r, &head); + reference_tree = repo_get_commit_tree(r, reference_commit[0]); + + if (repo_index_has_changes(r, reference_tree, &sb)) { + error(_("Your local changes to the following files " + "would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + ret = 2; + goto out; + } + + for (j = remotes; j && j->item; j = j->next) { + struct commit *c = j->item; + struct object_id *oid = &c->object.oid; + struct commit_list *common, *k; + char *branch_name; + int can_ff = 1; + + if (ret) { + /* We allow only last one to have a + hand-resolvable conflicts. Last round failed + and we still had a head to merge. */ + puts(_("Automated merge did not work.")); + puts(_("Should not be doing an octopus.")); + + ret = 2; + goto out; + } + + branch_name = merge_get_better_branch_name(oid_to_hex(oid)); + common = get_merge_bases_many(c, references, reference_commit); + + if (!common) + die(_("Unable to find common commit with %s"), branch_name); + + for (k = common; k && !oideq(&k->item->object.oid, oid); k = k->next); + + if (k) { + printf(_("Already up to date with %s\n"), branch_name); + free(branch_name); + free_commit_list(common); + continue; + } + + if (!non_ff_merge) { + int i; + + for (i = 0, k = common; k && i < references && can_ff; k = k->next, i++) { + can_ff = oideq(&k->item->object.oid, + &reference_commit[i]->object.oid); + } + } + + if (!non_ff_merge && can_ff) { + /* The first head being merged was a + fast-forward. Advance the reference commit + to the head being merged, and use that tree + as the intermediate result of the merge. We + still need to count this as part of the + parent set. */ + struct object_id oids[2]; + printf(_("Fast-forwarding to: %s\n"), branch_name); + + oidcpy(oids, &head); + oidcpy(oids + 1, oid); + + ret = fast_forward(r, oids, 2, 0); + if (ret) { + free(branch_name); + free_commit_list(common); + goto out; + } + + references = 0; + write_tree(r, &reference_tree); + } else { + int i = 0; + struct tree *next = NULL; + struct object_id oids[MAX_UNPACK_TREES]; + + non_ff_merge = 1; + printf(_("Trying simple merge with %s\n"), branch_name); + + for (k = common; k; k = k->next) + oidcpy(oids + (i++), &k->item->object.oid); + + oidcpy(oids + (i++), &reference_tree->object.oid); + oidcpy(oids + (i++), oid); + + if (fast_forward(r, oids, i, 1)) { + ret = 2; + + free(branch_name); + free_commit_list(common); + + goto out; + } + + if (write_tree(r, &next)) { + struct lock_file lock = LOCK_INIT; + + puts(_("Simple merge did not work, trying automatic merge.")); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = !!merge_all(r->index, 0, 0, merge_one_file_cb, r); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + write_tree(r, &next); + } + + reference_tree = next; + } + + reference_commit[references++] = c; + + free(branch_name); + free_commit_list(common); + } + +out: + free(reference_commit); + return ret; +} diff --git a/merge-strategies.h b/merge-strategies.h index 778f8ce9d6..938411a04e 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -37,5 +37,8 @@ int merge_all(struct index_state *istate, int oneshot, int quiet, int merge_strategies_resolve(struct repository *r, struct commit_list *bases, const char *head_arg, struct commit_list *remote); +int merge_strategies_octopus(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote); #endif /* MERGE_STRATEGIES_H */ From patchwork Tue Sep 1 10:57:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747909 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DF6D9109B for ; Tue, 1 Sep 2020 11:01:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C274E207BC for ; Tue, 1 Sep 2020 11:01:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uAFqKPup" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726050AbgIALB1 (ORCPT ); Tue, 1 Sep 2020 07:01:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725989AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22BABC061251 for ; Tue, 1 Sep 2020 03:58:20 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id w5so1005681wrp.8 for ; Tue, 01 Sep 2020 03:58:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dkvQrPHzQcXlRTRvS/mM0QFX4JpxhrN/wEY0DTY4Lqc=; b=uAFqKPupl8yCWX0IWI99Q1ZB9ndVhibsJ54Hxxftpv5b+X3cKV1qDoOlQ/NeitgE6q rmB04p6uXPvyn43vVaQz8UmQr8XitqGWQS7sxNhOgZXRsDksF3OOQiEUHycIhINden7n jVwojbv2ZXAf/+vTQaJFG8fw0pQKBmBDKY8eiFQCh8o0gxnmn7NOChIYe0NJpEh4qd1s /99QxKLavflm4kzEPfFtZNDPYLgK+3jRIjVOBkCWX9o8io8LYtkwkYtFgvVhdHjsAAFu X1ofYPSxL7Wkc6c2F9YQobLvVPAzclad/FTqzUcXXuPodblRdAYksOLLfguzEL2mpRxD sTaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dkvQrPHzQcXlRTRvS/mM0QFX4JpxhrN/wEY0DTY4Lqc=; b=JWGjENzDEj4BpLlrO8wNdGMEDbYj01/9e8ljWqJWjfCch46LD2pxYHT1tHXkTx3eIS VqWhv+TKuKBc9SMMEspztiwXKlYXLI6W+StbqJPlTzoKuqG+BgnleSuPm0SaIEgoGC8v FtehZ2UG79INl7qBQVBTWUwBJ1feL7ax4gwqomrIfp/1+oETXfFq+ZXVLFjBqxvZVANy OqKD0CQsrde+onZPVdUBkaN4I9mHwZZ6k0O85CBdCw0uVuwTME7+qmkPN3sui1qKHDqO UskRVQU+n3iRs0A6D/Yhp+lgTsrjxNlaz8ER2C3DV4483/Cvu7KCEqTMjMk+vyltLI7j ePvQ== X-Gm-Message-State: AOAM532jdagB9V2QHf41XvdXVUX2O8Zd8nmOMx8AVs8ByNsIqAzTxDn2 WSwiQX501CocPLRjqbYWjhD0gkOSeME= X-Google-Smtp-Source: ABdhPJzFKsKcYYHZciwm4YmSDuJa5ofG/Kh7wP8ZlDcMlZN+gWwsAg6VB9PofDmXO73s4lOm+ktK3A== X-Received: by 2002:adf:b306:: with SMTP id j6mr1168679wrd.279.1598957898515; Tue, 01 Sep 2020 03:58:18 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:17 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 08/11] merge: use the "resolve" strategy without forking Date: Tue, 1 Sep 2020 12:57:02 +0200 Message-Id: <20200901105705.6059-9-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches `git merge' to invoke the "resolve" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- builtin/merge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/builtin/merge.c b/builtin/merge.c index 74829a838e..541d9bed02 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -41,6 +41,7 @@ #include "commit-reach.h" #include "wt-status.h" #include "commit-graph.h" +#include "merge-strategies.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -740,7 +741,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write %s"), get_index_file()); return clean ? 0 : 1; - } else { + } else if (!strcmp(strategy, "resolve")) + return merge_strategies_resolve(the_repository, common, + head_arg, remoteheads); + else { return try_merge_command(the_repository, strategy, xopts_nr, xopts, common, head_arg, remoteheads); From patchwork Tue Sep 1 10:57:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747903 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8AF9117D5 for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 70C1C206EF for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IfRUPJja" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726140AbgIALAN (ORCPT ); Tue, 1 Sep 2020 07:00:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40432 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726327AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A82A3C061258 for ; Tue, 1 Sep 2020 03:58:21 -0700 (PDT) Received: by mail-wm1-x343.google.com with SMTP id b79so701334wmb.4 for ; Tue, 01 Sep 2020 03:58:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/hV9SN8IDBmxdUCYEQZ8yHoyBTK4NFUOsNgfQYw5yus=; b=IfRUPJjaiXhRPOc43TX2u53odOET96rAz1mN0JZFmvzYo6yY98Qmjl3gATz89ygCAE IM1EiUnWY7SQthKHABdfWcwtDddlJ8i3tA9oLM/PqKX0aRtIgp137CZNLt34NQy8uy4S AcU6GXjd0RuinhYIHS62NtKhBptVX8tmUdyYbOD/efgwxAS2HOC3HyqcSNUUKICUXv3y ws7hhd0mdL7IjUuqnIbwam0voMR/3r6i2qH+QpJTV5DjlAqT/kzWAmmCGcEvYKKN5bW5 Iown9o1NXMX4Le0gXDs033usJYrJPY+DQbo/pjx8g8+Gar8u92dJGXsvIzWzucOZHQ23 vqDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/hV9SN8IDBmxdUCYEQZ8yHoyBTK4NFUOsNgfQYw5yus=; b=dT7CSxiyR+8WU7rJCXBP5ifHXavF1Y9Axa0uN+YGmxEoHAPvoZX3NuGqB3bbEkioyG HhRsFsXljXmtM078M+o0NvbyXp8zOT1+dwMrh0SPb5UBn79ym2pBhfDPYol5uO6guh+c 2s3kEK+fDaiBNAwN8YrNaVCqgf+aFNjjanZtzR99bSUXT/WgtsV3R0l36CFqseRSOxdK H0ZETXYh7Fq1+9gHFWai+wG8Ez+xUeeuCk/+D8KoS0Tg7bVbDVmnQNASxbbcqkFdT5Re RmRQRYm9iOr391TH7/7cnn+lkVFqmT94wmnaAj1qe2f8D6SijH4uxLbqpzlA8740nk/2 CHFA== X-Gm-Message-State: AOAM532cdlO9O9+9x3Oxjxe32AFZI4iLIPd4BE4ObmZeHqXZbG+LVqI+ mWRqKfVJz8SIf2Kuq6umNix6+if6z4Y= X-Google-Smtp-Source: ABdhPJwCFjSYuZHQV7cjaL+i3danrpf812K6gRbYZK0WKSYChc9wKHWhNemOpkdNQRLa5DQXhoNaGg== X-Received: by 2002:a1c:ed0e:: with SMTP id l14mr1188889wmh.140.1598957899712; Tue, 01 Sep 2020 03:58:19 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:19 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 09/11] merge: use the "octopus" strategy without forking Date: Tue, 1 Sep 2020 12:57:03 +0200 Message-Id: <20200901105705.6059-10-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches `git merge' to invoke the "octopus" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- builtin/merge.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/merge.c b/builtin/merge.c index 541d9bed02..90e092ad02 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -744,6 +744,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, } else if (!strcmp(strategy, "resolve")) return merge_strategies_resolve(the_repository, common, head_arg, remoteheads); + else if (!strcmp(strategy, "octopus")) + return merge_strategies_octopus(the_repository, common, + head_arg, remoteheads); else { return try_merge_command(the_repository, strategy, xopts_nr, xopts, From patchwork Tue Sep 1 10:57:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747901 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 69A7217FB for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4E66E206EF for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hlHwEvhe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726623AbgIALAE (ORCPT ); Tue, 1 Sep 2020 07:00:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40390 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726426AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 71679C06125C for ; Tue, 1 Sep 2020 03:58:22 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id s13so691825wmh.4 for ; Tue, 01 Sep 2020 03:58:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sRwrzj3BPk/K48IuZFLFzUEIerK1jDcOigS9kfN8NR0=; b=hlHwEvhe1ql6Hjdg72/GfvshPBICeJH6b3IP2n98A7zoM6fZteHtXeeA1jPMl9hbNy VQF5GFM/IghV2HzvNvbPA6WrPt3xkYCDfCt1z5FpHOIubWEKLCmqI6r4ZzN4d5cZdFyk iPJCTLaMBB7zcFoBYGxff2kP3g44G1CMlIk3xN7+b5rdO9IO/bDUdbrsOJDPJ1L+82Hw Jj3Y3BqHHmPWmQvWnGVj4StJ3bCs0ICN7fmUdignXpk+J/sGBaR4JTRsFYAA/KkXWvHz TLa3i7Czy2ZeULbGDvqqmvGXhfxEC/739/LzTwwlRtd5YFG6jzwNPuD95cWNqEOJ0jTo MDZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sRwrzj3BPk/K48IuZFLFzUEIerK1jDcOigS9kfN8NR0=; b=PKr8sKfuBhLIcJEKZnHcQ+RZ1kOY05dK4SFz6ejk7CKN/q8WjLBlef7TUsNT3efxLL y5IWEwdRGixGUAVxI8al+8n/Rbb1drkWNlY9KTBQ5Ntsojd7Nr4Ev56AwHops17d9gWB AvFbIpgCBiWgX4viFMVSk27R5IUe17xQ9Vzju6SqyvjG3tWWo0w6lD/d1f7QLTpa3DVh 05yMZv5ujBlUK/3Wzl+NsW5I3KSdyoQTIzP8VaIa/GoXgd2rGNv4+JFZjhAugOd4WJhn D4sBrVPdPRA0ZXu5977zlnF695pPu/+z7VAgucPNtJJKujq+WfkHJEy9RNExIIBxrmeU FM0Q== X-Gm-Message-State: AOAM533cAgubHLECR5MuThEjZc1v0LoBgsCrLS9mO/Ma6fThDxpYiJns hL5NSt2inEAGqqAnx2vSKbyY1fS+lbY= X-Google-Smtp-Source: ABdhPJwtzkSsUgdLtG48hKNFnW0veztMLP98KMEj5yd42gwNUe1UXdLzBSMvy7RzcUJSKFyqgp/TZw== X-Received: by 2002:a1c:7918:: with SMTP id l24mr1279369wme.46.1598957900894; Tue, 01 Sep 2020 03:58:20 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:20 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 10/11] sequencer: use the "resolve" strategy without forking Date: Tue, 1 Sep 2020 12:57:04 +0200 Message-Id: <20200901105705.6059-11-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches the sequencer to invoke the "resolve" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- sequencer.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 2425896911..c4c7b28d24 100644 --- a/sequencer.c +++ b/sequencer.c @@ -33,6 +33,7 @@ #include "commit-reach.h" #include "rebase-interactive.h" #include "reset.h" +#include "merge-strategies.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -1922,9 +1923,15 @@ static int do_pick_commit(struct repository *r, commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(r, opts->strategy, - opts->xopts_nr, (const char **)opts->xopts, - common, oid_to_hex(&head), remotes); + + if (!strcmp(opts->strategy, "resolve")) { + repo_read_index(r); + res |= merge_strategies_resolve(r, common, oid_to_hex(&head), remotes); + } else + res |= try_merge_command(r, opts->strategy, + opts->xopts_nr, (const char **)opts->xopts, + common, oid_to_hex(&head), remotes); + free_commit_list(common); free_commit_list(remotes); } From patchwork Tue Sep 1 10:57:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11747905 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AF60C18E4 for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 92F6B2151B for ; Tue, 1 Sep 2020 11:01:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WOgmH0Ip" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726625AbgIALAn (ORCPT ); Tue, 1 Sep 2020 07:00:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726455AbgIAK6f (ORCPT ); Tue, 1 Sep 2020 06:58:35 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 93D52C06125E for ; Tue, 1 Sep 2020 03:58:23 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id e17so700491wme.0 for ; Tue, 01 Sep 2020 03:58:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=UP0BDiHyOIXjIhcXINm+wriN40jQBqFkCxfYopWe1MQ=; b=WOgmH0Ip3bOynHjHg4HN1bsQpit1U9Jc05sVWM3uyS5qqvBBkzAOop6wskhH3WRemb tfYPEVN6a2p5GT7svCwXBjCp51MRgTNNg/Mumn7u9pxwYa0oeH+MZP0e3lrxldR2zN3j 6Y6oKlXJcwjCuQL61wLuXFN57xvNU3TpeLoYv0QuIcvHFduSH/mJDnUt/nUQEUtExn8o s/7QyobOWosbte78fJTRUp5+GgbBF4rhflI1Zd/DNTo4gnpWOxJOGaUgCYkGMG4lMoJp HHN2JzhMr5wj/6BppYRbqzWhTbafGaqqTuCkXX4OdKMA9EpC9u+nAIEB2PJFPa+Qs+CL AdUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UP0BDiHyOIXjIhcXINm+wriN40jQBqFkCxfYopWe1MQ=; b=aR60BzuCVQfSrYGRUSCYzoL9PjGAHESoGCj8Do87wUb1ssv5q9zu1GttoZuTONPuxf iziV3NFq2IZrR7xXRJNJ3kIr4jjOahKQrNq4bGcRlGQujdeR3PYcBIjchdyIbhhVq28z UQTtH2nt1VpS+j2NZN5fJ3H/Tai7Dnz8GxTCyT2D8UJBIJbBiOhLhk/ik+Jy2sh2/Lx4 57lr47wUM///aM8itZ1syP8zrHLrkbZ1IBZgyqN4C6N8TVD5JGlyQqeD2xmGXO4SW1Fl oxcw+gm8bjUQSnensH5Sht0/XWB1teCKP8Pks6VF8RPBTzDuObYJKI5rb7fXTxGzb4Y1 gRUQ== X-Gm-Message-State: AOAM532ELh8LXNPlQB9Tyl5JpBi0tWqAVkrG0InMs2QkeJN1y5jyQOi0 ljWw3rdtB83+0knVhOznwgJdwitBCC8= X-Google-Smtp-Source: ABdhPJzKsN/T7CRXUavm7kkj3fiPLQuBCHcDfwbq85pQCJF9ZUN2wyhvar2wu3dk/VfiZ8DsWHxHSw== X-Received: by 2002:a7b:c775:: with SMTP id x21mr1162241wmk.47.1598957902024; Tue, 01 Sep 2020 03:58:22 -0700 (PDT) Received: from ylate.lan (atoulouse-654-1-378-135.w86-199.abo.wanadoo.fr. [86.199.233.135]) by smtp.googlemail.com with ESMTPSA id x16sm1705875wrq.62.2020.09.01.03.58.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 03:58:21 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , phillip.wood@dunelm.org.uk, Alban Gruin Subject: [PATCH v2 11/11] sequencer: use the "octopus" merge strategy without forking Date: Tue, 1 Sep 2020 12:57:05 +0200 Message-Id: <20200901105705.6059-12-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200901105705.6059-1-alban.gruin@gmail.com> References: <20200625121953.16991-1-alban.gruin@gmail.com> <20200901105705.6059-1-alban.gruin@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This teaches the sequencer to invoke the "octopus" strategy with a function call instead of forking. Signed-off-by: Alban Gruin --- sequencer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sequencer.c b/sequencer.c index c4c7b28d24..34853b8970 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1927,6 +1927,9 @@ static int do_pick_commit(struct repository *r, if (!strcmp(opts->strategy, "resolve")) { repo_read_index(r); res |= merge_strategies_resolve(r, common, oid_to_hex(&head), remotes); + } else if (!strcmp(opts->strategy, "octopus")) { + repo_read_index(r); + res |= merge_strategies_octopus(r, common, oid_to_hex(&head), remotes); } else res |= try_merge_command(r, opts->strategy, opts->xopts_nr, (const char **)opts->xopts,