From patchwork Mon Nov 16 10:21:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908107 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0AEEC4742C for ; Mon, 16 Nov 2020 11:30:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 52D1920867 for ; Mon, 16 Nov 2020 11:30:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="H1SBPJiU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728921AbgKPKXK (ORCPT ); Mon, 16 Nov 2020 05:23:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728566AbgKPKXJ (ORCPT ); Mon, 16 Nov 2020 05:23:09 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37580C0613D1 for ; Mon, 16 Nov 2020 02:23:09 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id p1so18028897wrf.12 for ; Mon, 16 Nov 2020 02:23:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7NKR8/TOOCNoRIdKvR8AV7cjS9Gl1SgDrV3MY2xgjQI=; b=H1SBPJiUTde3ZYbFmig80B4Li86asJChdckzteJFpXQM4dNExs2+TxL3jn+K0gFJhi I68P4P/CvRZ5QU6uK9N5UgJ3WODiRLjMyJagIFIgMIFtb5KyBsySFnUlRseYHiWKPxvW GAjVVxrkUMo/ahb74H/hsaXfUVnzeB7EL4s6Doy7s2Mv5MIPVLggD0ESlNQ6xAKIEzhX URd3kL1pCMk78tQ3MDI8C6VxbINumEGoNBO+FiW9I6WpftPMrLxA8/zNgI1jRBG/oU4T hRCNar+/h2i6RpSnqZA0H/6rf13CSnu1Nv+xcNxL0taEpp2qXlCI70Zw+n7cxDkVK1Su M/ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7NKR8/TOOCNoRIdKvR8AV7cjS9Gl1SgDrV3MY2xgjQI=; b=LLN1iEZVfwMkUkk7ybiGXeyZe39cYvM/QxPtIsHxNgRMzgsepsABF9mfvkzg8AL3re 09sWHAv9pi+/7kb4RFF+A6jMNIh5d+Y6HkaFXXj9XiI9ql1iB3AtwUlkNZlXF3QrY9Wp SydL9kWpuethXUxbluh/jPKWVeV1Grn9ht8E1vktcyp4vrUoNW+wqChdORC/zZZB8Ig2 FLqTFZEqxoehTEnobWsl3g1x8DshpmosMb1jL4la7hUDkyiN7xsR1HfyLO1VnNvO1m0y +vLnMnK3ofXJe8j5vUF5DflMTuQrAakl2D2+jmbzPQNqpvvnmW8Ilyx7V86wQilSX/Of XgFw== X-Gm-Message-State: AOAM533bMhC5oxpPdssbaPFyzQkQ4Tm+6d+0bcCHuFlo7fBSjphIkYlf z2vSIY6aRIgYa0NE7NL1EOUHSF8uG/0= X-Google-Smtp-Source: ABdhPJw6FLp8A1a+sGYZ+TYdHDIOruaFwtM9bNbS7VfkkahXrRb54TtJsZ3h/Aa44Sc2y3tGu/iHmA== X-Received: by 2002:adf:ce07:: with SMTP id p7mr19756809wrn.39.1605522187703; Mon, 16 Nov 2020 02:23:07 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:07 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 01/12] t6027: modernise tests Date: Mon, 16 Nov 2020 11:21:47 +0100 Message-Id: <20201116102158.8365-2-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-1-alban.gruin@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Some tests in t6027 uses a if/then/else to check if a command failed or not, but we have the `test_must_fail' function to do it correctly for us nowadays. Signed-off-by: Alban Gruin --- t/t6407-merge-binary.sh | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh index 4e6c7cb77e..071d3f7343 100755 --- a/t/t6407-merge-binary.sh +++ b/t/t6407-merge-binary.sh @@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files' . ./test-lib.sh test_expect_success setup ' - cat "$TEST_DIRECTORY"/test-binary-1.png >m && git add m && git ls-files -s | sed -e "s/ 0 / 1 /" >E1 && @@ -35,33 +34,19 @@ test_expect_success setup ' ' test_expect_success resolve ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s resolve master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s resolve master && + git ls-files -s >current && + test_cmp expect current ' test_expect_success recursive ' - rm -f a* m* && git reset --hard anchor && - - if git merge -s recursive master - then - echo Oops, should not have succeeded - false - else - git ls-files -s >current - test_cmp expect current - fi + test_must_fail git merge -s recursive master && + git ls-files -s >current && + test_cmp expect current ' test_done From patchwork Mon Nov 16 10:21:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908105 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82395C4742C for ; Mon, 16 Nov 2020 11:31:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2A47520578 for ; Mon, 16 Nov 2020 11:31:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MtAOztbU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728933AbgKPKXL (ORCPT ); Mon, 16 Nov 2020 05:23:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34420 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728566AbgKPKXK (ORCPT ); Mon, 16 Nov 2020 05:23:10 -0500 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 3EE79C0613CF for ; Mon, 16 Nov 2020 02:23:10 -0800 (PST) Received: by mail-wr1-x42e.google.com with SMTP id p1so18028949wrf.12 for ; Mon, 16 Nov 2020 02:23:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XF1TFkYKb09IuVXVkVvH6iskGxmP9cD0WNFS1Kly3iE=; b=MtAOztbUyar3V0lT8Vafi/mpEvQjIuC+2txQ/UtfmBFbERuYIQbURZiwZRzburd3uD d8ij1X6QjOJxVR/+SIu0uoM4noOVa7iflK3+qRZNcwMrmFtLtBDu6XzI+6nIWSNGahT8 UFMU079CpTDrwT9pmRZVoWSkY7x6nGwWVTdd8AxHpoLZnCM8OF2K+bpr1ylmcIzIJa7A mSpxVgx15FBoMsOUG5kaw8cxKVlWiYFFe1lKbjJIujXxVxmXeT5eAz3ELhOm3DWL7tx6 bG98P2wBsiLNAjJFQeBHUtYAbwc9OqZ/xZa5rnemvj8Or6/30NYOwEshbhAQz4hJY31X 9LKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XF1TFkYKb09IuVXVkVvH6iskGxmP9cD0WNFS1Kly3iE=; b=QCcK//UpZCTYIXP+7nbNR9wFSdVwrml9wthLvEOa0XIT1DsAHCN+S1WFSvGu9ddrKO KR/OVrWPZ/x6c5iJFMwoXItauyb0wUS3ElgI7ZhDu815ViGYhLo6OLoIZzFqNACD/Vbt 4PhTfQLGBBVYE+tPzbXR1FOdzfaQY5SjVij/An0aXt03ng+I569iBNuNephE5XsReDTz YdEExUWoF0zm3VvbGCLefs+Ubf6xChyEzdeZKTI/teeUfAft4OBXtSoTpMHqTF45lUpP ekxM3Cz+lLyXoqvoPVQIaAycUFun2EytUl2SU9FAI3V8vt3al9+QAsXCGm3XS7kY64Ab +OzA== X-Gm-Message-State: AOAM532fZ1tcX3FDj/cWnTaj7xSLI/+QUhSJie+5ijdVk79xrEb7oEZP KBJauA9n5uk8Tn57Yu+qfdJKmnRjbk0= X-Google-Smtp-Source: ABdhPJy70n97lAMm5ujd9rhMP+QmuO7xXG85kClniHIYtsDtJHynH2OBMjLg2R02R5MAKA3moeIpBQ== X-Received: by 2002:a5d:5146:: with SMTP id u6mr19328658wrt.66.1605522188743; Mon, 16 Nov 2020 02:23:08 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:08 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 02/12] update-index: move add_cacheinfo() to read-cache.c Date: Mon, 16 Nov 2020 11:21:48 +0100 Message-Id: <20201116102158.8365-3-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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. The return value is either 0 (success), -1 (invalid path), or -2 (failed to add the file in 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 | 5 +++++ read-cache.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/builtin/update-index.c b/builtin/update-index.c index 79087bccea..44862f5e1d 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -404,27 +404,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 == -1) + return res; + if (res == -2) 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 c0072d43b1..be16ab3215 100644 --- a/cache.h +++ b/cache.h @@ -830,6 +830,11 @@ 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); +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 **pce); + 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 ecf6f68994..c25f951db4 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1350,6 +1350,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 **pce) +{ + int len, option; + struct cache_entry *ce = NULL; + + if (!verify_path(path, mode)) + return error(_("Invalid path '%s'"), path); + + len = strlen(path); + ce = make_empty_cache_entry(istate, len); + + oidcpy(&ce->oid, oid); + memcpy(ce->name, path, len); + ce->ce_flags = create_ce_flags(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 -2; + } + + if (pce) + *pce = 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 Mon Nov 16 10:21:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908119 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5AF9BC5519F for ; Mon, 16 Nov 2020 11:32:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DFD19206D5 for ; Mon, 16 Nov 2020 11:32:00 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="q8NjN59/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728945AbgKPKXN (ORCPT ); Mon, 16 Nov 2020 05:23:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728566AbgKPKXM (ORCPT ); Mon, 16 Nov 2020 05:23:12 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E4586C0613CF for ; Mon, 16 Nov 2020 02:23:11 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id c17so18029181wrc.11 for ; Mon, 16 Nov 2020 02:23:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tTWsUxGCxlbWYyCqt91U34pYED0jtBBTjmhncZPfW9w=; b=q8NjN59/HeWvEEvTwLF4JBTzkebjcXzVBKUfMxcH0uqeBT71QsZdsmfZcuC3UIhsqm EX4Wd8SCXVVAxAkENvA+yNj/MBHX2zrO9mYA6cpa9tZxwVRcA+FZ6LFV8gKXjJjNgcRr HdfClWnBcodExPuWC+PYlKaSPe6FEqt0G0X4yBxV1JrKt2htKcZFEhYvZ6II1eQm2AfJ GjLsTA//KwniFLoE4P3xwrmaoaOCEgExBiNm+8itf4jeyNSq9q8a+Shv4P4zpjqm5m43 svpJEZp4cYWm1Me97RhPlrRJw6adCjCvVewhPpNtITtBPCXYImqJ2uWg4T0QBHKWSVmU 4R6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tTWsUxGCxlbWYyCqt91U34pYED0jtBBTjmhncZPfW9w=; b=dlN6cOY2f0T6vqTuP8yL6KR6vZuPLYbmVeyCIDw0u/2LHg+5/AD0/ivTIaAlm8/xCb JdiyyWwObtYs1V8TbtZW9mP/H2EoWXxcuAdgXDsUlJTt3qrzyQ2nhC7JVB2JECeUp0A5 PYynloqQOihwFzYY5Qdhu2F+yST/iSw1klYsxtHOBZtZeOM3xLhH8NzvwqQAy1oumZlF YfEm7jnd6qoXix/Wq49oMFDhlYKlRrET2eMKUfzg3Y1mlN8Vkc/R+Te5gM9Qcu6iywr+ J/hbR/xsI0FY9bcCETeIUE39NIO9e9fY+nxq4drm0IBiGoFGZGF2nubXZZ12bEwkmcDf HD5g== X-Gm-Message-State: AOAM532Va60mBWshKCKTUf8eZ70dPzc/TSZAdaF9AUOI4Q2nhHsXxPM6 yDeo7jOuBqJSHomW+d6bJl9gxd1sWC4= X-Google-Smtp-Source: ABdhPJx2i5osdgMqP8GsRYIIti9ZnhIFjsUuWJ7XkTJ1e6291veuG46ri+78ZSc35JVnUILtmkszkg== X-Received: by 2002:adf:9d84:: with SMTP id p4mr18632350wre.370.1605522190079; Mon, 16 Nov 2020 02:23:10 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:09 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 03/12] merge-one-file: rewrite in C Date: Mon, 16 Nov 2020 11:21:49 +0100 Message-Id: <20201116102158.8365-4-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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. Signed-off-by: Alban Gruin --- Makefile | 3 +- builtin.h | 1 + builtin/merge-one-file.c | 94 +++++++++++++++++ git-merge-one-file.sh | 167 ------------------------------ git.c | 1 + merge-strategies.c | 176 ++++++++++++++++++++++++++++++++ merge-strategies.h | 12 +++ t/t6415-merge-dir-to-symlink.sh | 2 +- 8 files changed, 287 insertions(+), 169 deletions(-) create mode 100644 builtin/merge-one-file.c delete mode 100755 git-merge-one-file.sh create mode 100644 merge-strategies.c create mode 100644 merge-strategies.h diff --git a/Makefile b/Makefile index de53954590..6dfdb33cb2 100644 --- a/Makefile +++ b/Makefile @@ -601,7 +601,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 @@ -909,6 +908,7 @@ LIB_OBJS += match-trees.o LIB_OBJS += mem-pool.o LIB_OBJS += merge-blobs.o LIB_OBJS += merge-recursive.o +LIB_OBJS += merge-strategies.o LIB_OBJS += merge.o LIB_OBJS += mergesort.o LIB_OBJS += midx.o @@ -1094,6 +1094,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 53fb290963..4d2cd78856 100644 --- a/builtin.h +++ b/builtin.h @@ -178,6 +178,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix); int cmd_merge_index(int argc, const char **argv, const char *prefix); int cmd_merge_ours(int argc, const char **argv, const char *prefix); int cmd_merge_file(int argc, const char **argv, const char *prefix); +int cmd_merge_one_file(int argc, const char **argv, const char *prefix); int cmd_merge_recursive(int argc, const char **argv, const char *prefix); int cmd_merge_tree(int argc, const char **argv, const char *prefix); int cmd_mktag(int argc, const char **argv, const char *prefix); diff --git a/builtin/merge-one-file.c b/builtin/merge-one-file.c new file mode 100644 index 0000000000..9c21778e1d --- /dev/null +++ b/builtin/merge-one-file.c @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#define USE_THE_INDEX_COMPATIBILITY_MACROS +#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_mode(const char *name, const char *arg, unsigned int *mode) +{ + char *last; + int ret = 0; + + *mode = strtol(arg, &last, 8); + + if (*last) + ret = error(_("invalid '%s' mode: expected nothing, got '%c'"), name, *last); + else if (!(S_ISREG(*mode) || S_ISDIR(*mode) || S_ISLNK(*mode))) + ret = error(_("invalid '%s' mode: %o"), name, *mode); + + return ret; +} + +int cmd_merge_one_file(int argc, const char **argv, const char *prefix) +{ + struct object_id orig_blob, our_blob, their_blob, + *p_orig_blob = NULL, *p_our_blob = NULL, *p_their_blob = NULL; + unsigned int orig_mode = 0, our_mode = 0, their_mode = 0, ret = 0; + struct lock_file lock = LOCK_INIT; + + if (argc != 8) + usage(builtin_merge_one_file_usage); + + if (read_cache() < 0) + die("invalid index"); + + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); + + if (!get_oid_hex(argv[1], &orig_blob)) { + p_orig_blob = &orig_blob; + ret = read_mode("orig", argv[5], &orig_mode); + } else if (!*argv[1] && *argv[5]) + ret = error(_("no 'orig' object id given, but a mode was still given.")); + + if (!get_oid_hex(argv[2], &our_blob)) { + p_our_blob = &our_blob; + ret = read_mode("our", argv[6], &our_mode); + } else if (!*argv[2] && *argv[6]) + ret = error(_("no 'our' object id given, but a mode was still given.")); + + if (!get_oid_hex(argv[3], &their_blob)) { + p_their_blob = &their_blob; + ret = read_mode("their", argv[7], &their_mode); + } else if (!*argv[3] && *argv[7]) + ret = error(_("no 'their' object id given, but a mode was still given.")); + + if (ret) + return ret; + + ret = merge_three_way(the_repository, p_orig_blob, p_our_blob, p_their_blob, + argv[4], orig_mode, our_mode, their_mode); + + if (ret) { + rollback_lock_file(&lock); + return !!ret; + } + + return write_locked_index(&the_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 f1e8b56d99..a4d3f98094 100644 --- a/git.c +++ b/git.c @@ -540,6 +540,7 @@ static struct cmd_struct commands[] = { { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, + { "merge-one-file", cmd_merge_one_file, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c new file mode 100644 index 0000000000..c5576dc891 --- /dev/null +++ b/merge-strategies.c @@ -0,0 +1,176 @@ +#include "cache.h" +#include "dir.h" +#include "merge-strategies.h" +#include "xdiff-interface.h" + +static int checkout_from_index(struct index_state *istate, const char *path, + struct cache_entry *ce) +{ + 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 != our_mode) || + (their_blob && orig_mode != their_mode)) + return error(_("File %s deleted on one branch but had its " + "permissions changed on the other."), path); + + if (our_blob) { + printf(_("Removing %s\n"), path); + + if (file_exists(path)) + remove_path(path); + } + + if (remove_file_from_index(istate, path)) + return error("%s: cannot remove from the index", path); + return 0; +} + +static int do_merge_one_file(struct index_state *istate, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + int ret, i, dest; + 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); + else if (our_mode != their_mode) + return error(_("permission conflict: %o->%o,%o in %s"), + orig_mode, our_mode, their_mode, 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")); + } else if (ret > 0 || !orig_blob) { + free(result.ptr); + return error(_("content conflict in %s"), 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); + + return add_file_to_index(istate, path, 0); +} + +int merge_three_way(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode) +{ + if (orig_blob && + ((!their_blob && our_blob && oideq(orig_blob, our_blob)) || + (!our_blob && their_blob && oideq(orig_blob, their_blob)))) { + /* Deleted in both or deleted in one and unchanged in the other. */ + return merge_one_file_deleted(r->index, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + } else if (!orig_blob && our_blob && !their_blob) { + /* + * Added in one. The other side did not add and we + * added so there is nothing to be done, except making + * the path merged. + */ + return add_to_index_cacheinfo(r->index, our_mode, our_blob, + path, 0, 1, 1, NULL); + } else if (!orig_blob && !our_blob && their_blob) { + struct cache_entry *ce; + printf(_("Adding %s\n"), path); + + if (file_exists(path)) + return error(_("untracked %s is overwritten by the merge."), path); + + if (add_to_index_cacheinfo(r->index, their_mode, their_blob, + path, 0, 1, 1, &ce)) + return -1; + return checkout_from_index(r->index, path, ce); + } else if (!orig_blob && our_blob && their_blob && + oideq(our_blob, their_blob)) { + struct cache_entry *ce; + + /* Added in both, identically (check for same permissions). */ + if (our_mode != their_mode) + return error(_("File %s added identically in both branches, " + "but permissions conflict %o->%o."), + path, our_mode, their_mode); + + printf(_("Adding %s\n"), path); + + if (add_to_index_cacheinfo(r->index, our_mode, our_blob, + path, 0, 1, 1, &ce)) + return -1; + return checkout_from_index(r->index, path, ce); + } else if (our_blob && their_blob) { + /* Modified in both, but differently. */ + return do_merge_one_file(r->index, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); + } else { + char orig_hex[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; +} diff --git a/merge-strategies.h b/merge-strategies.h new file mode 100644 index 0000000000..e624c4f27c --- /dev/null +++ b/merge-strategies.h @@ -0,0 +1,12 @@ +#ifndef MERGE_STRATEGIES_H +#define MERGE_STRATEGIES_H + +#include "object.h" + +int merge_three_way(struct repository *r, + const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode); + +#endif /* MERGE_STRATEGIES_H */ diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2eddcc7664..5fb74e39a0 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -94,7 +94,7 @@ test_expect_success SYMLINKS 'a/b was resolved as symlink' ' test -h a/b ' -test_expect_failure 'do not lose untracked in merge (resolve)' ' +test_expect_success 'do not lose untracked in merge (resolve)' ' git reset --hard && git checkout baseline^0 && >a/b/c/e && From patchwork Mon Nov 16 10:21:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908109 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DAD6CC5519F for ; Mon, 16 Nov 2020 11:31:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 826AA206B7 for ; Mon, 16 Nov 2020 11:31:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LGdClJzD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728958AbgKPKXO (ORCPT ); Mon, 16 Nov 2020 05:23:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbgKPKXN (ORCPT ); Mon, 16 Nov 2020 05:23:13 -0500 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C6DCBC0613D1 for ; Mon, 16 Nov 2020 02:23:12 -0800 (PST) Received: by mail-wr1-x442.google.com with SMTP id l1so18043477wrb.9 for ; Mon, 16 Nov 2020 02:23:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=O9i3dFKurz9LKwf6yXmA10w2J1MngtedFVAZEOjLrD8=; b=LGdClJzDhuIUhNYIjwuAM/ixi8tY0Z4BCQHSCJNZz9a4ruIF/MSNZowDF1Aoss0E5t N6uiDhh88gRjGbrG7c6UeRDRR2d7RsTjUV1IHlU+VQcFt1ARQGf6+oQ0JVY1fWkftr7P +j4NrThPPB2JI9XU8Oep+hiCyL+AOSupKdpQ54j8P+ON2QzxdHcqJEExtjUkyK2SIUuB XwyOFBJU1vSUizCs6v/dPPTK629vGJJ9m9bAgA9E66Szlm1PEbbD8tgFBy5Ibl7pezgI rPc8Zq6iQniEFoxANckF0NBIcJRzptoAkXG4dzOGiQMsroHy7zIBy/CjgEB2nP0Dxl8Q wA3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=O9i3dFKurz9LKwf6yXmA10w2J1MngtedFVAZEOjLrD8=; b=st1nKLhH60VOKHpnH12NPvGKSvGVl8SxxUS507Jc7YTpcOXIzpP57ruqSr0Z0eZ6LX F9ksNHJZOlc/8wYC0jNvx+ij6GgTZDBN9X6eQuTmf55TY5/OZqR33EJyFVVVhltMovaw e+zdBB8HEYtg2Oj5In9mzvcAoyGRWkOoAcoz5+8o9ugEQkOIfLvyQBx9elFVz8HK5Dym YUC2Pgo2KVQSlwRKD/x+HJUuYuWn42PJGRiI2rItRwQhXE5GIMr3uDzRQgstzKNVbNf9 dnV9oz1UapUPnhwfhC29wXSJxES5T0lrqO8q92St5GaB9GhGlMKO4knppDzrRyqaGO2L vt/A== X-Gm-Message-State: AOAM530RtzSagESdcNJjXpNYa6bQNv5tqhSCTV8WCq+SB4Ke3+z57HUg mgENqkUZ1lkhqiaA2nxPW3dRzl4Ak7g= X-Google-Smtp-Source: ABdhPJwBrggJ9suN5qR7aiKd4L+P6+IGs3iVVPYFxQ78wnYg7izdcN1Tloa9si0beWXfYF85Lu/oTQ== X-Received: by 2002:adf:f607:: with SMTP id t7mr18292184wrp.169.1605522191190; Mon, 16 Nov 2020 02:23:11 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:10 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 04/12] merge-index: libify merge_one_path() and merge_all() Date: Mon, 16 Nov 2020 11:21:50 +0100 Message-Id: <20201116102158.8365-5-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 --- builtin/merge-index.c | 77 +++---------------------------- merge-strategies.c | 103 ++++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 17 +++++++ 3 files changed, 127 insertions(+), 70 deletions(-) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 38ea6ad6ca..49e3382fb9 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,74 +1,11 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" -#include "run-command.h" - -static const char *pgm; -static int one_shot, quiet; -static int err; - -static int merge_entry(int pos, const char *path) -{ - int found; - const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL }; - char hexbuf[4][GIT_MAX_HEXSZ + 1]; - char ownbuf[4][60]; - - if (pos >= active_nr) - die("git merge-index: %s not in the cache", path); - found = 0; - do { - const struct cache_entry *ce = active_cache[pos]; - int stage = ce_stage(ce); - - if (strcmp(ce->name, path)) - break; - found++; - oid_to_hex_r(hexbuf[stage], &ce->oid); - xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); - arguments[stage] = hexbuf[stage]; - arguments[stage + 4] = ownbuf[stage]; - } while (++pos < active_nr); - if (!found) - die("git merge-index: %s not in the cache", path); - - if (run_command_v_opt(arguments, 0)) { - if (one_shot) - err++; - else { - if (!quiet) - die("merge program failed"); - exit(1); - } - } - return found; -} - -static void merge_one_path(const char *path) -{ - int pos = cache_name_pos(path, strlen(path)); - - /* - * If it already exists in the cache as stage0, it's - * already merged and there is nothing to do. - */ - if (pos < 0) - merge_entry(-pos-1, path); -} - -static void merge_all(void) -{ - int i; - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - i += merge_entry(i, ce->name)-1; - } -} +#include "merge-strategies.h" int cmd_merge_index(int argc, const char **argv, const char *prefix) { - int i, force_file = 0; + int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; + const char *pgm; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -98,14 +35,14 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-a")) { - merge_all(); + err |= merge_all_index(&the_index, one_shot, quiet, + merge_one_file_spawn, (void *)pgm); 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, (void *)pgm); } - if (err && !quiet) - die("merge program failed"); return err; } diff --git a/merge-strategies.c b/merge-strategies.c index c5576dc891..4eb96129f1 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,6 +1,7 @@ #include "cache.h" #include "dir.h" #include "merge-strategies.h" +#include "run-command.h" #include "xdiff-interface.h" static int checkout_from_index(struct index_state *istate, const char *path, @@ -174,3 +175,105 @@ int merge_three_way(struct repository *r, return 0; } + +int merge_one_file_spawn(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data) +{ + char oids[3][GIT_MAX_HEXSZ + 1] = {{0}}; + char modes[3][10] = {{0}}; + const char *arguments[] = { (char *)data, oids[0], oids[1], oids[2], + path, modes[0], modes[1], modes[2], NULL }; + + if (orig_blob) { + oid_to_hex_r(oids[0], orig_blob); + xsnprintf(modes[0], sizeof(modes[0]), "%06o", orig_mode); + } + + if (our_blob) { + oid_to_hex_r(oids[1], our_blob); + xsnprintf(modes[1], sizeof(modes[1]), "%06o", our_mode); + } + + 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); +} + +static int merge_entry(struct index_state *istate, int quiet, int pos, + const char *path, 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(oids[0], oids[1], oids[2], path, modes[0], modes[1], modes[2], data)) { + if (!quiet) + error(_("Merge program failed")); + return -2; + } + + return found; +} + +int merge_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; + + /* + * If it already exists in the cache as stage0, it's + * already merged and there is nothing to do. + */ + if (pos < 0) { + ret = merge_entry(istate, quiet, -pos - 1, path, fn, data); + if (ret == -1) + return -1; + else if (ret == -2) + return 1; + } + return 0; +} + +int merge_all_index(struct index_state *istate, int oneshot, int quiet, + merge_fn fn, void *data) +{ + int err = 0, i, ret; + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; + if (!ce_stage(ce)) + continue; + + ret = merge_entry(istate, quiet, i, ce->name, fn, data); + if (ret > 0) + i += ret - 1; + else if (ret == -1) + return -1; + else if (ret == -2) { + if (oneshot) + err++; + else + return 1; + } + } + + return err; +} diff --git a/merge-strategies.h b/merge-strategies.h index e624c4f27c..d2f52d6792 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -9,4 +9,21 @@ int merge_three_way(struct repository *r, 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)(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data); + +int merge_one_file_spawn(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 */ From patchwork Mon Nov 16 10:21:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908117 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B34ACC5519F for ; Mon, 16 Nov 2020 11:32:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5A857206D5 for ; Mon, 16 Nov 2020 11:32:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dirDWaxB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728989AbgKPKXP (ORCPT ); Mon, 16 Nov 2020 05:23:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34436 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbgKPKXO (ORCPT ); Mon, 16 Nov 2020 05:23:14 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E4207C0613CF for ; Mon, 16 Nov 2020 02:23:13 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id c17so18029314wrc.11 for ; Mon, 16 Nov 2020 02:23:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=eN5AsqAo7eJjL+aiPSr/B/Ni3cQHcqh53762V550vWw=; b=dirDWaxBvFQGLSMFexani1erzBcrV2GNGXSH9Z5VXg2pzwBYsjxTJC5TtSgPGzaxtq 702qxdSwguQWG/oKZz/5NXqfxwGrQdmxzn5P/RxK2kYjMophYnvsy0aqyfGhA7zNAw9j z0UxMRjtDjRKZ9BhqI9n19xZo5EHoqQx+l01u17uCfKMF6ImFy6NE8MhRZtJUGGyXiG4 RK1XjJ7JaVZXW0H66xYa/3P5a7BvNzWvbb7cM9YRjcRkxZZY7VCD/g41fLOC2RKJ8H+u DuELlTq+nCxr8YWkUQmIECqTqJ1Ztp/sdztGiM+o13laWTcBTWJA2//Wv9mNUA+sYXjf KJsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eN5AsqAo7eJjL+aiPSr/B/Ni3cQHcqh53762V550vWw=; b=jiAI1AmNPaO40wxIN9zU3GPyIIZwHr5JM5+ysCzQLug+MsfSODQlB9lqxGMShet1Ya heLlYkZSVLQk6R+45wYuMyK8F2c9jcorEwzYLiKlFzmIonCuO5erjUqk5yAYc5AUYEUw cQJ2Jxp9w7uG27Kq/B0Rs4PUSRHnFjIxCIB+NMS7U7V3j9eDtRy85uusyTHMSujDpWXB Hn2Z2mANjwr22ewW7PGd1qfIxXHfc2tIYC9kUPlEwrVRV+n/eWvjGg3a5mrlnFQxgCo8 l8agt7tDOq1C3RbofZQD4uz6KBASWA5j0AK9dunM2CvMQ+ASSNBWsMjGlrPWL1DUsP/J 7VTQ== X-Gm-Message-State: AOAM532+zj1SgMCkJ5oFvNeORlnboUX1RiulBaueuM3Ym6NJj/XHn/HU Uag3qImYB6gauSDT5ZMLHKEqXyejdzY= X-Google-Smtp-Source: ABdhPJwP3Q1giA0ezkC/Rq7jQZH9DImPl6DIv93hsxzkX3v9rV4RY6FSo1F/K8WrKBUG0PMRLQ1jTQ== X-Received: by 2002:a5d:5308:: with SMTP id e8mr18333865wrv.299.1605522192408; Mon, 16 Nov 2020 02:23:12 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:11 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 05/12] merge-index: don't fork if the requested program is `git-merge-one-file' Date: Mon, 16 Nov 2020 11:21:51 +0100 Message-Id: <20201116102158.8365-6-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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' has been rewritten and libified, this teaches `merge-index' to call merge_three_way() without forking using a new callback, merge_one_file_func(). Signed-off-by: Alban Gruin --- builtin/merge-index.c | 29 +++++++++++++++++++++++++++-- merge-strategies.c | 11 +++++++++++ merge-strategies.h | 6 ++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 49e3382fb9..e684811d35 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,11 +1,15 @@ #define USE_THE_INDEX_COMPATIBILITY_MACROS #include "builtin.h" +#include "lockfile.h" #include "merge-strategies.h" int cmd_merge_index(int argc, const char **argv, const char *prefix) { int i, force_file = 0, err = 0, one_shot = 0, quiet = 0; const char *pgm; + void *data; + merge_fn merge_action; + struct lock_file lock = LOCK_INIT; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -26,7 +30,19 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) quiet = 1; i++; } + pgm = argv[i++]; + if (!strcmp(pgm, "git-merge-one-file")) { + merge_action = merge_one_file_func; + data = (void *)the_repository; + + setup_work_tree(); + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); + } else { + merge_action = merge_one_file_spawn; + data = (void *)pgm; + } + for (; i < argc; i++) { const char *arg = argv[i]; if (!force_file && *arg == '-') { @@ -36,13 +52,22 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "-a")) { err |= merge_all_index(&the_index, one_shot, quiet, - merge_one_file_spawn, (void *)pgm); + merge_action, data); continue; } die("git merge-index: unknown option %s", arg); } err |= merge_index_path(&the_index, one_shot, quiet, arg, - merge_one_file_spawn, (void *)pgm); + merge_action, data); + } + + if (merge_action == merge_one_file_func) { + if (err) { + rollback_lock_file(&lock); + return err; + } + + return write_locked_index(&the_index, &lock, COMMIT_LOCK); } return err; } diff --git a/merge-strategies.c b/merge-strategies.c index 4eb96129f1..2ed3a8dd68 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -176,6 +176,17 @@ int merge_three_way(struct repository *r, return 0; } +int merge_one_file_func(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((struct repository *)data, + orig_blob, our_blob, their_blob, path, + orig_mode, our_mode, their_mode); +} + int merge_one_file_spawn(const struct object_id *orig_blob, const struct object_id *our_blob, const struct object_id *their_blob, const char *path, diff --git a/merge-strategies.h b/merge-strategies.h index d2f52d6792..b69a12b390 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -15,6 +15,12 @@ typedef int (*merge_fn)(const struct object_id *orig_blob, unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, void *data); +int merge_one_file_func(const struct object_id *orig_blob, + const struct object_id *our_blob, + const struct object_id *their_blob, const char *path, + unsigned int orig_mode, unsigned int our_mode, unsigned int their_mode, + void *data); + int merge_one_file_spawn(const struct object_id *orig_blob, const struct object_id *our_blob, const struct object_id *their_blob, const char *path, From patchwork Mon Nov 16 10:21:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908115 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 29311C5519F for ; Mon, 16 Nov 2020 11:32:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B5DB9206D5 for ; Mon, 16 Nov 2020 11:32:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pl5Yrl95" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729001AbgKPKXR (ORCPT ); Mon, 16 Nov 2020 05:23:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34440 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728937AbgKPKXP (ORCPT ); Mon, 16 Nov 2020 05:23:15 -0500 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F7E7C0613CF for ; Mon, 16 Nov 2020 02:23:15 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id d12so18029146wrr.13 for ; Mon, 16 Nov 2020 02:23:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=hg2XSbyICPv99XPQxRCCxccouPyL3+plBczAYX6NiXM=; b=pl5Yrl95s+hV187ClSrf5FYFRPBlhpKDb09GNRTN6fpJ4cqKLJ/tB6aMF/uiBSsK7r 6WhVYfQcEzeUYFm3NYUKUsStoHlArJlLDWrkyoQ9acIkBtY8lqUXLBPDOfVr0jeNSzq1 16lD16uJVNZ3lOaCUJciWROdeUUIOZgLpe3BO5E2uoNTaOZI+aL+7eeh3KOsVFcJhhLP Lk2Iuj3o1b6NcTXH0DS/sUrizptaUWsoEqWW5OSXZclRzH63y1B6XUh4jB+RT1/VrAfx hCvovOCAq/FKQ2V1Bzl+XlW0ffJz+1XExRikAaf7ZyU+5T7Ylr17CnfqhtNMvPBS3vHK grGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=hg2XSbyICPv99XPQxRCCxccouPyL3+plBczAYX6NiXM=; b=rjde8xYF2R8TzW/pGEIQ8ajGcUiMfWkj/pj3FPHb4tQIBSLbSnnMZRsjTR9bUnSDUO AjT0h0S5LEuihbqj0f/JoWbKCEaC01bQfkDUd5JxiH7Ob4akFRuceikCpBOvpmPQqMm2 LKRta+AR2EqlxzE3W7tg30T2P6m01+jvdh7f016G17x76q738vNzsDIVvTYWWf6CBR4n R2GJUfKlKdweUmT7AGtROmMacT2Lo/WPPUOK80dYe22YMS3CKYaoImuC+p0lttnv1cuL Y5NQtxDDXu9kGBlFDK7fYG7WrZyYq43WEIj/C8n7YtDo5RCFcMvzUL0ptXrTXaio8yjC zWXA== X-Gm-Message-State: AOAM530FHKCElrL+ta3kOkVze5I8dGFeAnvKYOeXJFf7JOit2MuFlI0p IZST2avSMO3HI8kN/9DsqB593EqPwWs= X-Google-Smtp-Source: ABdhPJxNSsEv+fYc013P05XID9BVMGPksi8/RSzqIBJdh2R0EUYG7/qq44GigdNP4aEw2pVeACVLZg== X-Received: by 2002:adf:f246:: with SMTP id b6mr17687040wrp.238.1605522193819; Mon, 16 Nov 2020 02:23:13 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:13 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 06/12] merge-resolve: rewrite in C Date: Mon, 16 Nov 2020 11:21:52 +0100 Message-Id: <20201116102158.8365-7-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 write_index_as_tree(). - The call to `merge-index', needed to invoke `git merge-one-file', is replaced by a call to the new merge_all_index() function. The index is read in cmd_merge_resolve(), and is wrote back by merge_strategies_resolve(). The parameters of merge_strategies_resolve() will be surprising at first glance: why using a commit list for `bases' and `remote', where we could use an oid array, and a pointer to an oid? Because, in a later commit, try_merge_strategy() will be able to call merge_strategies_resolve() directly, and it already uses a commit list for `bases' (`common') and `remote' (`remoteheads'), and a string for `head_arg'. To reduce frictions later, merge_strategies_resolve() takes the same types of parameters. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-resolve.c | 73 +++++++++++++++++++++++++++++++ git-merge-resolve.sh | 54 ----------------------- git.c | 1 + merge-strategies.c | 95 +++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 5 +++ 7 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 builtin/merge-resolve.c delete mode 100755 git-merge-resolve.sh diff --git a/Makefile b/Makefile index 6dfdb33cb2..3cc6b192f1 100644 --- a/Makefile +++ b/Makefile @@ -601,7 +601,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 @@ -1097,6 +1096,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 4d2cd78856..35e91c16d0 100644 --- a/builtin.h +++ b/builtin.h @@ -180,6 +180,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..dca31676b8 --- /dev/null +++ b/builtin/merge-resolve.c @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#define USE_THE_INDEX_COMPATIBILITY_MACROS +#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; + + if (argc < 5) + usage(builtin_merge_resolve_usage); + + setup_work_tree(); + if (read_cache() < 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 = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + commit_list_insert(commit, &remote); + else + next_base = commit_list_append(commit, next_base); + } + } + + /* + * 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; + + return merge_strategies_resolve(the_repository, bases, head, remote); +} diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh deleted file mode 100755 index 343fe7bccd..0000000000 --- a/git-merge-resolve.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two trees, using enhanced multi-base read-tree. - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Give up if we are given two or more remotes -- not handling octopus. -case "$remotes" in -?*' '?*) - exit 2 ;; -esac - -# Give up if this is a baseless merge. -if test '' = "$bases" -then - exit 2 -fi - -git update-index -q --refresh -git read-tree -u -m --aggressive $bases $head $remotes || exit 2 -echo "Trying simple merge." -if result_tree=$(git write-tree 2>/dev/null) -then - exit 0 -else - echo "Simple merge failed, trying Automatic merge." - if git merge-index -o git-merge-one-file -a - then - exit 0 - else - exit 1 - fi -fi diff --git a/git.c b/git.c index a4d3f98094..64a1a1de41 100644 --- a/git.c +++ b/git.c @@ -544,6 +544,7 @@ static struct cmd_struct commands[] = { { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-resolve", cmd_merge_resolve, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT }, { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, diff --git a/merge-strategies.c b/merge-strategies.c index 2ed3a8dd68..9fafee5954 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,7 +1,10 @@ #include "cache.h" +#include "cache-tree.h" #include "dir.h" +#include "lockfile.h" #include "merge-strategies.h" #include "run-command.h" +#include "unpack-trees.h" #include "xdiff-interface.h" static int checkout_from_index(struct index_state *istate, const char *path, @@ -288,3 +291,95 @@ int merge_all_index(struct index_state *istate, int oneshot, int quiet, return err; } + +static int fast_forward(struct repository *r, struct tree_desc *t, + int nr, int aggressive) +{ + struct unpack_trees_options opts; + struct lock_file lock = LOCK_INIT; + + refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = r->index; + opts.dst_index = r->index; + opts.merge = 1; + opts.update = 1; + opts.aggressive = aggressive; + + if (nr == 1) + opts.fn = oneway_merge; + else if (nr == 2) { + opts.fn = twoway_merge; + opts.initial_checkout = is_index_unborn(r->index); + } else if (nr >= 3) { + opts.fn = threeway_merge; + opts.head_idx = nr - 1; + } + + if (unpack_trees(nr, t, &opts)) + return -1; + + if (write_locked_index(r->index, &lock, COMMIT_LOCK)) + return error(_("unable to write new index file")); + + return 0; +} + +static int 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; +} + +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 object_id head, oid; + struct commit_list *i; + int nr = 0; + + if (head_arg) + get_oid(head_arg, &head); + + 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 tree *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; + + if (fast_forward(r, t, nr, 1)) + return 2; + + if (write_index_as_tree(&oid, r->index, r->index_file, + WRITE_TREE_SILENT, NULL)) { + int ret; + struct lock_file lock = LOCK_INIT; + + puts(_("Simple merge failed, trying Automatic merge.")); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = merge_all_index(r->index, 0, 0, merge_one_file_func, r); + + write_locked_index(r->index, &lock, COMMIT_LOCK); + return !!ret; + } + + return 0; +} diff --git a/merge-strategies.h b/merge-strategies.h index b69a12b390..4f996261b4 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 repository *r, @@ -32,4 +33,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 Mon Nov 16 10:21:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908121 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2D4CC4742C for ; Mon, 16 Nov 2020 11:33:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4D150206D5 for ; Mon, 16 Nov 2020 11:33:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UWlujxU+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729004AbgKPKXS (ORCPT ); Mon, 16 Nov 2020 05:23:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728982AbgKPKXQ (ORCPT ); Mon, 16 Nov 2020 05:23:16 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62009C0613D1 for ; Mon, 16 Nov 2020 02:23:16 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id c9so23196267wml.5 for ; Mon, 16 Nov 2020 02:23:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=erCmlE+BY3YMPeBRvPZQFAVR4wjD0xnNAA1juWeRcK8=; b=UWlujxU+UndbHuUFvor1vjsf4nCRlck+uL5s8USLmYqIcLMTadFW4Hpq5vkxPOAxLW Y4vnq+ATq1ZzneiqTVUrs6egONhS9bQIMq01FEL1ASBHPOa3MoZ7SfPVtnlMnt+Or1FC WQbaJF3grYzOovvNsNV3zVKcF/FozCNdwMWtUXXzGlj/SEF4keIFiJ/hgLgZcBejySfU N6JzCHxmQbOnI1hyI9wuYOur9qKDjicAWBDXjrJyMfs+GxePsKFFybBwAs50EICmmbKR ZaG10j3CSDntRnKwpl+mGMAMycXA+P2ZTmnWZoTGH45vdzRYvO6ZTV+E4P1vOnZywnnU G+HA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=erCmlE+BY3YMPeBRvPZQFAVR4wjD0xnNAA1juWeRcK8=; b=r2+nWRqayx6IcvP4XEBnPzkPLOXodB2nFF3ND2N73OYjHT2PY/1VR6aW9jqFwfyBAq sG7JOuN6yDQY5G62v39MOhqj2q5hhp8NoNxUk9oFU+WxyEZBKeOupfk3oxUwl0/i5jPN ZKXWEWkbsftxLIzUCpyGNLjN8FCAugbPCLT12iYn1NnI2ycQb4a+c5lYCUQdlVsfPoyb aKYSVGYmOw+cMoKg6gG+z6y6cUfPWLIIqiIonugVmXQiO75E8mn2C3W+o8G/v7D+r7F4 1pdSV9t7wPoNonwqS3ROZbVcMbxLlJQdBGkHarAeOKeFEEk8vwUmaNEEM2ZgcLvTiYqO /p7A== X-Gm-Message-State: AOAM530iiTu6PXHJ0Ed+FM+QeyR1jW8kCAS+jEzN07ijUSYiIlrckOLh rVholSQstaAAxxGs1OcURAirS8tUfgo= X-Google-Smtp-Source: ABdhPJxvPau7cZkzcX2X7RR+iNnYItAJp33mY6gVqb39uUQC065Fe7vyVu4vyg00G+APydDUhQBBLg== X-Received: by 2002:a1c:df04:: with SMTP id w4mr14566438wmg.3.1605522194818; Mon, 16 Nov 2020 02:23:14 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:14 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 07/12] merge-recursive: move better_branch_name() to merge.c Date: Mon, 16 Nov 2020 11:21:53 +0100 Message-Id: <20201116102158.8365-8-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 a4bfd8fc51..972243b5e9 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -8,18 +8,6 @@ static const char builtin_merge_recursive_usage[] = "git %s ... -- ..."; -static char *better_branch_name(const char *branch) -{ - static char githead_env[8 + GIT_MAX_HEXSZ + 1]; - char *name; - - if (strlen(branch) != the_hash_algo->hexsz) - return xstrdup(branch); - xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); - name = getenv(githead_env); - return xstrdup(name ? name : branch); -} - int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { const struct object_id *bases[21]; @@ -75,8 +63,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (get_oid(o.branch2, &h2)) die(_("could not resolve ref '%s'"), o.branch2); - o.branch1 = better1 = better_branch_name(o.branch1); - o.branch2 = better2 = better_branch_name(o.branch2); + o.branch1 = better1 = merge_get_better_branch_name(o.branch1); + o.branch2 = better2 = merge_get_better_branch_name(o.branch2); if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); diff --git a/cache.h b/cache.h index be16ab3215..2d844576ea 100644 --- a/cache.h +++ b/cache.h @@ -1933,7 +1933,7 @@ int checkout_fast_forward(struct repository *r, const struct object_id *from, const struct object_id *to, int overwrite_ignore); - +char *merge_get_better_branch_name(const char *branch); int sane_execvp(const char *file, char *const argv[]); diff --git a/merge.c b/merge.c index 5fb88af102..801d673c5f 100644 --- a/merge.c +++ b/merge.c @@ -109,3 +109,15 @@ int checkout_fast_forward(struct repository *r, return error(_("unable to write new index file")); return 0; } + +char *merge_get_better_branch_name(const char *branch) +{ + static char githead_env[8 + GIT_MAX_HEXSZ + 1]; + char *name; + + if (strlen(branch) != the_hash_algo->hexsz) + return xstrdup(branch); + xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); + name = getenv(githead_env); + return xstrdup(name ? name : branch); +} From patchwork Mon Nov 16 10:21:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908123 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 268FBC4742C for ; Mon, 16 Nov 2020 11:33:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A5B7A206D5 for ; Mon, 16 Nov 2020 11:33:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gJIcPHqF" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729023AbgKPKXT (ORCPT ); Mon, 16 Nov 2020 05:23:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34452 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728982AbgKPKXS (ORCPT ); Mon, 16 Nov 2020 05:23:18 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 00713C0613CF for ; Mon, 16 Nov 2020 02:23:17 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id w24so23102381wmi.0 for ; Mon, 16 Nov 2020 02:23:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HjE+poeRybBXKLcIhJwJCi+R7eoMU8bVAR9p52Ihx/U=; b=gJIcPHqFI/uO+TLSqhhPBk92v87LZEIRGQfjBuXwzT/63v+jdBS9HDqcETV/Yfn/Yb YK99rVddlQI2CxWnJ/WVVolWlJvKiUSSikyUvNSNObfTNcbOrEE9ul5Qh6SXdutahlur ERF6YCMubvk6k2DSyLNdGDqMnyxZnqf3Fey856dFONsJuVNRn0aFZ7YituQucjPolRay NQY9VcJUXdK5jxQIEuRZ3NZIqmII3i3pPvblthRcNAIXXBJnmruh3m9/u+diUfyPpAQC 0TqcvCZx3XBXVJpSOalo3oL+ee9bHR+Ifa7bWBs0IImGOCqxy5BaXl5roI6wGfbJynhs YxFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HjE+poeRybBXKLcIhJwJCi+R7eoMU8bVAR9p52Ihx/U=; b=HAHzNugi/8040yuRoP6TTIj2HdA/K6BzGTlSaqf4LH1M2/UVGFdVuDwaOX0pvXO91p GhltAgChSk5kV+OnnjCl6YRIsBjdj1J+xOp7UWl38nDo3nCY5fAEa6A8mJmzbMwnpftH YIZM7Rip0BsTQaggpYU+qGyiuOVgtas5PE1jPyq3u9fEXuuvUVbNQlO/d6m6eAF8qNQc Z3zrysBDCWA5cCGm5Fq81KLZ1RSFULtoakzQD1Vo+i8f1UJ5DtlnrU+aPU5Q81YZ/baA SzISKF80HKSDGGE3yBxM5w40BrneI+HkwGHGGkcNLobVatXEd899pSovYQQjETc7yIf6 r3cg== X-Gm-Message-State: AOAM531g/us6Zl+d1rnXjn52lwhgX5IMNpm9RpRh/KgSAjmPiZt7lxXt E3IH8yaY6Cwn6CcCjhaFeup09XJ/DAc= X-Google-Smtp-Source: ABdhPJyzmFpavgxI+oFfRuZEGeDg991BIWyeBv6j8JxWGhqp4UMXhMSUPvqhOUH55akEJSSNMDAAvQ== X-Received: by 2002:a1c:3d05:: with SMTP id k5mr15337687wma.151.1605522196147; Mon, 16 Nov 2020 02:23:16 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:15 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 08/12] merge-octopus: rewrite in C Date: Mon, 16 Nov 2020 11:21:54 +0100 Message-Id: <20201116102158.8365-9-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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_index_as_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 wrote back by merge_strategies_octopus(). Here to, merge_strategies_octopus() takes two commit lists and a string to reduce frictions when try_merge_strategies() will be modified to call it directly. Signed-off-by: Alban Gruin --- Makefile | 2 +- builtin.h | 1 + builtin/merge-octopus.c | 69 ++++++++++++++++ git-merge-octopus.sh | 112 ------------------------- git.c | 1 + merge-strategies.c | 179 ++++++++++++++++++++++++++++++++++++++++ merge-strategies.h | 3 + 7 files changed, 254 insertions(+), 113 deletions(-) create mode 100644 builtin/merge-octopus.c delete mode 100755 git-merge-octopus.sh diff --git a/Makefile b/Makefile index 3cc6b192f1..2b2bdffafe 100644 --- a/Makefile +++ b/Makefile @@ -600,7 +600,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 @@ -1093,6 +1092,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 35e91c16d0..50225404a0 100644 --- a/builtin.h +++ b/builtin.h @@ -176,6 +176,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..ca8f9f345d --- /dev/null +++ b/builtin/merge-octopus.c @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#define USE_THE_INDEX_COMPATIBILITY_MACROS +#include "cache.h" +#include "builtin.h" +#include "commit.h" +#include "merge-strategies.h" + +static const char builtin_merge_octopus_usage[] = + "git merge-octopus [...] -- [...]"; + +int cmd_merge_octopus(int argc, const char **argv, const char *prefix) +{ + int i, sep_seen = 0; + struct commit_list *bases = NULL, *remotes = NULL; + struct commit_list **next_base = &bases, **next_remote = &remotes; + const char *head_arg = NULL; + + if (argc < 5) + usage(builtin_merge_octopus_usage); + + setup_work_tree(); + if (read_cache() < 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 = lookup_commit_or_die(&oid, argv[i]); + + if (sep_seen) + next_remote = commit_list_append(commit, next_remote); + else + next_base = commit_list_append(commit, next_base); + } + } + + /* + * Reject if this is not an octopus -- resolve should be used + * instead. + */ + if (commit_list_count(remotes) < 2) + return 2; + + return merge_strategies_octopus(the_repository, bases, head_arg, remotes); +} diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh deleted file mode 100755 index 7d19d37951..0000000000 --- a/git-merge-octopus.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# -# Resolve two or more trees. -# - -. git-sh-setup - -LF=' -' - -# The first parameters up to -- are merge bases; the rest are heads. -bases= head= remotes= sep_seen= -for arg -do - case ",$sep_seen,$head,$arg," in - *,--,) - sep_seen=yes - ;; - ,yes,,*) - head=$arg - ;; - ,yes,*) - remotes="$remotes$arg " - ;; - *) - bases="$bases$arg " - ;; - esac -done - -# Reject if this is not an octopus -- resolve should be used instead. -case "$remotes" in -?*' '?*) - ;; -*) - exit 2 ;; -esac - -# MRC is the current "merge reference commit" -# MRT is the current "merge result tree" - -if ! git diff-index --quiet --cached HEAD -- -then - gettextln "Error: Your local changes to the following files would be overwritten by merge" - git diff-index --cached --name-only HEAD -- | sed -e 's/^/ /' - exit 2 -fi -MRC=$(git rev-parse --verify -q $head) -MRT=$(git write-tree) -NON_FF_MERGE=0 -OCTOPUS_FAILURE=0 -for SHA1 in $remotes -do - case "$OCTOPUS_FAILURE" in - 1) - # We allow only last one to have a hand-resolvable - # conflicts. Last round failed and we still had - # a head to merge. - gettextln "Automated merge did not work." - gettextln "Should not be doing an octopus." - exit 2 - esac - - eval pretty_name=\${GITHEAD_$SHA1:-$SHA1} - if test "$SHA1" = "$pretty_name" - then - SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)" - eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name} - fi - common=$(git merge-base --all $SHA1 $MRC) || - die "$(eval_gettext "Unable to find common commit with \$pretty_name")" - - case "$LF$common$LF" in - *"$LF$SHA1$LF"*) - eval_gettextln "Already up to date with \$pretty_name" - continue - ;; - esac - - if test "$common,$NON_FF_MERGE" = "$MRC,0" - then - # The first head being merged was a fast-forward. - # Advance MRC to the head being merged, and use that - # tree as the intermediate result of the merge. - # We still need to count this as part of the parent set. - - eval_gettextln "Fast-forwarding to: \$pretty_name" - git read-tree -u -m $head $SHA1 || exit - MRC=$SHA1 MRT=$(git write-tree) - continue - fi - - NON_FF_MERGE=1 - - eval_gettextln "Trying simple merge with \$pretty_name" - git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2 - next=$(git write-tree 2>/dev/null) - if test $? -ne 0 - then - gettextln "Simple merge did not work, trying automatic merge." - git merge-index -o git-merge-one-file -a || - OCTOPUS_FAILURE=1 - next=$(git write-tree 2>/dev/null) - fi - - MRC="$MRC $SHA1" - MRT=$next -done - -exit "$OCTOPUS_FAILURE" diff --git a/git.c b/git.c index 64a1a1de41..d51fb5d2bf 100644 --- a/git.c +++ b/git.c @@ -539,6 +539,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 9fafee5954..970ff4793d 100644 --- a/merge-strategies.c +++ b/merge-strategies.c @@ -1,5 +1,6 @@ #include "cache.h" #include "cache-tree.h" +#include "commit-reach.h" #include "dir.h" #include "lockfile.h" #include "merge-strategies.h" @@ -383,3 +384,181 @@ int merge_strategies_resolve(struct repository *r, return 0; } + +static int write_tree(struct repository *r, struct tree **reference_tree) +{ + struct object_id oid; + int ret; + + if (!(ret = write_index_as_tree(&oid, r->index, r->index_file, 0, NULL))) + *reference_tree = lookup_tree(r, &oid); + + return ret; +} + +static int octopus_fast_forward(struct repository *r, const char *branch_name, + struct tree *tree_head, struct tree *current_tree, + struct tree **reference_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 (fast_forward(r, t, 2, 0)) + return -1; + if (write_tree(r, reference_tree)) + 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 *j; + int nr = 0, ret = 0; + + printf(_("Trying simple merge with %s\n"), branch_name); + + for (j = common; j; j = j->next) { + struct tree *tree = repo_get_commit_tree(r, j->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 (fast_forward(r, t, nr, 1)) + return -1; + + if (write_tree(r, reference_tree)) { + struct lock_file lock = LOCK_INIT; + + puts(_("Simple merge did not work, trying automatic merge.")); + repo_hold_locked_index(r, &lock, LOCK_DIE_ON_ERROR); + ret = merge_all_index(r->index, 0, 0, merge_one_file_func, r); + write_locked_index(r->index, &lock, COMMIT_LOCK); + + write_tree(r, reference_tree); + } + + return ret ? -2 : 0; +} + +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, references = 1; + struct commit **reference_commit; + struct tree *reference_tree, *tree_head; + struct commit_list *i; + struct object_id head; + struct strbuf sb = STRBUF_INIT; + + get_oid(head_arg, &head); + + reference_commit = xcalloc(commit_list_count(remotes) + 1, + sizeof(struct commit *)); + reference_commit[0] = lookup_commit_reference(r, &head); + reference_tree = repo_get_commit_tree(r, reference_commit[0]); + + tree_head = repo_get_commit_tree(r, reference_commit[0]); + if (parse_tree(tree_head)) { + ret = 2; + goto out; + } + + if (repo_index_has_changes(r, reference_tree, &sb)) { + error(_("Your local changes to the following files " + "would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + ret = 2; + goto out; + } + + for (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; + int k = 0, up_to_date = 0; + + if (ret) { + /* + * We allow only last one to have a + * hand-resolvable conflicts. Last round failed + * and we still had a head to merge. + */ + puts(_("Automated merge did not work.")); + puts(_("Should not be doing an octopus.")); + + ret = 2; + goto out; + } + + branch_name = merge_get_better_branch_name(oid_to_hex(oid)); + common = get_merge_bases_many(c, references, reference_commit); + + if (!common) { + error(_("Unable to find common commit with %s"), branch_name); + + free(branch_name); + free_commit_list(common); + + ret = 2; + goto out; + } + + for (j = common; j && !(up_to_date || !ff_merge); j = j->next) { + up_to_date |= oideq(&j->item->object.oid, oid); + + if (k < references) + ff_merge &= oideq(&j->item->object.oid, &reference_commit[k++]->object.oid); + } + + if (up_to_date) { + printf(_("Already up to date with %s\n"), branch_name); + + free(branch_name); + free_commit_list(common); + continue; + } + + if (ff_merge) { + ret = octopus_fast_forward(r, branch_name, tree_head, + current_tree, &reference_tree); + references = 0; + } else { + ret = octopus_do_merge(r, branch_name, common, + current_tree, &reference_tree); + } + + free(branch_name); + free_commit_list(common); + + if (ret == -1) + goto out; + + reference_commit[references++] = c; + } + +out: + free(reference_commit); + return ret; +} diff --git a/merge-strategies.h b/merge-strategies.h index 4f996261b4..05232a5a89 100644 --- a/merge-strategies.h +++ b/merge-strategies.h @@ -36,5 +36,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 Mon Nov 16 10:21:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2BCEC4742C for ; Mon, 16 Nov 2020 11:44:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 54EEB22245 for ; Mon, 16 Nov 2020 11:44:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZYjfJuZz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729029AbgKPKXU (ORCPT ); Mon, 16 Nov 2020 05:23:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34454 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729015AbgKPKXT (ORCPT ); Mon, 16 Nov 2020 05:23:19 -0500 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC249C0613CF for ; Mon, 16 Nov 2020 02:23:18 -0800 (PST) Received: by mail-wm1-x343.google.com with SMTP id h2so23224413wmm.0 for ; Mon, 16 Nov 2020 02:23:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tVoypWL/ZqKV0FHBZEGAHK+0wCgGjtBLlOB5vMSR38A=; b=ZYjfJuZzL3xi+X2TmnaR3vhocBmH8r1sMdBMjLkE/dRP5UstmA3coO+9YrMiNMm3eI 7cT1lRMsXlj/IbVkNirXygqLSIeuCCUAnoghk8Eq2cxT3MVx+e/RkDqOEPmZ/bX4xKCQ BjUhz4CG+rAoX0nCVw7OfJuPeZ8OYUUJ1Cq0EUlVZePGIibrowKWAB5UHcM4UIIRbShh m6QVYBalJcrCo91hLqPctOj8p6ucBGsJ6BBPqOvolVaUrCjz/5jnvet+B4OH3klc/vis WIWN3pa58n+sp8czsq8hQ3hCCy3l6abmHfxcXTuuGIO/fqXZ5+SxZYtJBjHPb7dD89vO 4gnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tVoypWL/ZqKV0FHBZEGAHK+0wCgGjtBLlOB5vMSR38A=; b=BYbdTICwu65wn5qVENVMJXfvexcMjGeDR1IfTu2H/RfgvhnYEP7oV00YUTGltoYpBN O0Bdv/hdm+2bUHjkJvgpQ/dzqwCO5xqqc5/QTO1vZJq57jP3PDzD1HOv9bx7cDXUmt6W tgFKihHg+wt0VtuML+m0IdaKHUr35/rsyJ/Y2IupNWMnF9AzqZxxXe81ERmZwnv7ML1/ iHvE3DQ899Wu004TCcPa61oX5iHUymwus64C6H89PRzsCoR/tu4DrDo3aEbb6Rd3qfo1 LJrPAavnZ8EskwzcEudwQHUo1/8GVd9qcaOK2Q1FJ5MukFSgg4kBRtiqh2QruPigCBH+ LSNA== X-Gm-Message-State: AOAM530Q76giV1lxfbTpunq/IvnNBBPAfihz118fYvBxb4f05yzdcpUj WXzk1EjbCbgnSZ0tRcBdLQqyFXs1urY= X-Google-Smtp-Source: ABdhPJwqk7121zvPqgl3Xnu9AOrEFioy9oioE1cqZATduoiW1dDUNjRoJAx9dqSXbHuaemXx8UF1gA== X-Received: by 2002:a05:600c:4101:: with SMTP id j1mr14371311wmi.35.1605522197263; Mon, 16 Nov 2020 02:23:17 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:16 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 09/12] merge: use the "resolve" strategy without forking Date: Mon, 16 Nov 2020 11:21:55 +0100 Message-Id: <20201116102158.8365-10-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 9d5359edc2..3b35aa320c 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -41,6 +41,7 @@ #include "commit-reach.h" #include "wt-status.h" #include "commit-graph.h" +#include "merge-strategies.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -740,6 +741,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 Mon Nov 16 10:21:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908147 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86F06C4742C for ; Mon, 16 Nov 2020 11:37:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 207DD221F8 for ; Mon, 16 Nov 2020 11:37:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hven03TM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729169AbgKPKXW (ORCPT ); Mon, 16 Nov 2020 05:23:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34462 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729057AbgKPKXV (ORCPT ); Mon, 16 Nov 2020 05:23:21 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 15073C0613D1 for ; Mon, 16 Nov 2020 02:23:20 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id p19so11705640wmg.0 for ; Mon, 16 Nov 2020 02:23:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ffaO07lkSqT/s54SNv4krQd6SSHjCTt+XHwgCwqfNuo=; b=hven03TMJE42GlHW+/SAoQyWyagJMSLKc2HdCAauQggRDCQR9yFoEp5u+i/3Oc5WEk S9dTP+hISIjYd2ZiDRntizvhpzdjmix7xXwd4pYuw9qU1jj03qPkzjib2oLY1rHSZqUZ f1ODcXM0d4OJLN4wNfWL5vE0pME8Op5fSxcn8x/MRNPSd8NSQMVfPmH6NoInMMBlHrPo aQI+fNWE7Nv8VTS8W7BLbWpwLOWMG9YQpmqJyO84cFEv1Z0VJE2hAktw/adt/mitQGP2 zZUgt8M58RUGNLmRyNhKwTgNoA2nHm6ct00bo5xxAYO3eUor8093IAMLQ1ylJTAcYi1/ otBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ffaO07lkSqT/s54SNv4krQd6SSHjCTt+XHwgCwqfNuo=; b=bPhs+Anh4mzGu6xqwlim2U12DaslrgLwEdK7mltHbYmaierkbRfpezqZwNGLS5O4VO ToZ1MPcvoMs1O5ewRH8jYKlCIgcWhSLsqwgAL6GcxBfTABtELB8K76ayem4CLY/y2WXn OyxZZceOIVO/23JMu5IHVDvEWwodv2sLbmmZPfHl/yw0uZHamuGqY3qtPm38BmzHOHy0 2o5haub9BVi29qZImEYntOINZD5pRhqxvcgoQuSUgdOVA7SdE0oM0WdrNaVLXY1W6HPr RflLs2GxX55u6GXHoggROPgzSmfE18wuvr8RvDFgRGhZBaPiukOYCVpoxRb1eltOGH5z zQOg== X-Gm-Message-State: AOAM532zti7U+J+FDx4GnEfMarndddEZtKndz8R4pSwmB3lh0uE0NBtl hgDvAP/oMBl7C8LrudfALI2p5e5YwpA= X-Google-Smtp-Source: ABdhPJyDFsLX0KGRRjW0/PI1Ce1yZ9rRLCt3u4I0sHxlRic03bpAywR5yalXu0trJKpiqZOTmlUU0g== X-Received: by 2002:a1c:4b18:: with SMTP id y24mr15340203wma.154.1605522198434; Mon, 16 Nov 2020 02:23:18 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:17 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 10/12] merge: use the "octopus" strategy without forking Date: Mon, 16 Nov 2020 11:21:56 +0100 Message-Id: <20201116102158.8365-11-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 3b35aa320c..f3345a582a 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -744,6 +744,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, } else if (!strcmp(strategy, "resolve")) { return merge_strategies_resolve(the_repository, common, head_arg, remoteheads); + } else if (!strcmp(strategy, "octopus")) { + return merge_strategies_octopus(the_repository, common, + head_arg, remoteheads); } else { return try_merge_command(the_repository, strategy, xopts_nr, xopts, From patchwork Mon Nov 16 10:21:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908145 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB90FC4742C for ; Mon, 16 Nov 2020 11:37:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5BBA1221F8 for ; Mon, 16 Nov 2020 11:37:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Bc2z/mWp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729055AbgKPKXV (ORCPT ); Mon, 16 Nov 2020 05:23:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34464 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729015AbgKPKXV (ORCPT ); Mon, 16 Nov 2020 05:23:21 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA2D9C0613CF for ; Mon, 16 Nov 2020 02:23:20 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id 19so23201281wmf.1 for ; Mon, 16 Nov 2020 02:23:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RUfvN0pl5K/WuXCV4D53cIPGvmeqL7bcfgCSQ17fPJA=; b=Bc2z/mWpQgJo5lBlZSdRblZPTedDK6eM56aTBqJe+iEwU6+s681zg2DBuThxuMR+dg SUFcnB8RoKOoYO897IS1ADlMEJa+Q2Vtlm2ND+FTi750lJ9HIt4rxyO3PAix55P7gNMN lArgIeaMMHMPep8kb5N6IGOaVo1zvhydRVTXaC/3iHVsFS00BzwYfu9uiwvlJgMdLxgD Jmx/sX66LYMqjYXw+4jsw5wmHNHOyASm081k8JR/r0W2z53vp0pD2bo10f+plh2nLPtV OWdHIiFEkaE+uzx25vswP/L9cwXoZjENLLmPxqkp1xi6el0sq6imF8Xsu6kmX2H3LjaG 566A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RUfvN0pl5K/WuXCV4D53cIPGvmeqL7bcfgCSQ17fPJA=; b=jXHrJhnyawYe3iDtnrSmginoMWEmqarfpYuPIJZq3aWdA4I5+7YX0Saoz05rH8o5Ol NlWE0Eh/YqGSQz8/vOFgi69C5bRIWa7jg5XKJNbx4Lajy/qv+ss95tWEuPVS8Ime7L0U r8IkU0sZc7m1TI6H5JdzySro6kKxYE4ACslaSWiWbGb0bTUXcLD1EzekCeeNVCwB897P RSPc2kZdL+ae8cfvULf/+Voj0PtelzuYQS/Tl1rKUwGydqh6KSZC4fL0OenpOaZ10+Or 4Tj/+XfQBogp+Rroe6HxST+uUnL08uMcBJcCKY8OtKzSKLbbQ8NPUe+78hJntLMPkjTw 091w== X-Gm-Message-State: AOAM533m5MKMIt5xm9nPL6mPb6eztTX0vv7puOsnWyTxz1Tc7IeZq6MA W0hcvvZvXinfV3Pqg2ikEdpXFaSE81s= X-Google-Smtp-Source: ABdhPJyWwCPDbcP62b3nNZlNEwUrAeNmVAfwkyZpSyhOLgdMdu+agbb6GFs/4GIoo0j3ijWgytcarg== X-Received: by 2002:a1c:20d0:: with SMTP id g199mr15684455wmg.68.1605522199500; Mon, 16 Nov 2020 02:23:19 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:19 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 11/12] sequencer: use the "resolve" strategy without forking Date: Mon, 16 Nov 2020 11:21:57 +0100 Message-Id: <20201116102158.8365-12-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index e8676e965f..ff411d54af 100644 --- a/sequencer.c +++ b/sequencer.c @@ -33,6 +33,7 @@ #include "commit-reach.h" #include "rebase-interactive.h" #include "reset.h" +#include "merge-strategies.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -2000,9 +2001,15 @@ static int do_pick_commit(struct repository *r, commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(r, opts->strategy, - opts->xopts_nr, (const char **)opts->xopts, - common, oid_to_hex(&head), remotes); + + if (!strcmp(opts->strategy, "resolve")) { + repo_read_index(r); + res |= merge_strategies_resolve(r, common, oid_to_hex(&head), remotes); + } else + res |= try_merge_command(r, opts->strategy, + opts->xopts_nr, (const char **)opts->xopts, + common, oid_to_hex(&head), remotes); + free_commit_list(common); free_commit_list(remotes); } From patchwork Mon Nov 16 10:21:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alban Gruin X-Patchwork-Id: 11908143 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 339F6C5519F for ; Mon, 16 Nov 2020 11:37:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BA54A221F8 for ; Mon, 16 Nov 2020 11:37:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BKCyDx00" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729057AbgKPKXX (ORCPT ); Mon, 16 Nov 2020 05:23:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729015AbgKPKXW (ORCPT ); Mon, 16 Nov 2020 05:23:22 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E49EBC0613CF for ; Mon, 16 Nov 2020 02:23:21 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id a3so23080847wmb.5 for ; Mon, 16 Nov 2020 02:23:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=K9YVjZ1L8kzbu2itpBCJA99lobPJTsxMd/HON2LJPvg=; b=BKCyDx00qmTKFzlsUCmv5cpi54fG1r6m36u0ryge2PtfP2Mw+2EpwPi6PQkV3QO9Py jhal0kDXxs2Xh4lnXlyVbgd9M5AmfWGVhnWYD1dIUec0Qk9MjAKkdGAuWo1+6WmAyFfR Jshe68x7Si6XoJh92LYW497ladoaNerM1ummG+yLIZIl2gsBCDvwYMnMFydhuO3eMHGu 3nVcOq2Oj2X8a0u0u5hGbHxQugSLQhT2RAP2eAAffhzRM8NrKUUpUOWVhofTXmT9kz1r 35VWlnRK2iDBo340qV9Ns7etotX/8pVCzlIdLrJiUjY6yTL1g/mXbVLiav3DhRG+8cNl 6yNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=K9YVjZ1L8kzbu2itpBCJA99lobPJTsxMd/HON2LJPvg=; b=fZBPxGe0Mr3IoWDW8on/w190i+ih3XpdV5tCKtMMhImjXa/TFMG+66jCq+SjJbLSDC 0QGXZvMlmaz+faMDdEABAuO6WR/ZPd39ANEz4Aq0xENBmf6GOeV/CMnkb3oQ8TCMi24y qZiNQeW1b/bvuAhc8R0XrvMFpp8iCSjYFyR5jntjOCMy6hXmZlzorDa9T4G2JlQTGnEa 1E6y55jNyL1o9h90FWNjdt26aJffHf0YkGc5cIJYZ9zqTqBksredZRCuq2SqfCJ8L5q9 xSuwtmRZWO13FMACuj5rATK5EdyJYMnXp/1tugHCY6vLQ6kFkakzeiB+oNInyDh0YagH 0CuQ== X-Gm-Message-State: AOAM533rW/eOjQmVdZyh5ArzNiL6JMe/7i/aU7f5O6k/WH6awOUUeqkL 0te3f0Qacmd2M7Qv9i3OkHgrvMJV0oo= X-Google-Smtp-Source: ABdhPJyp/SBTKnCt16Mu8+WyFwvFUU2KFwXtRC//cXhCVwEjWifSIx9cksPFlmYZBXJxdWitYpPgoA== X-Received: by 2002:a05:600c:2204:: with SMTP id z4mr14068954wml.57.1605522200431; Mon, 16 Nov 2020 02:23:20 -0800 (PST) Received: from ylate.lan (atoulouse-654-1-426-233.w2-6.abo.wanadoo.fr. [2.6.209.233]) by smtp.googlemail.com with ESMTPSA id f5sm22884520wrg.32.2020.11.16.02.23.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 Nov 2020 02:23:20 -0800 (PST) From: Alban Gruin To: git@vger.kernel.org Cc: Junio C Hamano , Phillip Wood , Alban Gruin Subject: [PATCH v5 12/12] sequencer: use the "octopus" merge strategy without forking Date: Mon, 16 Nov 2020 11:21:58 +0100 Message-Id: <20201116102158.8365-13-alban.gruin@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201116102158.8365-1-alban.gruin@gmail.com> References: <20201113110428.21265-1-alban.gruin@gmail.com> <20201116102158.8365-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 ff411d54af..746afad930 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2005,6 +2005,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,