From patchwork Tue Aug 9 18:54:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939877 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 4E4E1C19F2D for ; Tue, 9 Aug 2022 19:09:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345761AbiHITJ2 (ORCPT ); Tue, 9 Aug 2022 15:09:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43356 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345698AbiHITI6 (ORCPT ); Tue, 9 Aug 2022 15:08:58 -0400 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 5E3E41CFDA for ; Tue, 9 Aug 2022 11:55:26 -0700 (PDT) Received: by mail-wr1-x42f.google.com with SMTP id l4so15268628wrm.13 for ; Tue, 09 Aug 2022 11:55:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=gtJJT2CWN5LP9jVWyKeIJcyps2N5tS2OX869fEppxYk=; b=JIl4jXJSN6Me+brH5JEng056KikOySU14/bvK3+X+YpFbWFTbrDm4AP+OAXQBj4k0O JIcqoe6v8Id/V2DVHiEJ9LlSfAhJGTn+2/UgVwCmie+gxCnfd3yTfgHOavJ6Ffmey5zz QhzPJ7yqdGYkOroP8BNTrikU5C3D2qvB/EDl5a313i6e2PWjESxoCVlVrjnGADfKMx8N QJghU4h00oXYJftlH0f8WAVLXiKO+f6XdhkpwHfBn4Jimy88fX1toDtql5+VctelGqMW mh+OZaKd86Po90S53pZebtZEofxFEIsmXw0YqQ1ASGXvgr1C02b5pIAzqZsZ1+bI/Vz+ Jv2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=gtJJT2CWN5LP9jVWyKeIJcyps2N5tS2OX869fEppxYk=; b=ZUzK3r25jlC2PYJ+FBUO6YpFQUI93LLlxEn7u3kz/HYBpnLU6YCEGeQa5SBee7Hbj/ HsUxrIpv/kDbbjbi+cTQ870iyYZiqdr3gY68wvg3rxeGJu8KwAqexXa3OMUx4vZNPDn0 sXzU3oKo76WoZOZQfLTa9jDr1//FKVBmiNkGwYQX/NyQrvZQ+rWtQKtGFtsPeyT6Dhnq LZYg5u7MuVdf5/WvVk5qjD0hvyVEpa+ExBt/yE2OjlqEbTyvMY1ul+OY5MHqwm6oxlQZ 9lHo90DPZGFrP31rligg2+qt1Y9db+1XuMvVk26uP8enc5cCCALGB+Tw8HgpIPx6XrZi 2uhA== X-Gm-Message-State: ACgBeo00AvY8oQ+pdwWukLeFMtKpZj546soOb/IEYbJS6Adg6HlCxNs5 nh6jH9ot9/KK5eBSRMbZmhCb8WFxrKg= X-Google-Smtp-Source: AA6agR4NgvmJKK/GfUXkIJy+VC5Ipx7vGpWJA0H673wnZ/SpUhde834mHxgKG3SurBV/DP35tCbAog== X-Received: by 2002:a5d:59a5:0:b0:222:c5a5:59c4 with SMTP id p5-20020a5d59a5000000b00222c5a559c4mr8456006wrr.656.1660071324932; Tue, 09 Aug 2022 11:55:24 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:24 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 01/14] t6060: modify multiple files to expose a possible issue with merge-index Date: Tue, 9 Aug 2022 20:54:16 +0200 Message-Id: <20220809185429.20098-2-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Currently, merge-index iterates over every index entry, skipping stage0 entries. It will then count how many entries following the current one have the same name, then fork to do the merge. It will then increase the iterator by the number of entries to skip them. This behaviour is correct, as even if the subprocess modifies the index, merge-index does not reload it at all. But when it will be rewritten to use a function, the index it will use will be modified and may shrink when a conflict happens or if a file is removed, so we have to be careful to handle such cases. Here is an example: * Merge branches, file1 and file2 are trivially mergeable. |\ | * Modifies file1 and file2. * | Modifies file1 and file2. |/ * Adds file1 and file2. When the merge happens, the index will look like that: i -> 0. file1 (stage1) 1. file1 (stage2) 2. file1 (stage3) 3. file2 (stage1) 4. file2 (stage2) 5. file2 (stage3) merge-index handles `file1' first. As it appears 3 times after the iterator, it is merged. The index is now stale, `i' is increased by 3, and the index now looks like this: 0. file1 (stage1) 1. file1 (stage2) 2. file1 (stage3) i -> 3. file2 (stage1) 4. file2 (stage2) 5. file2 (stage3) `file2' appears three times too, so it is merged. With a naive rewrite, the index would look like this: 0. file1 (stage0) 1. file2 (stage1) 2. file2 (stage2) i -> 3. file2 (stage3) `file2' appears once at the iterator or after, so it will be added, _not_ merged. Which is wrong. A naive rewrite would lead to unproperly merged files, or even files not handled at all. This changes t6060 to reproduce this case, by creating 2 files instead of 1, to check the correctness of the soon-to-be-rewritten merge-index. The files are identical, which is not really important -- the factors that could trigger this issue are that they should be separated by at most one entry in the index, and that the first one in the index should be trivially mergeable. Signed-off-by: Alban Gruin --- t/t6060-merge-index.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index ed449abe55..d0d6dec0c8 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -5,16 +5,19 @@ test_description='basic git merge-index / git-merge-one-file tests' test_expect_success 'setup diverging branches' ' test_write_lines 1 2 3 4 5 6 7 8 9 10 >file && - git add file && + cp file file2 && + git add file file2 && git commit -m base && git tag base && sed s/2/two/ tmp && mv tmp file && + cp file file2 && git commit -a -m two && git tag two && git checkout -b other HEAD^ && sed s/10/ten/ tmp && mv tmp file && + cp file file2 && git commit -a -m ten && git tag ten ' @@ -33,8 +36,11 @@ ten EOF test_expect_success 'read-tree does not resolve content merge' ' + cat >expect <<-\EOF && + file + file2 + EOF git read-tree -i -m base ten two && - echo file >expect && git diff-files --name-only --diff-filter=U >unmerged && test_cmp expect unmerged ' From patchwork Tue Aug 9 18:54:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939879 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 1E260C25B06 for ; Tue, 9 Aug 2022 19:09:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345794AbiHITJe (ORCPT ); Tue, 9 Aug 2022 15:09:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344647AbiHITJG (ORCPT ); Tue, 9 Aug 2022 15:09:06 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 902F9E0CA for ; Tue, 9 Aug 2022 11:55:27 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id z12so15290569wrs.9 for ; Tue, 09 Aug 2022 11:55:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=o0CBaMAnbHqKIU6wgoZiwnGPgTaMvClGaDUwjI8nV8w=; b=Q2Ye4wY0yrE4Ac1oXHyHKBeNtDsibobk4hHW7u5PCvQ5PJW2QqF5lGo0hrnD46EtfB zoYxyp1cNcaoQQ54kDtk4uertOB1ta3qICMK7GFP1qKaBox7sd8HO2f1mjnxm5BvmILM uQDdeD5WXDuCPolS+6WVL4W976FfYBygncC5WIp5fnr6aGyL99eE8BcxEGngnZ51eXeo LDVOeI5ucXcegg3N3dhUacJ+7xXHvRF8k7ItxRH7ZKi13owJOwBHYuTZryWOF8mIrEQF 4clgYToZdO2raEp8cggbi+d80miFWO5s9h121A186CRYjoUW+fnJtkRiNL1yWBNDS8RC lkvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=o0CBaMAnbHqKIU6wgoZiwnGPgTaMvClGaDUwjI8nV8w=; b=y3x7uHJrtlE2LBYAE+hRTFiydFl7O35dmQB+OzBs8tzVt/6KNJT0q8zx8b5L+69PVf UqQRDKEL/5lFVASLcVgWaFbymz3mEF5C6J5csJu4FXWImFRxM7NRTTH/zyhUfLgapyMf TScR3NA+YISaRQpROLu11b09s9IZFjsO6pExYhytkBanHh2gEDfmYlTJYUWXhPo5Qtvc LS+X/0tXuan02oaNeFFlm4tKOcKvSyzXCiVCyVaw8tC2KMAWjFqkFqRle9E6INCreCIg Wk56hqYGl/6+fou7QaIt/rStGrKK9M4qfR8QY//k2GrFl5xrUptrmWvzSJ88lf5uOqUI yM6Q== X-Gm-Message-State: ACgBeo3GTmyNY5vPfISVUTbM+DDuQfHlSmtjwX3DiHceXU60WANB4ky/ 2NOwDauZWKqb5fec8b5HKP/S3q6wA7c= X-Google-Smtp-Source: AA6agR6DHxp1hhkQ6iuUyxHgWRRdVNytdFBapH/qpDkuaZ/bAY6f8jbiJdEfxoxoLEne3N2RCwsyYg== X-Received: by 2002:adf:d1e2:0:b0:223:6167:fd00 with SMTP id g2-20020adfd1e2000000b002236167fd00mr4455479wrd.330.1660071326208; Tue, 09 Aug 2022 11:55:26 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:25 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 02/14] t6060: add tests for removed files Date: Tue, 9 Aug 2022 20:54:17 +0200 Message-Id: <20220809185429.20098-3-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Until now, t6060 did not not check git-merge-one-file's behaviour when a file is deleted in a branch. To avoid regressions on this during the conversion from shell to C, this adds a new file, `file3', in the commit tagged as `base', and deletes it in the commit tagged as `two'. Signed-off-by: Alban Gruin --- t/t6060-merge-index.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index d0d6dec0c8..bb4da4bbb2 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -6,12 +6,14 @@ test_description='basic git merge-index / git-merge-one-file tests' test_expect_success 'setup diverging branches' ' test_write_lines 1 2 3 4 5 6 7 8 9 10 >file && cp file file2 && - git add file file2 && + cp file file3 && + git add file file2 file3 && git commit -m base && git tag base && sed s/2/two/ tmp && mv tmp file && cp file file2 && + git rm file3 && git commit -a -m two && git tag two && git checkout -b other HEAD^ && @@ -39,6 +41,7 @@ test_expect_success 'read-tree does not resolve content merge' ' cat >expect <<-\EOF && file file2 + file3 EOF git read-tree -i -m base ten two && git diff-files --name-only --diff-filter=U >unmerged && From patchwork Tue Aug 9 18:54:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939880 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 92996C19F2D for ; Tue, 9 Aug 2022 19:09:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345795AbiHITJi (ORCPT ); Tue, 9 Aug 2022 15:09:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43364 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345712AbiHITJG (ORCPT ); Tue, 9 Aug 2022 15:09:06 -0400 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 685EF1FCD2 for ; Tue, 9 Aug 2022 11:55:28 -0700 (PDT) Received: by mail-wm1-x330.google.com with SMTP id c187-20020a1c35c4000000b003a30d88fe8eso9347148wma.2 for ; Tue, 09 Aug 2022 11:55:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=elWVq8d07rynQLykm6um+HWT12gq5M7NUCyGEK5wpak=; b=HxX4ZtegCalzHU2nIwr95/VBvb70OdGkqXhGTp+cYVzk8zpMtfx/77oC+g4MXjuuVl wd6I7DBjPnPTDg9GGSRkq19B9aVCBebw6/fjcYPm7mwiFyvdT9ZzuQ/7I2mYynExQmlj 15hFJifApz1FnKOnADlixDZ9Mn0MS3mMMlw83n0tD02HCcD8dRmNjaX+1NJi4kXq/tLI WIfjgzb5G8O32Lvrx3NCH8sH5wHqWuf7LWO3B4IzRu5RA6lJxzyCkL5RqwUNq/Tidxf5 iNCCHo31SZyzSnvDanM0pdRJyXZKXVTzYxhIkIiD3V622KbohhufAvlZdW/zVK3VOjq5 EJSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=elWVq8d07rynQLykm6um+HWT12gq5M7NUCyGEK5wpak=; b=Um/2VFZZnOPnVfWJa+ra4coJdb+2rPUSxTLjl3l3lxezfpACZnEFuFNuMw+1B8vFCe kpQX/J//nNDZUpmNEPwcSvj9LRCVRKR07gH5fJctvrp2YD+a3tniWrxq3UF7lHcjazGx 72sIl4pN6I89yOwZn2koQigpqqq++5K359pP6330TGi9dhyQKVBZ4QUjIF4RQ7Wu5gJP kimPJUStm0XEv9i3qvmChEEesDcCUq3YaR4sF+jegcYn+Dt+GA4Nohy+5NrKDxQzZNs+ CxZO9yKdDwnavbQOY9bUHdPCyug1TQA+/2jKkOxTem0iYVnhk8fGvgzw10lwUhi2hXVW nAHQ== X-Gm-Message-State: ACgBeo0L+Rls33IbT44pn8Zi2cc2KET4UplkW/DUNPjhnZQ6AxAmYiAl VCcH8EVMULBEicVABptwvgLr4oMVxG8= X-Google-Smtp-Source: AA6agR6W5G2PTgHwEssi1JolnCG7USgcFqS3NY934HCrncGy5VALtAz86saA0EZkg6PN882J2fADng== X-Received: by 2002:a7b:ce12:0:b0:3a5:4d8b:65df with SMTP id m18-20020a7bce12000000b003a54d8b65dfmr5757894wmc.27.1660071327014; Tue, 09 Aug 2022 11:55:27 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:26 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 03/14] merge-index: libify merge_one_path() and merge_all() Date: Tue, 9 Aug 2022 20:54:18 +0200 Message-Id: <20220809185429.20098-4-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The "resolve" and "octopus" merge strategies do not call directly `git merge-one-file', they delegate the work to another git command, `git merge-index', that will loop over files in the index and call the specified command. Unfortunately, these functions are not part of libgit.a, which means that once rewritten, the strategies would still have to invoke `merge-one-file' by spawning a new process first. To avoid this, this moves and renames merge_one_path(), merge_all(), and their helpers to merge-strategies.c. They also take a callback to dictate what they should do for each file. For now, to preserve the behaviour of `merge-index', only one callback, launching a new process, is defined. Signed-off-by: Alban Gruin --- Makefile | 1 + builtin/merge-index.c | 92 ++++++++++++++---------------------------- merge-strategies.c | 82 +++++++++++++++++++++++++++++++++++++ merge-strategies.h | 18 +++++++++ t/t7607-merge-state.sh | 2 +- 5 files changed, 133 insertions(+), 62 deletions(-) create mode 100644 merge-strategies.c create mode 100644 merge-strategies.h diff --git a/Makefile b/Makefile index 2ec9b2dc6b..40d1be4e5e 100644 --- a/Makefile +++ b/Makefile @@ -991,6 +991,7 @@ LIB_OBJS += merge-blobs.o LIB_OBJS += merge-ort.o LIB_OBJS += merge-ort-wrappers.o LIB_OBJS += merge-recursive.o +LIB_OBJS += merge-strategies.o LIB_OBJS += merge.o LIB_OBJS += midx.o LIB_OBJS += name-hash.o diff --git a/builtin/merge-index.c b/builtin/merge-index.c index c0383fe9df..f66cc515d8 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,76 +1,43 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" +#include "merge-strategies.h" #include "run-command.h" static const char *pgm; -static int one_shot, quiet; -static int err; -static int merge_entry(int pos, const char *path) +static int merge_one_file_spawn(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, + void *data) { - int found; - const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL }; - char hexbuf[4][GIT_MAX_HEXSZ + 1]; - char ownbuf[4][60]; + char oids[3][GIT_MAX_HEXSZ + 1] = {{0}}; + char modes[3][10] = {{0}}; + const char *arguments[] = { pgm, oids[0], oids[1], oids[2], + path, modes[0], modes[1], modes[2], NULL }; - if (pos >= active_nr) - die("git merge-index: %s not in the cache", path); - found = 0; - do { - const struct cache_entry *ce = active_cache[pos]; - int stage = ce_stage(ce); - - if (strcmp(ce->name, path)) - break; - found++; - oid_to_hex_r(hexbuf[stage], &ce->oid); - xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); - arguments[stage] = hexbuf[stage]; - arguments[stage + 4] = ownbuf[stage]; - } while (++pos < active_nr); - if (!found) - die("git merge-index: %s not in the cache", path); - - if (run_command_v_opt(arguments, 0)) { - if (one_shot) - err++; - else { - if (!quiet) - die("merge program failed"); - exit(1); - } + if (orig_blob) { + oid_to_hex_r(oids[0], orig_blob); + xsnprintf(modes[0], sizeof(modes[0]), "%06o", orig_mode); } - return found; -} - -static void merge_one_path(const char *path) -{ - int pos = cache_name_pos(path, strlen(path)); - /* - * If it already exists in the cache as stage0, it's - * already merged and there is nothing to do. - */ - if (pos < 0) - merge_entry(-pos-1, path); -} + if (our_blob) { + oid_to_hex_r(oids[1], our_blob); + xsnprintf(modes[1], sizeof(modes[1]), "%06o", our_mode); + } -static void merge_all(void) -{ - int i; - /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - i += merge_entry(i, ce->name)-1; + if (their_blob) { + oid_to_hex_r(oids[2], their_blob); + xsnprintf(modes[2], sizeof(modes[2]), "%06o", their_mode); } + + return run_command_v_opt(arguments, 0); } int cmd_merge_index(int argc, const char **argv, const char *prefix) { - int i, force_file = 0; + int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -94,7 +61,9 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) quiet = 1; i++; } + pgm = argv[i++]; + for (; i < argc; i++) { const char *arg = argv[i]; if (!force_file && *arg == '-') { @@ -103,14 +72,15 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-a")) { - merge_all(); + err |= merge_all_index(&the_index, one_shot, quiet, + merge_one_file_spawn, NULL); continue; } die("git merge-index: unknown option %s", arg); } - merge_one_path(arg); + err |= merge_index_path(&the_index, one_shot, quiet, arg, + merge_one_file_spawn, NULL); } - if (err && !quiet) - die("merge program failed"); + return err; } diff --git a/merge-strategies.c b/merge-strategies.c new file mode 100644 index 0000000000..418c9dd710 --- /dev/null +++ b/merge-strategies.c @@ -0,0 +1,82 @@ +#include "cache.h" +#include "merge-strategies.h" + +static int merge_entry(struct index_state *istate, unsigned int pos, + const char *path, int *err, merge_fn fn, void *data) +{ + int found = 0; + const struct object_id *oids[3] = {NULL}; + unsigned int modes[3] = {0}; + + do { + const struct cache_entry *ce = istate->cache[pos]; + int stage = ce_stage(ce); + + if (strcmp(ce->name, path)) + break; + found++; + oids[stage - 1] = &ce->oid; + modes[stage - 1] = ce->ce_mode; + } while (++pos < istate->cache_nr); + if (!found) + return error(_("%s is not in the cache"), path); + + if (fn(istate, oids[0], oids[1], oids[2], path, + modes[0], modes[1], modes[2], data)) + (*err)++; + + return found; +} + +int merge_index_path(struct index_state *istate, int oneshot, int quiet, + const char *path, merge_fn fn, void *data) +{ + int pos = index_name_pos(istate, path, strlen(path)), ret, err = 0; + + /* + * If it already exists in the cache as stage0, it's + * already merged and there is nothing to do. + */ + if (pos < 0) { + ret = merge_entry(istate, -pos - 1, path, &err, fn, data); + if (ret == -1) + return -1; + else if (err) { + if (!quiet && !oneshot) + error(_("merge program failed")); + return 1; + } + } + return 0; +} + +int merge_all_index(struct index_state *istate, int oneshot, int quiet, + merge_fn fn, void *data) +{ + int err = 0, ret; + unsigned int i; + + /* TODO: audit for interaction with sparse-index. */ + ensure_full_index(istate); + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; + if (!ce_stage(ce)) + continue; + + ret = merge_entry(istate, i, ce->name, &err, fn, data); + if (ret > 0) + i += ret - 1; + else if (ret == -1) + return -1; + + if (err && !oneshot) { + if (!quiet) + error(_("merge program failed")); + return 1; + } + } + + if (err && !quiet) + error(_("merge program failed")); + return err; +} diff --git a/merge-strategies.h b/merge-strategies.h new file mode 100644 index 0000000000..88f476f170 --- /dev/null +++ b/merge-strategies.h @@ -0,0 +1,18 @@ +#ifndef MERGE_STRATEGIES_H +#define MERGE_STRATEGIES_H + +#include "object.h" + +typedef int (*merge_fn)(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, + void *data); + +int merge_index_path(struct index_state *istate, int oneshot, int quiet, + const char *path, merge_fn fn, void *data); +int merge_all_index(struct index_state *istate, int oneshot, int quiet, + merge_fn fn, void *data); + +#endif /* MERGE_STRATEGIES_H */ diff --git a/t/t7607-merge-state.sh b/t/t7607-merge-state.sh index 89a62ac53b..96befa5b80 100755 --- a/t/t7607-merge-state.sh +++ b/t/t7607-merge-state.sh @@ -20,7 +20,7 @@ test_expect_success 'Ensure we restore original state if no merge strategy handl # just hit conflicts, it completely fails and says that it cannot # handle this type of merge. test_expect_code 2 git merge branch2 branch3 >output 2>&1 && - grep "fatal: merge program failed" output && + grep "error: merge program failed" output && grep "Should not be doing an octopus" output && # Make sure we did not leave stray changes around when no appropriate From patchwork Tue Aug 9 18:54:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939882 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 61F16C19F2D for ; Tue, 9 Aug 2022 19:09:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345819AbiHITJn (ORCPT ); Tue, 9 Aug 2022 15:09:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45458 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344826AbiHITJH (ORCPT ); Tue, 9 Aug 2022 15:09:07 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30ED11FCD1 for ; Tue, 9 Aug 2022 11:55:29 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id j7so15333834wrh.3 for ; Tue, 09 Aug 2022 11:55:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=Cit47d/USdckqIdFx1bqdLYm9Vxj3ZE//AEQ78K9c/w=; b=q1SAHeZaMjL1j5ZBv0yibRrpfMqkPw0SSJamRBW8Lfh5ib0nOjhPw/+kGM0XGllJJU n5Z4T+jm4DktWSqLY+wmzo5dDzWC4823EiLvPQ+5QW8THcyTawJ7fu7kv+21XXCNgpi8 Z3fJLNtqCWD9rwX1CGvMz5eX6OZ9qiIoVAgdOcnG+AslP19gVoPrGGDSqV1ncknf3UCQ rQ67g6sNJ/3U0YrlwY3hFER1gcLRQWG31CH4S8ELGa3vqQYmZD1hLbDaMOj3/r0FlkEz vFJILan3m33eyRG+6ZunrJKZoGrUJoCnPZsOxFh25p8VufxPPOPOEuuU3bonN3XR65PQ 80tA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=Cit47d/USdckqIdFx1bqdLYm9Vxj3ZE//AEQ78K9c/w=; b=yfQsGEV4693I7LP7XN9kPaqaCBXpRToB50j4HcNV9ZHVihL8KndaYWx4vqGQ2sdH1y CIvt8x2vJ1o3R0TzbUl+tt/B1s7Ty3+/KAoE4iWXreTGwhCQ/xGFUtgvnMxTvLVjMXAh psIb+Dem6HNHpoxdez1GCLeETC7ZMh9VIznXJu4y0i+fpabHUy+m9PUXQhgGMSWW4tij 5QcQszVrwg88dppaMuwqNy3eGVNz22gNyG+WDkyIxuvOmJVMO14h/3ZD4UoiG+AQpayQ QBJWy0mCVniGxllyS/J2BL00VaMDY/r0fJAPz0vDDXomvfZvoEGBkHJEKl5Rwto0ewPR to9Q== X-Gm-Message-State: ACgBeo068Pyse3quEo47Tb2cR/sIgk/enERJI7D6+MvtRH7PLlExodFD n5K3xPqeDySRoKtxfKRropWmKpUNfEE= X-Google-Smtp-Source: AA6agR6zORK365bS1rmmieLr7Gkk4VGTAt+WhYeUZhCupnwFVz/c1GV4xvBON/2xHmcA2+JdhdGZfQ== X-Received: by 2002:a5d:4889:0:b0:21d:eab7:f798 with SMTP id g9-20020a5d4889000000b0021deab7f798mr15129392wrq.96.1660071327726; Tue, 09 Aug 2022 11:55:27 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:27 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 04/14] merge-index: drop the index Date: Tue, 9 Aug 2022 20:54:19 +0200 Message-Id: <20220809185429.20098-5-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org In an effort to reduce the usage of the global index throughout the codebase, this removes references to it in `git merge-index'. Signed-off-by: Alban Gruin --- builtin/merge-index.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index f66cc515d8..9d74b6e85c 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,4 +1,3 @@ -#define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" #include "merge-strategies.h" #include "run-command.h" @@ -38,6 +37,7 @@ static int merge_one_file_spawn(struct index_state *istate, int cmd_merge_index(int argc, const char **argv, const char *prefix) { int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; + struct repository *r = the_repository; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -47,10 +47,11 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) if (argc < 3) usage("git merge-index [-o] [-q] (-a | [--] [...])"); - read_cache(); + if (repo_read_index(r) < 0) + die("invalid index"); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&the_index); + ensure_full_index(r->index); i = 1; if (!strcmp(argv[i], "-o")) { @@ -72,13 +73,13 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-a")) { - err |= merge_all_index(&the_index, one_shot, quiet, + err |= merge_all_index(r->index, one_shot, quiet, merge_one_file_spawn, NULL); continue; } die("git merge-index: unknown option %s", arg); } - err |= merge_index_path(&the_index, one_shot, quiet, arg, + err |= merge_index_path(r->index, one_shot, quiet, arg, merge_one_file_spawn, NULL); } From patchwork Tue Aug 9 18:54:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939881 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 E0E5CC25B08 for ; Tue, 9 Aug 2022 19:09:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345802AbiHITJl (ORCPT ); Tue, 9 Aug 2022 15:09:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43626 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345699AbiHITJH (ORCPT ); Tue, 9 Aug 2022 15:09:07 -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 1D1421F624 for ; Tue, 9 Aug 2022 11:55:30 -0700 (PDT) Received: by mail-wr1-x42d.google.com with SMTP id j7so15333867wrh.3 for ; Tue, 09 Aug 2022 11:55:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=Tb0RwUZ46/MxCQYiDDQvnRO982rWhA3+X/4oEcbOulo=; b=iJwVN1YYSAKoJ7d5AJgKdIRgIfdL9Wu8lioDrQSotDMg2S4rAmXfq1+M5xF2MoH2Cs BXxMpiSkQQKgCevKzmURHFM9CiLvJ7Lsscr5S94m8YMd9IhxLnF2Ec1JFIHCpC1oPq2H OgSEs5SM4ktprc03EAvBxwo7ZKXJyzmGe9xggMjH291qkPf/BOuEKmBW6TQQ8EoQdhg6 O48npMmavpB7sVGy6IA0ts7pgrjTfrJ58wE+WM5rW/Tvvv0aW6tYr6xxBha6FTePwFev sbvISAoIgtRuydvV7kXeTpPBw65MIPbqvbGaRJOcl5U3MLSrlhvDyaSEkebYusW8TIB+ xeJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=Tb0RwUZ46/MxCQYiDDQvnRO982rWhA3+X/4oEcbOulo=; b=yQi5O4ZfqMBJ+I+Bx6AQ8AnGwV9ZDpUy2rUaUzQ3r1X+Fqq57ZXIwaYOej69PaszFO hi/AOMtbmjSPTT9GsQycWpRLNaqh5wt6sydzfPEQnSmL5RsnfmdhDASVUpSVg8puWD2X GelhgIx7cK8NyyNZNdjbqcOZyjHJ3vXQpQcJQTCLSxMO3hHF4/G/allpxrro61jQ/HWO a42LjGFhDqyiX3rfRMvGSkvULHW2qmRqmsZmjx7BJx1FbLRr1MR7LaNNKOwDTcbJ40Ta Z8U1eMtqJEBdNj011DEN0ktS0/4HyD5kj7GxuBeFaNAhgjIk4qH2E34VchNHjprGd74o GBGw== X-Gm-Message-State: ACgBeo0gn390x54rUAW2CQ/89jZ8wPEEUimdiVfqRVN/LPDjM2GEiYaV Cv2UBT2E9ELVwAIW/l/QniBAztflA6M= X-Google-Smtp-Source: AA6agR53LjRO8L6/6w41xxsHlmMgdghbKIj4I9+AEsJSADdOAT0U7u23beQAaK0REgjDZEIYy1UxbQ== X-Received: by 2002:a5d:6c63:0:b0:220:5e4d:c6e9 with SMTP id r3-20020a5d6c63000000b002205e4dc6e9mr15660954wrz.250.1660071328678; Tue, 09 Aug 2022 11:55:28 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:28 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 05/14] merge-index: add a new way to invoke `git-merge-one-file' Date: Tue, 9 Aug 2022 20:54:20 +0200 Message-Id: <20220809185429.20098-6-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Since `git-merge-one-file' will be rewritten and libified, there may be cases where there is no executable named this way (ie. when git is compiled with `SKIP_DASHED_BUILT_INS' enabled). This adds a new way to invoke this particular program even if it does not exist, by passing `--use=merge-one-file' to merge-index. For now, it still forks. The test suite and shell scripts (git-merge-octopus.sh and git-merge-resolve.sh) are updated to use this new convention. Signed-off-by: Alban Gruin --- Documentation/git-merge-index.txt | 7 ++++--- builtin/merge-index.c | 25 ++++++++++++++++++++++--- git-merge-octopus.sh | 2 +- git-merge-resolve.sh | 2 +- t/t6060-merge-index.sh | 8 ++++---- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.txt index eea56b3154..622638a13b 100644 --- a/Documentation/git-merge-index.txt +++ b/Documentation/git-merge-index.txt @@ -9,7 +9,7 @@ git-merge-index - Run a merge for files needing merging SYNOPSIS -------- [verse] -'git merge-index' [-o] [-q] (-a | ( [--] ...) ) +'git merge-index' [-o] [-q] ( | --use=merge-one-file) (-a | ( [--] ...) ) DESCRIPTION ----------- @@ -44,8 +44,9 @@ code. Typically this is run with a script calling Git's imitation of the 'merge' command from the RCS package. -A sample script called 'git merge-one-file' is included in the -distribution. +A sample script called 'git merge-one-file' used to be included in the +distribution. This program must now be called with +'--use=merge-one-file'. ALERT ALERT ALERT! The Git "merge object order" is different from the RCS 'merge' program merge object order. In the above ordering, the diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 9d74b6e85c..aba3ba5694 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "lockfile.h" #include "merge-strategies.h" #include "run-command.h" @@ -37,7 +38,10 @@ static int merge_one_file_spawn(struct index_state *istate, int cmd_merge_index(int argc, const char **argv, const char *prefix) { int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; + merge_fn merge_action = merge_one_file_spawn; + struct lock_file lock = LOCK_INIT; struct repository *r = the_repository; + const char *use_internal = NULL; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -45,7 +49,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) signal(SIGCHLD, SIG_DFL); if (argc < 3) - usage("git merge-index [-o] [-q] (-a | [--] [...])"); + usage("git merge-index [-o] [-q] ( | --use=merge-one-file) (-a | [--] [...])"); if (repo_read_index(r) < 0) die("invalid index"); @@ -64,6 +68,14 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) } pgm = argv[i++]; + setup_work_tree(); + + if (skip_prefix(pgm, "--use=", &use_internal)) { + if (!strcmp(use_internal, "merge-one-file")) + pgm = "git-merge-one-file"; + else + die(_("git merge-index: unknown internal program %s"), use_internal); + } for (; i < argc; i++) { const char *arg = argv[i]; @@ -74,13 +86,20 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "-a")) { err |= merge_all_index(r->index, one_shot, quiet, - merge_one_file_spawn, NULL); + merge_action, NULL); continue; } die("git merge-index: unknown option %s", arg); } err |= merge_index_path(r->index, one_shot, quiet, arg, - merge_one_file_spawn, NULL); + merge_action, NULL); + } + + if (is_lock_file_locked(&lock)) { + if (err) + rollback_lock_file(&lock); + else + return write_locked_index(r->index, &lock, COMMIT_LOCK); } return err; diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 7d19d37951..2770891960 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -100,7 +100,7 @@ do if test $? -ne 0 then gettextln "Simple merge did not work, trying automatic merge." - git merge-index -o git-merge-one-file -a || + git merge-index -o --use=merge-one-file -a || OCTOPUS_FAILURE=1 next=$(git write-tree 2>/dev/null) fi diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh index 77e93121bf..e59175eb75 100755 --- a/git-merge-resolve.sh +++ b/git-merge-resolve.sh @@ -55,7 +55,7 @@ then exit 0 else echo "Simple merge failed, trying Automatic merge." - if git merge-index -o git-merge-one-file -a + if git merge-index -o --use=merge-one-file -a then exit 0 else diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index bb4da4bbb2..3845a9d3cc 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -48,8 +48,8 @@ test_expect_success 'read-tree does not resolve content merge' ' test_cmp expect unmerged ' -test_expect_success 'git merge-index git-merge-one-file resolves' ' - git merge-index git-merge-one-file -a && +test_expect_success 'git merge-index --use=merge-one-file resolves' ' + git merge-index --use=merge-one-file -a && git diff-files --name-only --diff-filter=U >unmerged && test_must_be_empty unmerged && test_cmp expect-merged file && @@ -81,7 +81,7 @@ test_expect_success 'merge-one-file respects GIT_WORK_TREE' ' export GIT_WORK_TREE && GIT_INDEX_FILE=$PWD/merge.index && export GIT_INDEX_FILE && - git merge-index git-merge-one-file -a && + git merge-index --use=merge-one-file -a && git cat-file blob :file >work/file-index ) && test_cmp expect-merged bare.git/work/file && @@ -96,7 +96,7 @@ test_expect_success 'merge-one-file respects core.worktree' ' export GIT_DIR && git config core.worktree "$PWD/child" && git read-tree -i -m base ten two && - git merge-index git-merge-one-file -a && + git merge-index --use=merge-one-file -a && git cat-file blob :file >file-index ) && test_cmp expect-merged subdir/child/file && From patchwork Tue Aug 9 18:54:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939883 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 31F89C19F2D for ; Tue, 9 Aug 2022 19:09:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345826AbiHITJo (ORCPT ); Tue, 9 Aug 2022 15:09:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345041AbiHITJH (ORCPT ); Tue, 9 Aug 2022 15:09:07 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D166B22281 for ; Tue, 9 Aug 2022 11:55:30 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id s11-20020a1cf20b000000b003a52a0945e8so4493050wmc.1 for ; Tue, 09 Aug 2022 11:55:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=P+p6RXcqgOi2+v2p/94vXgQ8gI+U3h0btCeV1eEBlzw=; b=kWhk3eY6KhVQKWbxnXE4qiz2XIp6XND+Lz8RLGUbnmPzRHhQRNbYDTV5/DjL9q37xz AxoadL3sTA8cxFzh8ZHD7lo9XF/kL4PWpNZ4gUyX5LKQbY0wPezqB2W2pQj3mlxRgGaa a5f0g9F912Ns50e6UxE/j0CQVQV/SmJh7CEmeOmsxaMOs+Eb6eh1Jqc7ngTyDw33bv+u qCY6yyBTvMJ1F3tPLY3PoTim1YaUDPuzhh77xXBvjza3UNHDSZfWdvU6TJ0TK7UAc9Dz D9gkfGpQZEbHgdQ2vtk+/gLHp37MMSJUSh8uBgqIDMcURSd5o5hoTLtRsJJb+5YFsrTp 64zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=P+p6RXcqgOi2+v2p/94vXgQ8gI+U3h0btCeV1eEBlzw=; b=hZr2LnqiJ6cCRjdbuYfAfGvTbOFawk93G8W//wKoPedqy+HCf7RgtkVuBLwjYC/vIR MuyGg1jx5zDJ1gs5Wpf9CLDCNzOodKUTgp1MIGjXGmKd6hm/5ZdXjYk7eb+lqPwmEaHB WAHm+vR4tgc6+XyIHzqkmMtffV2o7pTNTqZRSzqCINZ9pkqHHoZp+sV4wIXX/IdTsiGX MqNro5sOeDZX/lJSym12vXwF00eGlQ0Gs7b2Xou7xByb/94NTZEN8JHuKjqODWCzbvD5 kGsOMWnvA1Ah9DinWw16m5X7z1sylrwO6CSQktCm7E2ncVRVYx8+paq/t4bx396F09WL WZyQ== X-Gm-Message-State: ACgBeo3Qx+I7WBm760VjmIER3qI/vIAJYlblYpcRLxmYJrb9HdWORRPW qxsGArduYZ5q3PB0sgs9O+sYkkwEQzw= X-Google-Smtp-Source: AA6agR5QrW2jzunkfQy0j4Ha40blVgOW16bURnB73TKt2kVtzguTr4YZasyG5QgEmAloJ9/Ai8KPPg== X-Received: by 2002:a05:600c:4f06:b0:3a3:2158:c5ed with SMTP id l6-20020a05600c4f0600b003a32158c5edmr17014314wmq.103.1660071329457; Tue, 09 Aug 2022 11:55:29 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:29 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 06/14] update-index: move add_cacheinfo() to read-cache.c Date: Tue, 9 Aug 2022 20:54:21 +0200 Message-Id: <20220809185429.20098-7-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org This moves the function add_cacheinfo() that already exists in update-index.c to update-index.c, renames it add_to_index_cacheinfo(), and adds an `istate' parameter. The new cache entry is returned through a pointer passed in the parameters. This function can return three values: - 0, when the file has been successfully added to the index; - ADD_TO_INDEX_CACHEINFO_INVALID_PATH, when the file does not exists; - ADD_TO_INDEX_CACHEINFO_UNABLE_TO_ADD, when the file could not be added to the index. This will become useful in the next commit, when the three-way merge will need to call this function. Signed-off-by: Alban Gruin --- builtin/update-index.c | 25 +++++++------------------ cache.h | 8 ++++++++ read-cache.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/builtin/update-index.c b/builtin/update-index.c index b62249905f..2e322a58f2 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -411,27 +411,16 @@ static int process_path(const char *path, struct stat *st, int stat_errno) static int add_cacheinfo(unsigned int mode, const struct object_id *oid, const char *path, int stage) { - int len, option; - struct cache_entry *ce; + int res; - if (!verify_path(path, mode)) - return error("Invalid path '%s'", path); - - len = strlen(path); - ce = make_empty_cache_entry(&the_index, len); - - oidcpy(&ce->oid, oid); - memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(stage); - ce->ce_namelen = len; - ce->ce_mode = create_ce_mode(mode); - if (assume_unchanged) - ce->ce_flags |= CE_VALID; - option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; - option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; - if (add_cache_entry(ce, option)) + res = add_to_index_cacheinfo(&the_index, mode, oid, path, stage, + allow_add, allow_replace, NULL); + if (res == ADD_TO_INDEX_CACHEINFO_INVALID_PATH) + return error(_("Invalid path '%s'"), path); + if (res == ADD_TO_INDEX_CACHEINFO_UNABLE_TO_ADD) return error("%s: cannot add to the index - missing --add option?", path); + report("add '%s'", path); return 0; } diff --git a/cache.h b/cache.h index 4aa1bd079d..6b5d0a2ba3 100644 --- a/cache.h +++ b/cache.h @@ -885,6 +885,14 @@ int remove_file_from_index(struct index_state *, const char *path); int add_to_index(struct index_state *, const char *path, struct stat *, int flags); int add_file_to_index(struct index_state *, const char *path, int flags); +#define ADD_TO_INDEX_CACHEINFO_INVALID_PATH (-1) +#define ADD_TO_INDEX_CACHEINFO_UNABLE_TO_ADD (-2) + +int add_to_index_cacheinfo(struct index_state *, unsigned int mode, + const struct object_id *oid, const char *path, + int stage, int allow_add, int allow_replace, + struct cache_entry **ce_ret); + int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip); int ce_same_name(const struct cache_entry *a, const struct cache_entry *b); void set_object_name_for_intent_to_add_entry(struct cache_entry *ce); diff --git a/read-cache.c b/read-cache.c index 4de207752d..e895bf5c6a 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1436,6 +1436,41 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti return 0; } +int add_to_index_cacheinfo(struct index_state *istate, unsigned int mode, + const struct object_id *oid, const char *path, + int stage, int allow_add, int allow_replace, + struct cache_entry **ce_ret) +{ + int len, option; + struct cache_entry *ce; + + if (!verify_path(path, mode)) + return ADD_TO_INDEX_CACHEINFO_INVALID_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(stage); + ce->ce_namelen = len; + ce->ce_mode = create_ce_mode(mode); + if (assume_unchanged) + ce->ce_flags |= CE_VALID; + option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; + option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; + + if (add_index_entry(istate, ce, option)) { + discard_cache_entry(ce); + return ADD_TO_INDEX_CACHEINFO_UNABLE_TO_ADD; + } + + if (ce_ret) + *ce_ret = ce; + + return 0; +} + /* * "refresh" does not calculate a new sha1 file or bring the * cache up-to-date for mode/content changes. But what it From patchwork Tue Aug 9 18:54:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939884 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 33905C3F6B0 for ; Tue, 9 Aug 2022 19:09:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345832AbiHITJt (ORCPT ); Tue, 9 Aug 2022 15:09:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345721AbiHITJI (ORCPT ); Tue, 9 Aug 2022 15:09:08 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E89BE22510 for ; Tue, 9 Aug 2022 11:55:31 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id n4so13535485wrp.10 for ; Tue, 09 Aug 2022 11:55:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=v4O8So/flSbWMAld2f6/XrXeOJdFqXo/wD/5BCK4Ra4=; b=Q4eaaqSXlGVR/lMz3sqpTSLR7s3HqObPncfbEMcmLdEE8Paj21meLTTC8nbbGXuvwu m1tLq3haX9JgIfmWly4Uz12CtNfH+BdX/58phH//gL+DC6QGJzOlSq2V2f8v1g9EtjHd oLwhs7RDwaeDFuUyKsPGBGK/O57iED/IacHm9jszljrSD0JFun9oZvwRqi3fLkHwwXrv 02BAPMaqhQEE9iuMX74dhHqci+XlqtGvFzaLgGRMCJ0oxI8BcTOnUARSaRc12Go4SaV8 mhTwYQHFO3oSERaAnb4s/u5/nzqy/k3X6uzTcjbcQOjMqTNgzBKQt+VNvKQpM9kzWcWr QEqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=v4O8So/flSbWMAld2f6/XrXeOJdFqXo/wD/5BCK4Ra4=; b=cT5RdzBCrN1SITmVgdmNl0pd92rsFTWrPqwAiaerP3M1VPLV71ZMcv43r8VY5jmPW7 fv0J9MGGy0D3V8pXxc6BTBxdudObmSGwznlSqLskuCk7753qupEZxhcdR3aJzYyy/oXz bqKIzLmZikz8aO+kN/sd1bHx8WKGI9rlLQC9vH4eRwYGhdC1NN4+MFK4H+6vtGbqkaZC r3777s913RYd16QeYM7OISDHJ+ZvJpHOR/Be71AfPAWjnbvW4G7PD0oXeGNNLim0J31m IUROTouCCwewvo9a0T8+PqHSgB897LUd+SMXxdEogk1t1aK7C0lENKmo9CL+R2DgyCS3 Fa5w== X-Gm-Message-State: ACgBeo2OuC909XHJcgPdXUcB3cgq5L91OE1k5rEBzO3NOKC4Vmh2CZ6q E9VYIiKFFl37a6ldjea27PSyE6Mkwbk= X-Google-Smtp-Source: AA6agR5ZUr28h+jODCkdGdXh1OHI0iJDEM/uj//EMtMXDy/kP+yWFrTp+iRaoXI2OvZAilD0blPDvQ== X-Received: by 2002:a05:6000:1f0e:b0:221:6dd6:a2a3 with SMTP id bv14-20020a0560001f0e00b002216dd6a2a3mr13138172wrb.574.1660071330309; Tue, 09 Aug 2022 11:55:30 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:30 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 07/14] merge-one-file: rewrite in C Date: Tue, 9 Aug 2022 20:54:22 +0200 Message-Id: <20220809185429.20098-8-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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_to_index_cacheinfo(); - calls to `update-index --remove' are replaced by calls to remove_file_from_index(); - calls to `checkout-index -u -f' are replaced by calls to checkout_entry(); - calls to `unpack-file' and `merge-files' are replaced by calls to read_mmblob() and xdl_merge(), respectively, to merge files in-memory; - calls to `checkout-index -f --stage=2' are removed, as this is needed to have the correct permission bits on the merged file from the script, but not in the C version; - calls to `update-index' are replaced by calls to add_file_to_index(). 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. This also teaches `merge-index' to call merge_three_way() (when invoked with `--use=merge-one-file') without forking using a new callback, merge_one_file_func(). To avoid any issue with a shrinking index because of the merge function used (directly in the process or by forking), as described earlier, the iterator of the loop of merge_all_index() is increased by the number of entries with the same name, minus the difference between the number of entries in the index before and after the merge. This should handle a shrinking index correctly, but could lead to issues with a growing index. However, this case is not treated, as there is no callback that can produce such a case. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-index.c | 4 +- builtin/merge-one-file.c | 92 ++++++++++++++ git-merge-one-file.sh | 167 ------------------------- git.c | 1 + merge-strategies.c | 208 +++++++++++++++++++++++++++++++- merge-strategies.h | 13 ++ t/t6060-merge-index.sh | 2 +- t/t6415-merge-dir-to-symlink.sh | 2 +- 10 files changed, 317 insertions(+), 175 deletions(-) create mode 100644 builtin/merge-one-file.c delete mode 100755 git-merge-one-file.sh diff --git a/Makefile b/Makefile index 40d1be4e5e..e2e6cbbb41 100644 --- a/Makefile +++ b/Makefile @@ -631,7 +631,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 @@ -1186,6 +1185,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 40e9ecc848..cdbe91bbe8 100644 --- a/builtin.h +++ b/builtin.h @@ -182,6 +182,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-index.c b/builtin/merge-index.c index aba3ba5694..a242b357f8 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -72,9 +72,11 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) if (skip_prefix(pgm, "--use=", &use_internal)) { if (!strcmp(use_internal, "merge-one-file")) - pgm = "git-merge-one-file"; + merge_action = merge_one_file_func; else die(_("git merge-index: unknown internal program %s"), use_internal); + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); } for (; i < argc; i++) { diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c new file mode 100644 index 0000000000..ec718cc1c9 --- /dev/null +++ b/builtin/merge-one-file.c @@ -0,0 +1,92 @@ +/* + * 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 object name (or empty) + * argv[2] - file in branch1 object name (or empty) + * argv[3] - file in branch2 object name (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."; + +static int read_param(const char *name, const char *arg_blob, const char *arg_mode, + struct object_id *blob, struct object_id **p_blob, unsigned int *mode) +{ + if (*arg_blob && !get_oid_hex(arg_blob, blob)) { + char *last; + + *p_blob = blob; + *mode = strtol(arg_mode, &last, 8); + + if (*last) + return error(_("invalid '%s' mode: expected nothing, got '%c'"), name, *last); + else if (!(S_ISREG(*mode) || S_ISDIR(*mode) || S_ISLNK(*mode))) + return error(_("invalid '%s' mode: %o"), name, *mode); + } else if (!*arg_blob && *arg_mode) + return error(_("no '%s' object id given, but a mode was still given."), name); + + return 0; +} + +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; + struct repository *r = the_repository; + + if (argc != 8) + usage(builtin_merge_one_file_usage); + + if (repo_read_index(r) < 0) + die("invalid index"); + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + if (read_param("orig", argv[1], argv[5], &orig_blob, + &p_orig_blob, &orig_mode)) + ret = -1; + + if (read_param("our", argv[2], argv[6], &our_blob, + &p_our_blob, &our_mode)) + ret = -1; + + if (read_param("their", argv[3], argv[7], &their_blob, + &p_their_blob, &their_mode)) + ret = -1; + + if (ret) + return ret; + + ret = merge_three_way(r->index, 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(r->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 e5d62fa5a9..f5d3c6cb39 100644 --- a/git.c +++ b/git.c @@ -561,6 +561,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 index 418c9dd710..373b69c10b 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,5 +1,198 @@ #include "cache.h" +#include "dir.h" +#include "entry.h" #include "merge-strategies.h" +#include "xdiff-interface.h" + +static int add_merge_result_to_index(struct index_state *istate, unsigned int mode, + const struct object_id *oid, const char *path, + int checkout) +{ + struct cache_entry *ce; + int res; + + res = add_to_index_cacheinfo(istate, mode, oid, path, 0, 1, 1, &ce); + if (res == -1) + return error(_("Invalid path '%s'"), path); + else if (res == -2) + return -1; + + if (checkout) { + struct checkout state = CHECKOUT_INIT; + + state.istate = istate; + state.force = 1; + state.base_dir = ""; + state.base_dir_len = 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 *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 != their_mode) || + (!their_blob && orig_mode != our_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; + ssize_t written; + mmbuffer_t result = {NULL, 0}; + mmfile_t mmfs[3]; + xmparam_t xmp = {{0}}; + + 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); + + 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()); + } + + read_mmblob(mmfs + 1, our_blob); + read_mmblob(mmfs + 2, their_blob); + + xmp.level = XDL_MERGE_ZEALOUS_ALNUM; + xmp.style = 0; + xmp.favor = 0; + + ret = xdl_merge(mmfs + 0, mmfs + 1, mmfs + 2, &xmp, &result); + + for (i = 0; i < 3; i++) + free(mmfs[i].ptr); + + if (ret < 0) { + free(result.ptr); + return error(_("Failed to execute internal merge")); + } + + if (ret > 0 || !orig_blob) + ret = error(_("content conflict in %s"), path); + if (our_mode != their_mode) + ret = error(_("permission conflict: %o->%o,%o in %s"), + orig_mode, our_mode, their_mode, path); + + unlink(path); + if ((dest = open(path, O_WRONLY | O_CREAT, our_mode)) < 0) { + free(result.ptr); + return error_errno(_("failed to open file '%s'"), path); + } + + written = write_in_full(dest, result.ptr, result.size); + close(dest); + + free(result.ptr); + + if (written < 0) + return error_errno(_("failed to write to '%s'"), path); + if (ret) + return ret; + + return add_file_to_index(istate, path, 0); +} + +int merge_three_way(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 (orig_blob && + ((!our_blob && !their_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(istate, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + } else if (!orig_blob && our_blob && !their_blob) { + /* + * Added in ours. The other side did not add and we + * added so there is nothing to be done, except making + * the path merged. + */ + return add_merge_result_to_index(istate, our_mode, our_blob, path, 0); + } 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); + + return add_merge_result_to_index(istate, their_mode, their_blob, path, 1); + } 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); + + return add_merge_result_to_index(istate, our_mode, our_blob, path, 1); + } else if (our_blob && their_blob) { + /* Modified in both, but differently. */ + return do_merge_one_file(istate, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + } else { + char orig_hex[GIT_MAX_HEXSZ] = {0}, our_hex[GIT_MAX_HEXSZ] = {0}, + their_hex[GIT_MAX_HEXSZ] = {0}; + + if (orig_blob) + oid_to_hex_r(orig_hex, orig_blob); + if (our_blob) + oid_to_hex_r(our_hex, our_blob); + if (their_blob) + oid_to_hex_r(their_hex, their_blob); + + return error(_("%s: Not handling case %s -> %s -> %s"), + path, orig_hex, our_hex, their_hex); + } + + return 0; +} + +int merge_one_file_func(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, + void *data) +{ + return merge_three_way(istate, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); +} static int merge_entry(struct index_state *istate, unsigned int pos, const char *path, int *err, merge_fn fn, void *data) @@ -54,7 +247,7 @@ int merge_all_index(struct index_state *istate, int oneshot, int quiet, merge_fn fn, void *data) { int err = 0, ret; - unsigned int i; + unsigned int i, prev_nr; /* TODO: audit for interaction with sparse-index. */ ensure_full_index(istate); @@ -63,10 +256,17 @@ int merge_all_index(struct index_state *istate, int oneshot, int quiet, if (!ce_stage(ce)) continue; + prev_nr = istate->cache_nr; ret = merge_entry(istate, i, ce->name, &err, fn, data); - if (ret > 0) - i += ret - 1; - else if (ret == -1) + if (ret > 0) { + /* + * Don't bother handling an index that has + * grown, since merge_one_file_func() can't grow + * it, and merge_one_file_spawn() can't change + * it. + */ + i += ret - (prev_nr - istate->cache_nr) - 1; + } else if (ret == -1) return -1; if (err && !oneshot) { diff --git a/merge-strategies.h b/merge-strategies.h index 88f476f170..8705a550ca 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -3,6 +3,12 @@ #include "object.h" +int merge_three_way(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); + typedef int (*merge_fn)(struct index_state *istate, const struct object_id *orig_blob, const struct object_id *our_blob, @@ -10,6 +16,13 @@ typedef int (*merge_fn)(struct index_state *istate, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, void *data); +int merge_one_file_func(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, + void *data); + int merge_index_path(struct index_state *istate, int oneshot, int quiet, const char *path, merge_fn fn, void *data); int merge_all_index(struct index_state *istate, int oneshot, int quiet, diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index 3845a9d3cc..9976996c80 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -70,7 +70,7 @@ test_expect_success 'merge-one-file fails without a work tree' ' (cd bare.git && GIT_INDEX_FILE=$PWD/merge.index && export GIT_INDEX_FILE && - test_must_fail git merge-index git-merge-one-file -a + test_must_fail git merge-index --use=merge-one-file -a ) ' diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2655e295f5..10bc5eb8c4 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -99,7 +99,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 Aug 9 18:54:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939885 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 DF7E5C19F2D for ; Tue, 9 Aug 2022 19:09:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345834AbiHITJu (ORCPT ); Tue, 9 Aug 2022 15:09:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345722AbiHITJI (ORCPT ); Tue, 9 Aug 2022 15:09:08 -0400 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4C8B2251E for ; Tue, 9 Aug 2022 11:55:32 -0700 (PDT) Received: by mail-wr1-x42e.google.com with SMTP id j1so15343868wrw.1 for ; Tue, 09 Aug 2022 11:55:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=fAVmtMNvs0oHXnGRsrKnKiTOAYJxorsy23H2Q85JteI=; b=ol/55fpX7QWaO0vOAvWle6znzF9bxcMwde2NskzdGJqM12rzTvGVhYB4fL4oV+8Due 1eAArHunrs4tvGSbn4nU5zoxF7FE0XvZYHYUI2uOEhiLQnYtFdWAjF81C9n4/B3SZWxp umMWcD8YA2qwW55UHOnl9CNf57DGfqGieB0vw3lAp+jpJ7w6wqQ18nHd0yJ8mGGH06eC z5QWT6W99K3Rf32gb3TNMG2wWrATltvwOf5Up6WxzColSd3mIzmhBnpgic5THJWw/iZY AJnwaoClBCEMSlVY8G7cPVaDZP4euz+bms1vdgJiud03Ib2VDdGRY7nhDfbBq43WT0Ae T0yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=fAVmtMNvs0oHXnGRsrKnKiTOAYJxorsy23H2Q85JteI=; b=F7ly9dPAnrx5SswAp7Gc/gfGASo8+nbhPx14vUNo7SnVRnfRt0qWjigd/5S4MA59nH kNFPASBBdFkRDGfkJgBKt7K9kwqJw8UcjYfQM8brWF/3oLaaXOH2jAG24l4TExZrIEmd j2bE2srJWZWSDfOCg/Ur8Bwz2rkpOVpo9y5T2EuPjbaAeuls748uzya4kZXN7l3nTRR0 T9pCwdaOwrcfA2IRnDCA5sPnSrILqSzqtoGUVIkNk/MdBQWpnuRzBsvYInHSDTnuj8t3 JlqBfYmlageeyAMXKD+yipmc6E4X348R7nNKrUcUoU8CasTN5KPs/AH0hI/Hykn61KlR GYzQ== X-Gm-Message-State: ACgBeo1/BTkilY4hTrQhicSyO6lglYiCHv6N7YC2WvmMwW+R0a6JjbWa 1rC1aQ0927ZM6y05eyq9WT7x/q9DOLw= X-Google-Smtp-Source: AA6agR7ihduE4jUhqd0PeBOM8+PTj4j4Tql/sOgAE/e5TT1k3C7IZ3FvulLgyykOn1oRdbeHyCIp/A== X-Received: by 2002:a05:6000:1446:b0:222:c466:58a0 with SMTP id v6-20020a056000144600b00222c46658a0mr9095914wrx.53.1660071331143; Tue, 09 Aug 2022 11:55:31 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:30 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 08/14] merge-resolve: rewrite in C Date: Tue, 9 Aug 2022 20:54:23 +0200 Message-Id: <20220809185429.20098-9-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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 cache_tree_update(). This call is wrapped in a new function, write_tree(). It is made to mimick write_index_as_tree() with WRITE_TREE_SILENT flag, but without locking the index; this is taken care directly in merge_strategies_resolve(). - The call to `diff-index ...' is replaced by a call to repo_index_has_changes(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to the new merge_all_index() function. The index is read in cmd_merge_resolve(), and is wrote back by merge_strategies_resolve(). This is to accomodate future applications: in `git-merge', the index has already been read when the merge strategy is called, so it would be redundant to read it again when the builtin will be able to use merge_strategies_resolve() directly. 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. merge_strategies_resolve() locks the index only once, at the beginning of the merge, and releases it when the merge has been completed. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-resolve.c | 63 ++++++++++++++++++ git-merge-resolve.sh | 64 ------------------- git.c | 1 + merge-strategies.c | 137 ++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 5 ++ 7 files changed, 208 insertions(+), 65 deletions(-) create mode 100644 builtin/merge-resolve.c delete mode 100755 git-merge-resolve.sh diff --git a/Makefile b/Makefile index e2e6cbbb41..0c18acb979 100644 --- a/Makefile +++ b/Makefile @@ -631,7 +631,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 @@ -1188,6 +1187,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 cdbe91bbe8..4627229944 100644 --- a/builtin.h +++ b/builtin.h @@ -184,6 +184,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..a51158ebf8 --- /dev/null +++ b/builtin/merge-resolve.c @@ -0,0 +1,63 @@ +/* + * 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, sep_seen = 0; + const char *head = NULL; + struct commit_list *bases = NULL, *remote = NULL; + struct commit_list **next_base = &bases; + struct repository *r = the_repository; + + if (argc < 5) + usage(builtin_merge_resolve_usage); + + setup_work_tree(); + if (repo_read_index(r) < 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], "--")) + sep_seen = 1; + else if (!strcmp(argv[i], "-h")) + usage(builtin_merge_resolve_usage); + else if (sep_seen && !head) + head = argv[i]; + else { + struct object_id oid; + struct commit *commit; + + if (get_oid(argv[i], &oid)) + die("object %s not found.", argv[i]); + + commit = oideq(&oid, r->hash_algo->empty_tree) ? + NULL : lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + commit_list_insert(commit, &remote); + else + next_base = commit_list_append(commit, next_base); + } + } + + return merge_strategies_resolve(r, bases, head, remote); +} diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh deleted file mode 100755 index e59175eb75..0000000000 --- a/git-merge-resolve.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two trees, using enhanced multi-base read-tree. - -. git-sh-setup - -# Abort if index does not match HEAD -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 - -# 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 --use=merge-one-file -a - then - exit 0 - else - exit 1 - fi -fi diff --git a/git.c b/git.c index f5d3c6cb39..09d222da88 100644 --- a/git.c +++ b/git.c @@ -565,6 +565,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 }, { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c index 373b69c10b..30f225ae5f 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,9 +1,34 @@ #include "cache.h" +#include "cache-tree.h" #include "dir.h" #include "entry.h" +#include "lockfile.h" #include "merge-strategies.h" +#include "unpack-trees.h" #include "xdiff-interface.h" +static int check_index_is_head(struct repository *r, const char *head_arg) +{ + struct commit *head_commit; + struct tree *head_tree; + struct object_id head; + struct strbuf sb = STRBUF_INIT; + + get_oid(head_arg, &head); + head_commit = lookup_commit_reference(r, &head); + head_tree = repo_get_commit_tree(r, head_commit); + + if (repo_index_has_changes(r, head_tree, &sb)) { + error(_("Your local changes to the following files " + "would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + return 1; + } + + return 0; +} + static int add_merge_result_to_index(struct index_state *istate, unsigned int mode, const struct object_id *oid, const char *path, int checkout) @@ -280,3 +305,115 @@ int merge_all_index(struct index_state *istate, int oneshot, int quiet, error(_("merge program failed")); return err; } + +static int merge_trees(struct repository *r, struct tree_desc *t, + int nr, int aggressive) +{ + struct unpack_trees_options opts; + + refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL); + + 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; + + 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; + return 0; +} + +static int add_tree(struct tree *tree, struct tree_desc *t) +{ + if (parse_tree(tree)) + return -1; + + init_tree_desc(t, tree->buffer, tree->size); + return 0; +} + +static int write_tree(struct repository *r) +{ + int was_valid; + was_valid = r->index->cache_tree && + cache_tree_fully_valid(r->index->cache_tree); + + if (!was_valid && cache_tree_update(r->index, WRITE_TREE_SILENT) < 0) + return WRITE_TREE_UNMERGED_INDEX; + return 0; +} + +int merge_strategies_resolve(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remote) +{ + struct tree_desc t[MAX_UNPACK_TREES]; + struct commit_list *i; + struct lock_file lock = LOCK_INIT; + int nr = 0, ret = 0; + + /* Abort if index does not match head */ + if (check_index_is_head(r, head_arg)) + return 2; + + /* + * Give up if we are given two or more remotes. Not handling + * octopus. + */ + if (remote && remote->next) + return 2; + + /* Give up if this is a baseless merge. */ + if (!bases) + return 2; + + puts(_("Trying simple merge.")); + + for (i = bases; i && i->item; i = i->next) { + if (add_tree(repo_get_commit_tree(r, i->item), t + (nr++))) + return 2; + } + + if (head_arg) { + struct object_id head; + struct tree *tree; + + get_oid(head_arg, &head); + tree = parse_tree_indirect(&head); + + if (add_tree(tree, t + (nr++))) + return 2; + } + + if (remote && add_tree(repo_get_commit_tree(r, remote->item), t + (nr++))) + return 2; + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + if (merge_trees(r, t, nr, 1)) { + rollback_lock_file(&lock); + return 2; + } + + if (write_tree(r)) { + puts(_("Simple merge failed, trying Automatic merge.")); + ret = merge_all_index(r->index, 1, 0, merge_one_file_func, NULL); + } + + if (write_locked_index(r->index, &lock, COMMIT_LOCK)) + return !!error(_("unable to write new index file")); + return !!ret; +} diff --git a/merge-strategies.h b/merge-strategies.h index 8705a550ca..bba4bf999c 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_three_way(struct index_state *istate, @@ -28,4 +29,8 @@ int merge_index_path(struct index_state *istate, int oneshot, int quiet, int merge_all_index(struct index_state *istate, int oneshot, int quiet, merge_fn fn, 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 Aug 9 18:54:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939886 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 31034C25B08 for ; Tue, 9 Aug 2022 19:09:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345842AbiHITJw (ORCPT ); Tue, 9 Aug 2022 15:09:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345135AbiHITJJ (ORCPT ); Tue, 9 Aug 2022 15:09:09 -0400 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7DAF422BE7 for ; Tue, 9 Aug 2022 11:55:33 -0700 (PDT) Received: by mail-wm1-x335.google.com with SMTP id v5so6750732wmj.0 for ; Tue, 09 Aug 2022 11:55:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=IUnBkjTsXPS0baa0O+Pu0f+n9e3ezUW+R7pCw2cLpYQ=; b=lC2TjbA3rYnGONnHRWrqMWo70xf2E5qvWIzJrq1g4I2uPwK5SyWm0etbcuNDO1YEak i6ChmkcqFlPxHv/gyZJVXFyt0rQxKguQKHlPRDPEhgbpL5tqDyc/vPDdAkQ1TF0XbZ0b QPr4wbFri9b3IAY59qcAbDE1yL5edUUQvDGZbAw+K5uX/RSUa1kn5eI4kzkEWj43tH6t bG1r2p/yJcMs2OX+WMkFkRXUrhCkLsH1NQOecfSURil1gwIyq9pTg+MLQd9Fs6aAD+RF LugpeMjQMPP+7RfT9dZ0Ok8B5laLyara9q5wNkTXCdIVkUqhaCa9hrXJ05AydjPdBcxn rz1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=IUnBkjTsXPS0baa0O+Pu0f+n9e3ezUW+R7pCw2cLpYQ=; b=jEYTEztKG+I4PwsaBsGpUXEpwbeoJrapS9/iw5ACd9nMuvctJCixHSXnUP1fMxwySK fpU99Y9SmeNou7U4kWyussofu8j7talOSBIVBw980ORIBfGo41HAOqCcIiCQgu0VBz+2 3J3gLsh+unTkGbulgCTFlftDP5pBbBAEarQfCOSQbjRzxDgqFv5CSME5ZFbLw0vYySYO gHNOC30yUS9/+KDiBICvzDd8APtudP/77XLEIuXxDOnr4y8Qsqrsr/sSpWFk4YEUf+c/ tT/T76n+ryuza59MH9QaFNiQdaigDj+CB31wlCTKIXTAM/gUsjzpBmqWjSWNsWRLghCD ekYw== X-Gm-Message-State: ACgBeo1x/06IsZxAGiDhTSnyNrgX+NdcXxT8vGRX6vhPlD6MQ8Ih4Tnc 3ajE1iMMQjJ1NWL0fyViNNr+d4V3qWM= X-Google-Smtp-Source: AA6agR5ya3BTXMLRTejfvbXUoulO2anrfLRbMcc6MM2cuXULJZlPjZXmwHXUIzuLbKIt16ufyvWhSQ== X-Received: by 2002:a05:600c:1ca9:b0:3a5:125:3738 with SMTP id k41-20020a05600c1ca900b003a501253738mr20697759wms.161.1660071332065; Tue, 09 Aug 2022 11:55:32 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:31 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 09/14] merge-recursive: move better_branch_name() to merge.c Date: Tue, 9 Aug 2022 20:54:24 +0200 Message-Id: <20220809185429.20098-10-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org better_branch_name() will be used by merge-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 b9acbf5d34..ae429c8514 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 6b5d0a2ba3..61ac42fa43 100644 --- a/cache.h +++ b/cache.h @@ -1916,7 +1916,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 2382ff66d3..d87bfd4824 100644 --- a/merge.c +++ b/merge.c @@ -102,3 +102,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 Aug 9 18:54:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939889 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 6E45BC25B08 for ; Tue, 9 Aug 2022 19:09:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345850AbiHITJ4 (ORCPT ); Tue, 9 Aug 2022 15:09:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345177AbiHITJL (ORCPT ); Tue, 9 Aug 2022 15:09:11 -0400 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8FD7B2317E for ; Tue, 9 Aug 2022 11:55:34 -0700 (PDT) Received: by mail-wm1-x336.google.com with SMTP id ay12so3908668wmb.1 for ; Tue, 09 Aug 2022 11:55:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=ksl2l8rhSZcCM4WzucrlS6OrefO74SDt8fRGsk1CB5g=; b=H7xA6y3+HZIWnUevlAatg3uMvfuAAjwXgfSPLOqGTcgtRuS8DaLkk9MeiSc6+DaHJB aMG7rGf3mkh7x0/wzcqS9CZpht1+/mViE2yPDS6l7uZXOXiR4J4f7NDn8xWO9ZP7q5RN KWZuHfTL9xtTHycaTiUgCWIuabEHwL07FHIciD0V9cA2pr4HSvsPRQZ6T5MoqEgWgQIW NxB5DGwxGNYfe59Dj2kDyyPFuMlrhCtX1oDtsSgKPXNDpwzDRme18wpwebbKAM8k4qvs M11eyTYFy1f9LNafWsIbDR57aywbHkRL5R5eULxcKz1AL3NNiTuW+f1WjK+tfbIIvOI8 zOgQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=ksl2l8rhSZcCM4WzucrlS6OrefO74SDt8fRGsk1CB5g=; b=b1U19+12yO71GTurozWVzk1X/Xn1m5UxaIwWAjl1dPB/aNufmZV/7RC9VxdHuBBsPu ZbnQpujw//baM5A0cxQ4hDH7AfQttrUn3XDISN0FJ3qR9geRkT0AUGzws/kiGoyQpk5D pLPNY7EG0fY745t7uk0bOKzlHLCNYPKEy9Dht8a//QpxcTw3cW8vFDJALLHxthAl5Urt cBM2lxS1gBkyDWkPfZ6bCLClgQtXfvol64/UZqgBWWhlBCpSrX46Pbh8A5QVcJpZFUGV shw9HyoqLQ+PhtPgcDHVHDw7i/g4B6oc+FlGO9fiOCoQl/51n7UZvP8dEJa5PPmcsNUz czfw== X-Gm-Message-State: ACgBeo1QaHPXne/HoIC4UnZ5K6F3AE5a/MWmId3Vb/XKR/Kmhnv18PVm cWFd+Ejzu0f247xlK5j4gfridjdBcnY= X-Google-Smtp-Source: AA6agR7pPga0+WXGmiG1ZHiVAwpkAKVlhvTGBbT9LQl0TqlhnvHjyNzgbt81GVXI6qdmIqesBm0spQ== X-Received: by 2002:a1c:7209:0:b0:3a3:1f31:ef3a with SMTP id n9-20020a1c7209000000b003a31f31ef3amr21278358wmc.87.1660071333060; Tue, 09 Aug 2022 11:55:33 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:32 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 10/14] merge-octopus: rewrite in C Date: Tue, 9 Aug 2022 20:54:25 +0200 Message-Id: <20220809185429.20098-11-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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_tree(). - The call to `diff-index ...' is replaced by a call to repo_index_has_changes(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to merge_all_index(). The index is read in cmd_merge_octopus(), and is written back by merge_strategies_octopus(), for the same reason as merge-resolve. Here too, merge_strategies_octopus() takes two commit lists and a string to reduce friction when try_merge_strategies() will be modified to call it directly. It also locks the index at the start of the merge, and releases it at the end. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-octopus.c | 63 +++++++++++++++ git-merge-octopus.sh | 112 -------------------------- git.c | 1 + merge-strategies.c | 171 ++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 3 + 7 files changed, 240 insertions(+), 113 deletions(-) create mode 100644 builtin/merge-octopus.c delete mode 100755 git-merge-octopus.sh diff --git a/Makefile b/Makefile index 0c18acb979..9fe1e72f6e 100644 --- a/Makefile +++ b/Makefile @@ -630,7 +630,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 @@ -1184,6 +1183,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 4627229944..9305dda166 100644 --- a/builtin.h +++ b/builtin.h @@ -180,6 +180,7 @@ int cmd_maintenance(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..ff3089bfca --- /dev/null +++ b/builtin/merge-octopus.c @@ -0,0 +1,63 @@ +/* + * 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; + struct repository *r = the_repository; + + if (argc < 5) + usage(builtin_merge_octopus_usage); + + setup_work_tree(); + if (repo_read_index(r) < 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_octopus_usage); + else if (sep_seen && !head_arg) + head_arg = argv[i]; + else { + struct object_id oid; + struct commit *commit; + + if (get_oid(argv[i], &oid)) + die("object %s not found.", argv[i]); + + commit = oideq(&oid, r->hash_algo->empty_tree) ? + NULL : 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); + } + } + + return merge_strategies_octopus(r, bases, head_arg, remotes); +} diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh deleted file mode 100755 index 2770891960..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 --use=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 09d222da88..7a5e506c64 100644 --- a/git.c +++ b/git.c @@ -560,6 +560,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 30f225ae5f..3e8255614b 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 "entry.h" #include "lockfile.h" @@ -417,3 +418,173 @@ int merge_strategies_resolve(struct repository *r, return !!error(_("unable to write new index file")); return !!ret; } + +static int octopus_fast_forward(struct repository *r, const char *branch_name, + struct tree *tree_head, struct tree *current_tree) +{ + /* + * 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 tree_desc t[2]; + + printf(_("Fast-forwarding to: %s\n"), branch_name); + + init_tree_desc(t, tree_head->buffer, tree_head->size); + if (add_tree(current_tree, t + 1)) + return -1; + if (merge_trees(r, t, 2, 0)) + return -1; + if (write_tree(r)) + return -1; + + return 0; +} + +static int octopus_do_merge(struct repository *r, const char *branch_name, + struct commit_list *common, struct tree *current_tree, + struct tree *reference_tree) +{ + struct tree_desc t[MAX_UNPACK_TREES]; + struct commit_list *i; + int nr = 0, ret = 0; + + printf(_("Trying simple merge with %s\n"), branch_name); + + for (i = common; i; i = i->next) { + struct tree *tree = repo_get_commit_tree(r, i->item); + if (add_tree(tree, t + (nr++))) + return -1; + } + + if (add_tree(reference_tree, t + (nr++))) + return -1; + if (add_tree(current_tree, t + (nr++))) + return -1; + if (merge_trees(r, t, nr, 1)) + return 2; + + if (write_tree(r)) { + puts(_("Simple merge did not work, trying automatic merge.")); + ret = !!merge_all_index(r->index, 1, 0, merge_one_file_func, NULL); + write_tree(r); + } + + return ret; +} + +int merge_strategies_octopus(struct repository *r, + struct commit_list *bases, const char *head_arg, + struct commit_list *remotes) +{ + int ff_merge = 1, ret = 0, nr_references = 1; + struct commit **reference_commits, *head_commit; + struct tree *reference_tree, *head_tree; + struct commit_list *i; + struct object_id head; + struct lock_file lock = LOCK_INIT; + + /* + * Reject if this is not an octopus -- resolve should be used + * instead. + */ + if (commit_list_count(remotes) < 2) + return 2; + + /* Abort if index does not match head */ + if (check_index_is_head(r, head_arg)) + return 2; + + get_oid(head_arg, &head); + head_commit = lookup_commit_reference(r, &head); + head_tree = repo_get_commit_tree(r, head_commit); + + CALLOC_ARRAY(reference_commits, commit_list_count(remotes) + 1); + reference_commits[0] = head_commit; + reference_tree = head_tree; + + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + for (i = remotes; i && i->item; i = i->next) { + struct commit *c = i->item; + struct object_id *oid = &c->object.oid; + struct tree *current_tree = repo_get_commit_tree(r, c); + struct commit_list *common, *j; + char *branch_name = merge_get_better_branch_name(oid_to_hex(oid)); + int up_to_date = 0; + + common = repo_get_merge_bases_many(r, c, nr_references, reference_commits); + if (!common) { + error(_("Unable to find common commit with %s"), branch_name); + + free(branch_name); + free_commit_list(common); + + ret = 2; + break; + } + + /* + * If `oid' is reachable from `HEAD', we're already up + * to date. + */ + for (j = common; j; j = j->next) { + if (oideq(&j->item->object.oid, oid)) { + up_to_date = 1; + break; + } + } + + if (up_to_date) { + printf(_("Already up to date with %s\n"), branch_name); + + free(branch_name); + free_commit_list(common); + continue; + } + + /* + * If we could fast-forward so far and `HEAD' is the + * single merge base with the current `remote' revision, + * keep fast-forwarding. + */ + if (ff_merge && common && !common->next && nr_references == 1 && + oideq(&common->item->object.oid, + &reference_commits[0]->object.oid)) { + ret = octopus_fast_forward(r, branch_name, head_tree, current_tree); + nr_references = 0; + } else { + ret = octopus_do_merge(r, branch_name, common, + current_tree, reference_tree); + ff_merge = 0; + } + + free(branch_name); + free_commit_list(common); + + if (ret == -1 || ret == 2) + break; + else if (ret && i->next) { + /* + * 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; + break; + } + + reference_commits[nr_references++] = c; + reference_tree = lookup_tree(r, &r->index->cache_tree->oid); + } + + free(reference_commits); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + return ret; +} diff --git a/merge-strategies.h b/merge-strategies.h index bba4bf999c..8de2249ee6 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -32,5 +32,8 @@ int merge_all_index(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 Aug 9 18:54:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939887 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 578CDC19F2D for ; Tue, 9 Aug 2022 19:09:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345323AbiHITJx (ORCPT ); Tue, 9 Aug 2022 15:09:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43234 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345226AbiHITJJ (ORCPT ); Tue, 9 Aug 2022 15:09:09 -0400 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 323EE220FE for ; Tue, 9 Aug 2022 11:55:34 -0700 (PDT) Received: by mail-wr1-x42f.google.com with SMTP id l4so15268994wrm.13 for ; Tue, 09 Aug 2022 11:55:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=FV1BT2+eT/x2XQS8lK21txyXDhDJgU1I8PQ/6zob1zM=; b=qUVpsJ2FFXTRhnMGHlboZ7CN6Lp/f+v8qWCa96YQP0F+/2/RyLeaXc2Hpwp1DsXV51 UbfSB1fMcSPsUSunmrUDyErbXrLnfi/iSFpD4za3Du8KCIICEkjUP+HNd9bsboLMyfAj 5LNEepotbyFzjST+MViieXxJdrWIRlN2CAaiWLcaUHZI8gOYi0Eio6YNmvW6r0zKtBwG Zfiv48ijC3Kny2KiI7HjKplUkyemSO7N7hm6ZRyFQL6QUWNg0KqqwhQpVlJgZvVRewcm VTKP2hfu1F2+A9xP0v8fkq+LN/+neaV68e9QPLK6XZZ4iJZSUUxDqO9vjxYhE9SRwAyP GTsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=FV1BT2+eT/x2XQS8lK21txyXDhDJgU1I8PQ/6zob1zM=; b=Q5lj71HTqoWEsbLyO57VAXzkX2dIys3IOs//UOw+fazHlUYmdHNKFx6+zQ9C3lZj3L 8BWYu3cusl3lIOT+jk50mDPc8oWl/GhpY+fFhDjv/wwNqt5a4eOcRH2QuBC2o2gsrqNm 87eEDq1NSPWHwmqdfU1dgbLKT2/DNrSdcYWi/FkQSzhji/46PaoBfEmvu4X2tlxU1h6W vFopfLaPyaQ8R9+vvt5Ck6/gAkoazCbV9KFNJtUqkjs9FTUz2WT6klgW4NK3TpU58FB3 4du4a0pOmJwwNajNksmZZhZw+j9wCsT6lY6VE1j4QbPdjrXNcP3QWXrF50KXVWUO1u7b wcLQ== X-Gm-Message-State: ACgBeo30HqLdELMTz+e0fjnlfRuONAEFPfhCCe4bywvOWXWYKPQEJL4b 0UeRk/8EZ4TIdNEyuVCWnIp2KIYgONg= X-Google-Smtp-Source: AA6agR4fHmAUnEn42SMMXtqaa+qqV6KD+yuW7/8SRRU9m7UeX4ApVJtryVkPjmlj76HoGj8kL3bbWA== X-Received: by 2002:adf:f286:0:b0:21e:f0dc:3df0 with SMTP id k6-20020adff286000000b0021ef0dc3df0mr15365419wro.377.1660071333830; Tue, 09 Aug 2022 11:55:33 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:33 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 11/14] merge: use the "resolve" strategy without forking Date: Tue, 9 Aug 2022 20:54:26 +0200 Message-Id: <20220809185429.20098-12-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/merge.c b/builtin/merge.c index f7c92c0e64..0ab2993ab2 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -44,6 +44,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) @@ -774,6 +775,9 @@ 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 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, From patchwork Tue Aug 9 18:54:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939890 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 87D7DC19F2D for ; Tue, 9 Aug 2022 19:10:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345897AbiHITKG (ORCPT ); Tue, 9 Aug 2022 15:10:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43790 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345329AbiHITJN (ORCPT ); Tue, 9 Aug 2022 15:09:13 -0400 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 0BD1826550 for ; Tue, 9 Aug 2022 11:55:36 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id az6-20020a05600c600600b003a530cebbe3so4317551wmb.0 for ; Tue, 09 Aug 2022 11:55:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=bSLfdThemNhLnl2UxpppknDa7YTekoJOJTrP7VayP+E=; b=ORNZHGRxa2Ke+KYaFpmPe5VA9PVkBFrUgqy09sbOUiAk6/eicPt30rSz+6kdHMWcrv F9CE1wkb3QfWJCfaK6OCjAQpERMVk3XxxKLfgzazGMoZqkBoAQp9Izjpmr6UL04P8ggr 5Et7FI35wIS1WptuLGYnoIvwh0rnDv4hG/MCPWlAruz73SNq51fPPZ1bx0hH4mcraRsD YAEF596bAteuf/pwHSfU+cZEkny2hWX7O9E+PXV4NbbiPBqtVAT6xC+lBFINY40wtGkW F7ezJccTxUL9Alji8FCp9cdkIFbwO+TLKzVzVgvZRup5lVkc0ZNglfPZdWb98uYo8LAY 58/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=bSLfdThemNhLnl2UxpppknDa7YTekoJOJTrP7VayP+E=; b=OpjB32SwD9b75/1175wo6sqEunZ3YVMR/4tcTjl9ove74nF+nAvm3fTCp2P96xATnN 06QT3YAlqis08a9N9fycLYrGabMUaEKmK7IGQRgmwZ0X88WxbdLk5G9TgdBXAA5eHJ3F 3v9ilEBjg2u1XTmttw1aawbGFxdCYxzrX6aoUE6Agv7HV2Uy8dUYhRc3Fgt9NIoI5/m6 DaD7XNlphE+bt86DKB7rRYVZkZzpBQhTl2olbw7vhL7Om2wU4j7e9vtU1rd7+4Ozu30N IEH6a/9go9xIDzzR9+AOsUG6D8xhTx8a76MYpfU9bRWv0q1CsGvSuD4NGRk2ExjRos1T 1SdA== X-Gm-Message-State: ACgBeo3ahUyD12dLRr9vDagP/d4BTl6qUCAIh9+0Q7U6p/YLp/chmZz+ 0atIv2yt+HSRb/WGfCunXLVGjPDto90= X-Google-Smtp-Source: AA6agR5z9NvGts7t5w5S5hXVoD6NcbdQjgj+bdywwuSYQS2SHWyAkTkvyQVZTqtYQ3R+ZbFvZ41t3A== X-Received: by 2002:a05:600c:1d8a:b0:3a3:1104:88ad with SMTP id p10-20020a05600c1d8a00b003a3110488admr16246358wms.179.1660071334547; Tue, 09 Aug 2022 11:55:34 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:34 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 12/14] merge: use the "octopus" strategy without forking Date: Tue, 9 Aug 2022 20:54:27 +0200 Message-Id: <20220809185429.20098-13-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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 0ab2993ab2..a44a6b810b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -778,6 +778,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 Aug 9 18:54:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939888 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 74311C25B06 for ; Tue, 9 Aug 2022 19:09:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345858AbiHITJ5 (ORCPT ); Tue, 9 Aug 2022 15:09:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43424 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345305AbiHITJM (ORCPT ); Tue, 9 Aug 2022 15:09:12 -0400 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA06D2528E for ; Tue, 9 Aug 2022 11:55:35 -0700 (PDT) Received: by mail-wm1-x335.google.com with SMTP id v5so6750782wmj.0 for ; Tue, 09 Aug 2022 11:55:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=gTVrfw6c+DAIGXClzrasR9FDs8MgAeUuIjvq4B7+jUM=; b=LkpaK6owA14Z3VxapQjMuDRcbkc+z1FJdgaslqpxlCvbsiMDMMq/FzCAyNk3nN36Ee cMU+JBXK0yrQVcMo9nEMdy1AxSaZFA1x2TqYsN4TSxGcfFaY9XcpYBvI8QuNdYI708/G ssdykP8D7mvwebiJuWHZ1yWLzomM7bNsjMchcEp3Mqfs0zMYIQM9/eu6MF19Ki3/WO0k SawfmW/KWFHCyvjpTf3EGmBq6zwGpiQlryUBUP1U9wx3KJSqzJS75GfhDXEMGTWyAWyc F/xuEdec2obI9dZ/lvLzUSfdt2Dwuk4lGpTMbS+weYDDH1a20sjfw+PJJLeNtZW2nW1a Gt+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=gTVrfw6c+DAIGXClzrasR9FDs8MgAeUuIjvq4B7+jUM=; b=6bcRQbRS+9e/8sDHPxai5OX0j7mDavo4I4TTjG++r49S/C2oawRJMJ6t+JHOBUuByy xfNDTqX7rSz0V2NKizQXVs1FoD4atgXlqTggLEiKdYQq+c68cBHZDAplQCX5YO/2BBJ1 Y/8tj2b8zHH1JU56bNv6cbELqNJvj6VA/JyyneFNLKnX0j1UiTjFTkrcj6UW/GtKhA/l /pN1UnvEgt+ODYEfANjEwDa1YXuSnyw66w1q+BzMuCQDyrrLitX1c2YVmggODbMp3BU2 fMdli6Ec6kVBeXYufoDm+2l5h+y1lKiPzmv1yciMEb6FS0tnefGkZ0xFD5f3KBTAJqjq +Ozg== X-Gm-Message-State: ACgBeo1na7HoWqr5qpH75vFMLH+avZD9S4xiYjVRqogst8AjYiJhsUsj NAsCC5OTKWKMEeMRjft4QR0tlCMJFFc= X-Google-Smtp-Source: AA6agR7sSMskizppOnWdZ+3ZOA4UqRB0Six+490TIYHhMuFuOlNomufAvrYM9HFhcSdsZYvvaIwMow== X-Received: by 2002:a05:600c:35c5:b0:3a5:664d:c556 with SMTP id r5-20020a05600c35c500b003a5664dc556mr2824446wmq.22.1660071335293; Tue, 09 Aug 2022 11:55:35 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:34 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 13/14] sequencer: use the "resolve" strategy without forking Date: Tue, 9 Aug 2022 20:54:28 +0200 Message-Id: <20220809185429.20098-14-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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 | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 5f22b7cd37..0e5e6cbb24 100644 --- a/sequencer.c +++ b/sequencer.c @@ -37,6 +37,7 @@ #include "reset.h" #include "branch.h" #include "log-tree.h" +#include "merge-strategies.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -2314,9 +2315,16 @@ 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 Aug 9 18:54:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 12939891 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 2854FC25B06 for ; Tue, 9 Aug 2022 19:10:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345411AbiHITKI (ORCPT ); Tue, 9 Aug 2022 15:10:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345340AbiHITJO (ORCPT ); Tue, 9 Aug 2022 15:09:14 -0400 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8C6D2C65E for ; Tue, 9 Aug 2022 11:55:37 -0700 (PDT) Received: by mail-wm1-x32b.google.com with SMTP id k6-20020a05600c1c8600b003a54ecc62f6so2461780wms.5 for ; Tue, 09 Aug 2022 11:55:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=zLEaoJFNZSQleFo9016QNQHr9BNunzTXAbdw7oqVu+o=; b=pnMi4mDjxH+JbIrYQZOWUOrCd8lCBgTOjWVkBAc6J9WA7wTSj0HUEv8iNCIx29aPaL VsB6yze6FPk+yrY1Ucnxwg7lAWpaM7gsaeBgm/HlHDANLjwLIJgL38d+T51vIajIEc2D hTUo6zBiUlhu9BKvVtoTOUE2TvuAEj2GP3+cC8EZueaoB4bR867eZdEvGvTEAGsx7tXc xDO4hJGGMlxo8gFmLyhNFphBNZcML+udkcMV3PLtUYNU8t2TuB3ncXehgzM4zsqNCd5e d5bHOPn3p9Vx3s5VVMOgXBZ/LH0MteKSXx2lGhmmUV3Vo13gAAXoLv3e7NrUgAc74rWr 1M1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=zLEaoJFNZSQleFo9016QNQHr9BNunzTXAbdw7oqVu+o=; b=dic5GmwaXhlQvFUzb7nXvyK9TFoNYY/G6qpwRaLcszQbsPsRN4TKg0TxcILO+6FcRX d2HzFvtRKA/EBxjHXxtw3+o0ljZc2uEVmVeF0qhSLxdCAC/IYbSDEeVBjicy81hYzlEl DCi7BLYVAypA0t0m9g5BVshwLnqfdUmixgZmsF/3SV890VPiYcOUSr+Zus2Eh9wHFXoX dyWzClnTRjI9SxJD1qJbST8n0PZJFvrd65FA/dtw4H7226n3t507CeC01o7tKbRUw9Sb HmlG39NQVOHIGpw0gLAByCJPMNIRu9ceCgnJPs/t5JEo84aXMHXijnCC4eK2hHZTOW3T 5Idg== X-Gm-Message-State: ACgBeo2WURxRGdiJQuPKoItBlsqdbnHhh5dm4OysS6243jCglUPl5FTg C6CbtG4KW/q3hRcKRGshgZIuTwmxNRM= X-Google-Smtp-Source: AA6agR4c4dxZTzr+svWwnGngp5M8env20h7XZKvnYbOFDS9S3WzPKFcUTaRHPKjAn8N8Oy7+9k3c5A== X-Received: by 2002:a7b:c5c8:0:b0:3a5:415d:20d3 with SMTP id n8-20020a7bc5c8000000b003a5415d20d3mr6641525wmk.97.1660071336298; Tue, 09 Aug 2022 11:55:36 -0700 (PDT) Received: from ylate.lan (89-81-181-244.abo.bbox.fr. [89.81.181.244]) by smtp.googlemail.com with ESMTPSA id j9-20020a05600c1c0900b003a529b7bc27sm13237414wms.9.2022.08.09.11.55.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 11:55:35 -0700 (PDT) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Johannes Schindelin , Alban Gruin Subject: [PATCH v8 14/14] sequencer: use the "octopus" strategy without forking Date: Tue, 9 Aug 2022 20:54:29 +0200 Message-Id: <20220809185429.20098-15-alban.gruin@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220809185429.20098-1-alban.gruin@gmail.com> References: <20210317204939.17890-1-alban.gruin@gmail.com> <20220809185429.20098-1-alban.gruin@gmail.com> MIME-Version: 1.0 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 0e5e6cbb24..00a3620584 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2319,6 +2319,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,