From patchwork Wed May 10 12:34:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236893 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF0F4C77B7C for ; Wed, 10 May 2023 12:34:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236673AbjEJMeL (ORCPT ); Wed, 10 May 2023 08:34:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232073AbjEJMeK (ORCPT ); Wed, 10 May 2023 08:34:10 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 215C15FCA for ; Wed, 10 May 2023 05:34:09 -0700 (PDT) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 465313200918; Wed, 10 May 2023 08:34:08 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 10 May 2023 08:34:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722047; x=1683808447; bh=s9 i+8tJEWLPvYCzjqsdGvO5pKetJqqKmSSkrV3pFZDE=; b=G0V/zmiOwh/DooCF9/ SOgYj0aMmuL5L1xb3gPe8Y8dTqdIVeXBeqz1mq6Jxg+osKNoYjwAtpnGDq87zeMj 0VlW/uJ47PEEZ9UBp1iHHNB7FnoIxGemWpPIWZzpTePMBm3S0LT/uk9YgbJtEQbI sXXXMqidNzsbiGlOKnqca/i0cHLlk0UXcEydW83v5qdK5GcIAR29dzmsfXcwoI3U xt4HXuSt3NbzDn4IN6gtDkDBxaB1by1f1kgl15NiHwEcgQtvCMlMi8YX2VEI8W2y P4IhzpytMehF8y97UIEcQeDf5tbhKWZdVCz5SSvSMj6UHCon80VgR/J8e8OnJF3Z 5Fww== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722047; x=1683808447; bh=s9i+8tJEWLPvY CzjqsdGvO5pKetJqqKmSSkrV3pFZDE=; b=fCIItgaxp1XpLfwPFbcLA7d6YKG5j Ea9Iuj4wpfngZ/NDJthHxJV2dxIp23zLVBUXp0DskuFxFpytwPkEnpCR1NU2wl1P C87dA+wAEKQA3HruQ6mhO7Dyzpr8daPAZ+KX3w2/N597AXThAbHpU6HajYN4mKZ0 K7sGqnDjA/sTyzdZ9mxgfzON9N3RTB/hINwPPKjxJIVMlYQFHwJrACAkME5fLIIm OSgZLCVayrsrbkDzTZ8TK3ra8urKCzu+ppyY0ArU421lXvqRmpAw5a2Du88cbVDF YEz8cFa8GqUG7kyTUVDXAzLUxEHUZYhoG80gMs3IC/id1SWUuDpoXqiKQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:06 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id dd42e52d (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:33:55 +0000 (UTC) Date: Wed, 10 May 2023 14:34:02 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 1/9] fetch: fix `--no-recurse-submodules` with multi-remote fetches Message-ID: <02ee4fab7e8b46bb04b1e7509bd752144ac77a12.1683721293.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When running `git fetch --no-recurse-submodules`, the exectation is that we don't fetch any submodules. And while this works for fetches of a single remote, it doesn't when fetching multiple remotes at once. The result is that we do recurse into submodules even though the user has explicitly asked us not to. This is because while we pass on `--recurse-submodules={yes,on-demand}` if specified by the user, we don't pass on `--no-recurse-submodules` to the subprocess spawned to perform the submodule fetch. Fix this by also forwarding this flag as expected. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 2 ++ t/t5526-fetch-submodules.sh | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/builtin/fetch.c b/builtin/fetch.c index c310d89878..08d7fc7233 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1876,6 +1876,8 @@ static void add_options_to_argv(struct strvec *argv) strvec_push(argv, "--keep"); if (recurse_submodules == RECURSE_SUBMODULES_ON) strvec_push(argv, "--recurse-submodules"); + else if (recurse_submodules == RECURSE_SUBMODULES_OFF) + strvec_push(argv, "--no-recurse-submodules"); else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) strvec_push(argv, "--recurse-submodules=on-demand"); if (tags == TAGS_SET) diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index dcdbe26a08..26e933f93a 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -1180,4 +1180,17 @@ test_expect_success 'fetch --all with --recurse-submodules with multiple' ' test_line_count = 2 fetch-subs ' +test_expect_success "fetch --all with --no-recurse-submodules only fetches superproject" ' + test_when_finished "rm -rf src_clone" && + + git clone --recurse-submodules src src_clone && + ( + cd src_clone && + git remote add secondary ../src && + git config submodule.recurse true && + git fetch --all --no-recurse-submodules 2>../fetch-log + ) && + ! grep "Fetching submodule" fetch-log +' + test_done From patchwork Wed May 10 12:34:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236895 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17431C77B7D for ; Wed, 10 May 2023 12:34:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237039AbjEJMeS (ORCPT ); Wed, 10 May 2023 08:34:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236872AbjEJMeO (ORCPT ); Wed, 10 May 2023 08:34:14 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 479FB49F7 for ; Wed, 10 May 2023 05:34:12 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id 0BE8F3200923; Wed, 10 May 2023 08:34:10 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Wed, 10 May 2023 08:34:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722050; x=1683808450; bh=Y/ nTWdHaeOZn32LkJID0vMBG4wBA9Dw8lYxaivc2sIc=; b=cnN2hNxPt/+fV+X9M7 jKxFfQ/DpmsW1SZvahJBOi0qX0LQBY/UQd3D97LGkG/jCUvY5ARn601OMbNLFJoy drUjS3R8Mb7+7Ofg0l4KgWJXcqVbV+2Tx6K1XtXPUd7fmGvf6aWHs08XzCx0cvaD kCLlneH5W6tzgSLjZUd8jRn1veW+QyYMq7ePe7hS6aVSZIZGKWdy9R6g8EOHD8ri JoCAY7bgv3/E7BsLUUJ7iLW7icuaDO1ccmSVKmOhGSau00cWevUj0jMJTrV3p+rv u4xmW1MA+hxYk8Xsm7b0uzcS2zW06dzTCYCYVj/ucFOY5luFdOOKrxh5o3ZNdfW1 i3hA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722050; x=1683808450; bh=Y/nTWdHaeOZn3 2LkJID0vMBG4wBA9Dw8lYxaivc2sIc=; b=WanYK1AnYSQderUr4Egl0IfDXZmbR eFel8rawQk1hBZUZl7oPW7wc2EvBZwQkANuH9RalIEHzKCvfppOSIrvw3ANoZag2 pRGYcV7QnfBhw2oNprlOnjNpGdvk0wtMnjZXCQoXqHevA76QhfI/0/SDwqYs6C/9 BTbFFOUUV0pU6J5sCs4oGsbbETYar+O+i6QHfHNuIsZd5oSG5gpLNPniE1IRzySk gdiWHBERib6h7YGWWz2S5Gs8SFdK4wFCz8pyypIY0A9yIbgpaWTbJkMNh/M2SekL qAX4+DlIj1lOpvFMtII0Da9e9TmVT+uR5fU5OSEst6ZlEqKIzFmdVljAw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:09 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id a5d53335 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:33:59 +0000 (UTC) Date: Wed, 10 May 2023 14:34:07 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 2/9] fetch: split out tests for output format Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We're about to introduce a new porcelain mode for the output of git-fetch(1). As part of that we'll be introducing a set of new tests that only relate to the output of this command. Split out tests that exercise the output format of git-fetch(1) so that it becomes easier to verify this functionality as a standalone unit. As the tests assume that the default branch is called "main" we set up the corresponding GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME environment variable accordingly. Signed-off-by: Patrick Steinhardt --- t/t5510-fetch.sh | 53 ---------------------------------- t/t5574-fetch-output.sh | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 53 deletions(-) create mode 100755 t/t5574-fetch-output.sh diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index dc44da9c79..4f289063ce 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -1118,59 +1118,6 @@ test_expect_success 'fetching with auto-gc does not lock up' ' ) ' -test_expect_success 'fetch aligned output' ' - git clone . full-output && - test_commit looooooooooooong-tag && - ( - cd full-output && - git -c fetch.output=full fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && - cat >expect <<-\EOF && - main -> origin/main - looooooooooooong-tag -> looooooooooooong-tag - EOF - test_cmp expect actual -' - -test_expect_success 'fetch compact output' ' - git clone . compact && - test_commit extraaa && - ( - cd compact && - git -c fetch.output=compact fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && - cat >expect <<-\EOF && - main -> origin/* - extraaa -> * - EOF - test_cmp expect actual -' - -test_expect_success '--no-show-forced-updates' ' - mkdir forced-updates && - ( - cd forced-updates && - git init && - test_commit 1 && - test_commit 2 - ) && - git clone forced-updates forced-update-clone && - git clone forced-updates no-forced-update-clone && - git -C forced-updates reset --hard HEAD~1 && - ( - cd forced-update-clone && - git fetch --show-forced-updates origin 2>output && - test_i18ngrep "(forced update)" output - ) && - ( - cd no-forced-update-clone && - git fetch --no-show-forced-updates origin 2>output && - test_i18ngrep ! "(forced update)" output - ) -' - for section in fetch transfer do test_expect_success "$section.hideRefs affects connectivity check" ' diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh new file mode 100755 index 0000000000..f91b654d38 --- /dev/null +++ b/t/t5574-fetch-output.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +test_description='git fetch output format' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +test_expect_success 'fetch aligned output' ' + git clone . full-output && + test_commit looooooooooooong-tag && + ( + cd full-output && + git -c fetch.output=full fetch origin >actual 2>&1 && + grep -e "->" actual | cut -c 22- >../actual + ) && + cat >expect <<-\EOF && + main -> origin/main + looooooooooooong-tag -> looooooooooooong-tag + EOF + test_cmp expect actual +' + +test_expect_success 'fetch compact output' ' + git clone . compact && + test_commit extraaa && + ( + cd compact && + git -c fetch.output=compact fetch origin >actual 2>&1 && + grep -e "->" actual | cut -c 22- >../actual + ) && + cat >expect <<-\EOF && + main -> origin/* + extraaa -> * + EOF + test_cmp expect actual +' + +test_expect_success '--no-show-forced-updates' ' + mkdir forced-updates && + ( + cd forced-updates && + git init && + test_commit 1 && + test_commit 2 + ) && + git clone forced-updates forced-update-clone && + git clone forced-updates no-forced-update-clone && + git -C forced-updates reset --hard HEAD~1 && + ( + cd forced-update-clone && + git fetch --show-forced-updates origin 2>output && + test_i18ngrep "(forced update)" output + ) && + ( + cd no-forced-update-clone && + git fetch --no-show-forced-updates origin 2>output && + test_i18ngrep ! "(forced update)" output + ) +' + +test_done From patchwork Wed May 10 12:34:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236896 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1C003C77B7D for ; Wed, 10 May 2023 12:34:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236931AbjEJMe1 (ORCPT ); Wed, 10 May 2023 08:34:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237037AbjEJMeR (ORCPT ); Wed, 10 May 2023 08:34:17 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85F0D8A7D for ; Wed, 10 May 2023 05:34:15 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id A32053200918; Wed, 10 May 2023 08:34:14 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute1.internal (MEProxy); Wed, 10 May 2023 08:34:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722054; x=1683808454; bh=LG o9vVT1L7kR3aHZ6e9SNBL392g2PWuQlN2grdCeRnc=; b=aRVS+S5PKXAQE2+2l8 dGo7o55d44IYT/rbpO3etQEX0NgVJV20hLTatw/KZv6ilSnZCjRvEo75TudYvhjD QzyEK47RwPEnN0vkwxrfINRgqKT4DT5DMXLzETeCr/59e9o61uAXCykQL9/DV2IB F26zn30GDvtKwwSd1KpstGJUFAE+S0IDj0zbxbGHj6lZrOqpJ91y/6S+Zk30NxtP kYYhxRiuFhbpqTPmM7QrtdQLspsfE3+iU69Q9RY8l6OAOfSM4avvmNUb7IGO4hxZ a5sibI8YLPz5b8CSazEu9mG08COkAdGZR3sux3bog/12BS2serZN4dmlmsoFbdEg J9lQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722054; x=1683808454; bh=LGo9vVT1L7kR3 aHZ6e9SNBL392g2PWuQlN2grdCeRnc=; b=csnQWbnin0yKGANCL50rseB4BO3TF 4Aa/cwAOep7CXCIqeURptY5Ucw4+9oppbtRSFyAr1uzaYnvcS/LgEMEu9cAGqeej mFcXOyvySh1vVgBaq84czxzNDGQNbJCejpWSOKmXFhAfz3/b3bP5xL3Vw2Gcqoq8 mQnBUyChOLT2tA6VGaVxDNf9wm/gmHKjFSiE7FtfYVUtvqVyl7Io78GJ97yxa/B+ TD5tHkNU+Y55zA1wPwANPJ0UjumJrqmpude4UyM7TOXwhFAECzwmOyOMrC0N4VOO gXPZmV+cRA92M9j78Y9OPpAccODXAufKUkjavOMUcGlpcYm7B/LdB98eg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:12 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id b49b9302 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:03 +0000 (UTC) Date: Wed, 10 May 2023 14:34:11 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 3/9] fetch: add a test to exercise invalid output formats Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Add a testcase that exercises the logic when an invalid output format is passed via the `fetch.output` configuration. Signed-off-by: Patrick Steinhardt --- t/t5574-fetch-output.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index f91b654d38..8a344e6790 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -7,6 +7,30 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +test_expect_success 'fetch with invalid output format configuration' ' + test_when_finished "rm -rf clone" && + git clone . clone && + + test_must_fail git -C clone -c fetch.output fetch origin 2>actual.err && + cat >expect <<-EOF && + error: missing value for ${SQ}fetch.output${SQ} + fatal: unable to parse ${SQ}fetch.output${SQ} from command-line config + EOF + test_cmp expect actual.err && + + test_must_fail git -C clone -c fetch.output= fetch origin 2>actual.err && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ} + EOF + test_cmp expect actual.err && + + test_must_fail git -C clone -c fetch.output=garbage fetch origin 2>actual.err && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ} + EOF + test_cmp expect actual.err +' + test_expect_success 'fetch aligned output' ' git clone . full-output && test_commit looooooooooooong-tag && From patchwork Wed May 10 12:34:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236897 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 844FBC77B7C for ; Wed, 10 May 2023 12:34:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237046AbjEJMee (ORCPT ); Wed, 10 May 2023 08:34:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237031AbjEJMeZ (ORCPT ); Wed, 10 May 2023 08:34:25 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 987B693FA for ; Wed, 10 May 2023 05:34:20 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id B78433200915; Wed, 10 May 2023 08:34:19 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 10 May 2023 08:34:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722059; x=1683808459; bh=DU Aiwwap859+UC5NXuvc6xH2/ICfx5+cyJzv67YR6ck=; b=H/RY8nuf1tvNWQaqG2 ZjPZ7mu0FumOQMXY832zxyZ66FW7bw+zluK4Zou//C9Z3Uh+SAy1ChSwGBUyWyss JVKiq1MFEPoU3SCeV7YhqpJM/0Jv2nOlfGNzXnGEuVaUl1iuRRmNxFI3HE/VMRHz 4M7WbyM6m+jKUKxJEztlaIKmuNB2DEHdoXy8FYyCeTfFAVsuymyVDpM8WhDKLSj2 1jQ51kj4CntM8VFMrZ9JvvtwNx0NIuov7rTt/n9vSUihZ9szZLuDyHL7D5NRiIDF MtyA47g7m3dWLyEMJvo9YVDtEYmGoOng3Ea0A9LkWjeTymQA+wyVPrDk1i0r7ub6 LAjw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722059; x=1683808459; bh=DUAiwwap859+U C5NXuvc6xH2/ICfx5+cyJzv67YR6ck=; b=Cz1mUU7P8fCjdqaZcSq5kmFg8OT/8 o38TRf3oIEPjcum8sqEclZ3blM378f6GoBYuPiti6JPHDnQwkk+TBu+LiPmjt8DZ PVtkUaSru8S+cBnaXBJ/OUwZJNKdFsqqeykPqYLU2ii4elsb03qbuMAFo/ka3fXS 74MxrJ/JUtu5ECzSx+IXecOkRuFM1r+Vrr7cpGD6bwuAOQM32P1LmE2OTwf+V3g5 2CZtnvsUrogEqGX1iJagXaQ0/GyKQuCxJkN3M/BMmUOmjBi8JLa+Mk5DqM6QowPt o3tFpKRis7cMIw3bmXUVu32c6p6Xh4gYbrrxoKVLxFzJSrLA7IzMYvXvQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepleejteffveehgeegteekteeiudeiieeigeeigedtffehgeekhfejheefkefhveel necuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:17 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 8bdd7db1 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:08 +0000 (UTC) Date: Wed, 10 May 2023 14:34:15 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 4/9] fetch: print left-hand side when fetching HEAD:foo Message-ID: <2cc7318697ef6062f6deadf7a22feb26c2c829e8.1683721293.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org `store_updated_refs()` parses the remote reference for two purposes: - It gets used as a note when writing FETCH_HEAD. - It is passed through to `display_ref_update()` to display updated references in the following format: ``` * branch master -> master ``` In most cases, the parsed remote reference is the prettified reference name and can thus be used for both cases. But if the remote reference is HEAD, the parsed remote reference becomes empty. This is intended when we write the FETCH_HEAD, where we skip writing the note in that case. But when displaying the updated references this leads to inconsistent output where the left-hand side of reference updates is missing in some cases: ``` $ git fetch origin HEAD HEAD:explicit-head :implicit-head main From https://github.com/git/git * branch HEAD -> FETCH_HEAD * [new ref] -> explicit-head * [new ref] -> implicit-head * branch main -> FETCH_HEAD ``` This behaviour has existed ever since the table-based output has been introduced for git-fetch(1) via 165f390250 (git-fetch: more terse fetch output, 2007-11-03) and was never explicitly documented either in the commit message or in any of our tests. So while it may not be a bug per se, it feels like a weird inconsistency and not like it was a concious design decision. The logic of how we compute the remote reference name that we ultimately pass to `display_ref_update()` is not easy to follow. There are three different cases here: - When the remote reference name is "HEAD" we set the remote reference name to the empty string. This is the case that causes the left-hand side to go missing, where we would indeed want to print "HEAD" instead of the empty string. This is what `prettify_refname()` would return. - When the remote reference name has a well-known prefix then we strip this prefix. This matches what `prettify_refname()` does. - Otherwise, we keep the fully qualified reference name. This also matches what `prettify_refname()` does. As the return value of `prettify_refname()` would do the correct thing for us in all three cases, we can thus fix the inconsistency by passing through the full remote reference name to `display_ref_update()`, which learns to call `prettify_refname()`. At the same time, this also simplifies the code a bit. Note that this patch also changes formatting of the block that computes the "kind" (which is the category like "branch" or "tag") and "what" (which is the prettified reference name like "master" or "v1.0") variables. This is done on purpose so that it is part of the diff, hopefully making the change easier to comprehend. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 37 ++++++++++++++++---------------- t/t5574-fetch-output.sh | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 08d7fc7233..6aecf549e8 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -918,12 +918,14 @@ static void display_ref_update(struct display_state *display_state, char code, } width = (summary_width + strlen(summary) - gettext_width(summary)); + remote = prettify_refname(remote); + local = prettify_refname(local); strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary); if (!display_state->compact_format) - print_remote_to_local(display_state, remote, prettify_refname(local)); + print_remote_to_local(display_state, remote, local); else - print_compact(display_state, remote, prettify_refname(local)); + print_compact(display_state, remote, local); if (error) strbuf_addf(&display_state->buf, " (%s)", error); strbuf_addch(&display_state->buf, '\n'); @@ -934,7 +936,7 @@ static void display_ref_update(struct display_state *display_state, char code, static int update_local_ref(struct ref *ref, struct ref_transaction *transaction, struct display_state *display_state, - const char *remote, const struct ref *remote_ref, + const struct ref *remote_ref, int summary_width) { struct commit *current = NULL, *updated; @@ -946,7 +948,7 @@ static int update_local_ref(struct ref *ref, if (oideq(&ref->old_oid, &ref->new_oid)) { if (verbosity > 0) display_ref_update(display_state, '=', _("[up to date]"), NULL, - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return 0; } @@ -959,7 +961,7 @@ static int update_local_ref(struct ref *ref, */ display_ref_update(display_state, '!', _("[rejected]"), _("can't fetch into checked-out branch"), - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return 1; } @@ -970,12 +972,12 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("updating tag", ref, transaction, 0); display_ref_update(display_state, r ? '!' : 't', _("[tag update]"), r ? _("unable to update local ref") : NULL, - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return r; } else { display_ref_update(display_state, '!', _("[rejected]"), _("would clobber existing tag"), - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return 1; } } @@ -1008,7 +1010,7 @@ static int update_local_ref(struct ref *ref, r = s_update_ref(msg, ref, transaction, 0); display_ref_update(display_state, r ? '!' : '*', what, r ? _("unable to update local ref") : NULL, - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return r; } @@ -1030,7 +1032,7 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("fast-forward", ref, transaction, 1); display_ref_update(display_state, r ? '!' : ' ', quickref.buf, r ? _("unable to update local ref") : NULL, - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); strbuf_release(&quickref); return r; } else if (force || ref->force) { @@ -1042,12 +1044,12 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("forced-update", ref, transaction, 1); display_ref_update(display_state, r ? '!' : '+', quickref.buf, r ? _("unable to update local ref") : _("forced update"), - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); strbuf_release(&quickref); return r; } else { display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"), - remote, ref->name, summary_width); + remote_ref->name, ref->name, summary_width); return 1; } } @@ -1252,14 +1254,13 @@ static int store_updated_refs(struct display_state *display_state, if (!strcmp(rm->name, "HEAD")) { kind = ""; what = ""; - } - else if (skip_prefix(rm->name, "refs/heads/", &what)) + } else if (skip_prefix(rm->name, "refs/heads/", &what)) { kind = "branch"; - else if (skip_prefix(rm->name, "refs/tags/", &what)) + } else if (skip_prefix(rm->name, "refs/tags/", &what)) { kind = "tag"; - else if (skip_prefix(rm->name, "refs/remotes/", &what)) + } else if (skip_prefix(rm->name, "refs/remotes/", &what)) { kind = "remote-tracking branch"; - else { + } else { kind = ""; what = rm->name; } @@ -1277,7 +1278,7 @@ static int store_updated_refs(struct display_state *display_state, display_state->url_len); if (ref) { - rc |= update_local_ref(ref, transaction, display_state, what, + rc |= update_local_ref(ref, transaction, display_state, rm, summary_width); free(ref); } else if (write_fetch_head || dry_run) { @@ -1288,7 +1289,7 @@ static int store_updated_refs(struct display_state *display_state, */ display_ref_update(display_state, '*', *kind ? kind : "branch", NULL, - *what ? what : "HEAD", + rm->name, "FETCH_HEAD", summary_width); } } diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index 8a344e6790..9890f6f381 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -61,6 +61,53 @@ test_expect_success 'fetch compact output' ' test_cmp expect actual ' +test_expect_success 'fetch output with HEAD' ' + test_when_finished "rm -rf head" && + git clone . head && + + git -C head fetch --dry-run origin HEAD >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * branch HEAD -> FETCH_HEAD + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch origin HEAD >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch --dry-run origin HEAD:foo >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * [new ref] HEAD -> foo + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch origin HEAD:foo >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err +' + +test_expect_success 'fetch output with object ID' ' + test_when_finished "rm -rf object-id" && + git clone . object-id && + commit=$(git rev-parse HEAD) && + + git -C object-id fetch --dry-run origin $commit:object-id >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * [new ref] $commit -> object-id + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C object-id fetch origin $commit:object-id >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err +' + test_expect_success '--no-show-forced-updates' ' mkdir forced-updates && ( From patchwork Wed May 10 12:34:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236898 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79BC8C77B7D for ; Wed, 10 May 2023 12:34:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230047AbjEJMeq (ORCPT ); Wed, 10 May 2023 08:34:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237060AbjEJMe0 (ORCPT ); Wed, 10 May 2023 08:34:26 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BAB108A4E for ; Wed, 10 May 2023 05:34:24 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id C672D3200915; Wed, 10 May 2023 08:34:23 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Wed, 10 May 2023 08:34:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722063; x=1683808463; bh=Dx CeDltvomwgZbHYs52cwbIp5g1uLJ+5uTUy9mNg5Vw=; b=ibHrgPYKGLj9odPaY7 HGiJNSLbdnKJBKR10dre5H6sGQzcmowp6vN3P3tFF7IafR1OY9PVqmUDpqLPAC7q TK8grpO4j/2yi3aTjXOY9CJN8KNrJlVoe8wWYL858ehE9TcTcKt7oaHcbKsRIRSH R1plLsVOn4pqSgbmVGOEvrTcWz9cUaOQW9nIw4VpnvXZKjAbD8eeb0GzEIaaAq1p fjv+v4b1TbF/OG+yqgAcT2ecAStxn7/vykZ7SqD7pEsdXjs6yH5bRMj+tU8jNUJ5 Bw6X8/Ya75rJbdy983cX9yoCaT734U24TIIwM5yNazHQp7haJa3BzfKUljouTe3S D/zA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722063; x=1683808463; bh=DxCeDltvomwgZ bHYs52cwbIp5g1uLJ+5uTUy9mNg5Vw=; b=Pvz/CZbKR190wcOcBAcl0v7ABuhOY UulI1ls9DAjIVg9SCKzyXBzmfx+CdTibTtAmzXuL4TEfk7bb6+fibK0l5S/+RpCt M3k2/kNL97Nbb/HE5L2He0/3z6wg32ivi/sHQsln0vVdYA+i414/yvh6ZwJ2nhdn D04x9OrrImFcXU8mIODryP2qXuTFAl5GTbPOLWTxWFsPurc8CgRaB2EN468eqnHd qQe3k4y4fTuFGxIp1aE/z2vNBZxVL78ggBdmYLGlvJr36l4tMd27AXb0sht9y+6G tbrDKfwsMAhp8h5hQMHqqNt7T6nipvzZWP58YRahuJNQWKSiZnbYhSZ2Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:21 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 0f359f38 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:12 +0000 (UTC) Date: Wed, 10 May 2023 14:34:20 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 5/9] fetch: refactor calculation of the display table width Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When displaying reference updates, we try to print the references in a neat table. As the table's width is determined its contents we thus need to precalculate the overall width before we can start printing updated references. The calculation is driven by `display_state_init()`, which invokes `refcol_width()` for every reference that is to be printed. This split is somewhat confusing. For one, we filter references that shall be attributed to the overall width in both places. And second, we needlessly recalculate the maximum line length based on the terminal columns and display format for every reference. Refactor the code so that the complete width calculations are neatly contained in `refcol_width()`. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 81 ++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 6aecf549e8..007eb3693d 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -751,40 +751,51 @@ static int s_update_ref(const char *action, return ret; } -static int refcol_width(const struct ref *ref, int compact_format) +static int refcol_width(const struct ref *ref_map, int compact_format) { - int max, rlen, llen, len; + const struct ref *ref; + int max, width = 10; - /* uptodate lines are only shown on high verbosity level */ - if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid)) - return 0; - - max = term_columns(); - rlen = utf8_strwidth(prettify_refname(ref->name)); - - llen = utf8_strwidth(prettify_refname(ref->peer_ref->name)); - - /* - * rough estimation to see if the output line is too long and - * should not be counted (we can't do precise calculation - * anyway because we don't know if the error explanation part - * will be printed in update_local_ref) - */ - if (compact_format) { - llen = 0; + max = term_columns(); + if (compact_format) max = max * 2 / 3; - } - len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen; - if (len >= max) - return 0; - return rlen; + for (ref = ref_map; ref; ref = ref->next) { + int rlen, llen = 0, len; + + if (ref->status == REF_STATUS_REJECT_SHALLOW || + !ref->peer_ref || + !strcmp(ref->name, "HEAD")) + continue; + + /* uptodate lines are only shown on high verbosity level */ + if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid)) + continue; + + rlen = utf8_strwidth(prettify_refname(ref->name)); + if (!compact_format) + llen = utf8_strwidth(prettify_refname(ref->peer_ref->name)); + + /* + * rough estimation to see if the output line is too long and + * should not be counted (we can't do precise calculation + * anyway because we don't know if the error explanation part + * will be printed in update_local_ref) + */ + len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen; + if (len >= max) + continue; + + if (width < rlen) + width = rlen; + } + + return width; } static void display_state_init(struct display_state *display_state, struct ref *ref_map, const char *raw_url) { - struct ref *rm; const char *format = "full"; int i; @@ -816,25 +827,7 @@ static void display_state_init(struct display_state *display_state, struct ref * die(_("invalid value for '%s': '%s'"), "fetch.output", format); - display_state->refcol_width = 10; - for (rm = ref_map; rm; rm = rm->next) { - int width; - - if (rm->status == REF_STATUS_REJECT_SHALLOW || - !rm->peer_ref || - !strcmp(rm->name, "HEAD")) - continue; - - width = refcol_width(rm, display_state->compact_format); - - /* - * Not precise calculation for compact mode because '*' can - * appear on the left hand side of '->' and shrink the column - * back. - */ - if (display_state->refcol_width < width) - display_state->refcol_width = width; - } + display_state->refcol_width = refcol_width(ref_map, display_state->compact_format); } static void display_state_release(struct display_state *display_state) From patchwork Wed May 10 12:34:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236899 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A89C3C77B7C for ; Wed, 10 May 2023 12:34:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237029AbjEJMer (ORCPT ); Wed, 10 May 2023 08:34:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36318 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237043AbjEJMe3 (ORCPT ); Wed, 10 May 2023 08:34:29 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7677F7AB9 for ; Wed, 10 May 2023 05:34:28 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 817B2320039A; Wed, 10 May 2023 08:34:27 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 10 May 2023 08:34:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722067; x=1683808467; bh=Vp z5Y4bjPeocNmWGjzLdVoplGoy421Oxi8GJP9YHdtc=; b=Tr9UCV1e8oPtR0Qw1Q lWD5i/Ga3U3Ah9T6VCL5tVgZ26RJRvDaxlOPXB9HE4T9GLzwmD4hoXIg3LwJUWQd F1/XeZN280pbqj3PtMGytrMOnOXc0PqC4b7uI25jqjV8lbT7Apizk38Whr/oQcIz ig4EjCCIYnT4h1PrpKb5/scPy6cf+Ik8mhTpigjYyLchluCLQ5/Z2USQJW1RzLWG fiX9f1/2wA3TPL477Xen6sgt+LSxpU8ycnHuJOQJyBG8wxL9EDNAiG470id4vk3f sz86Gt/a8zEkL/PJXsJ3YTG/OOLAOTI2EQa8iVnJOucACGyFrCQDMr4ut15HB0pd VDWg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722067; x=1683808467; bh=Vpz5Y4bjPeocN mWGjzLdVoplGoy421Oxi8GJP9YHdtc=; b=FFphgwf+x5134niOExcEQBBa+Mows Cus+g7wSq6SY1x3fsgJC/uigkufYTC8VSdVs4ApilGd5s63OQiNTC+3bs4fACrAX ht7Uy6klW2SM7SmNlZfz5XwY2Fqy+9FP4xpucuDdsrgJUc4KTS6idUVyNGxP15hp 6eAA/G4fKAMICFObJaFNxHvO3IPl8JzZ4RgAWkXRBuGFElM44/8DFXeWUMadstIH oLRKUyRnDonLvj91O85/KSG/z7dJTPsl20DU+iXjLsSahyTzRS5Vp4HtlWudbb9C XpgJ1rvva8sKZwqDpzCmeh/oxbVHUaWSJDrC6UgH1buPMAt4L4TZHdr+Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:25 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id d9d52796 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:16 +0000 (UTC) Date: Wed, 10 May 2023 14:34:24 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 6/9] fetch: introduce `display_format` enum Message-ID: <3cac552f5ff85f84f986de02bbafa7e4ea0be848.1683721293.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We currently have two different display formats in git-fetch(1) with the "full" and "compact" formats. This is tracked with a boolean value that simply denotes whether the display format is supposed to be compacted or not. This works reasonably well while there are only two formats, but we're about to introduce another format that will make this a bit more awkward to use. Introduce a `enum display_format` that is more readily extensible. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 69 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 007eb3693d..4c58ee503a 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -48,11 +48,17 @@ enum { TAGS_SET = 2 }; +enum display_format { + DISPLAY_FORMAT_UNKNOWN = 0, + DISPLAY_FORMAT_FULL, + DISPLAY_FORMAT_COMPACT, +}; + struct display_state { struct strbuf buf; int refcol_width; - int compact_format; + enum display_format format; char *url; int url_len, shown_url; @@ -820,14 +826,22 @@ static void display_state_init(struct display_state *display_state, struct ref * git_config_get_string_tmp("fetch.output", &format); if (!strcasecmp(format, "full")) - display_state->compact_format = 0; + display_state->format = DISPLAY_FORMAT_FULL; else if (!strcasecmp(format, "compact")) - display_state->compact_format = 1; + display_state->format = DISPLAY_FORMAT_COMPACT; else die(_("invalid value for '%s': '%s'"), "fetch.output", format); - display_state->refcol_width = refcol_width(ref_map, display_state->compact_format); + switch (display_state->format) { + case DISPLAY_FORMAT_FULL: + case DISPLAY_FORMAT_COMPACT: + display_state->refcol_width = refcol_width(ref_map, + display_state->format == DISPLAY_FORMAT_COMPACT); + break; + default: + BUG("unexpected display format %d", display_state->format); + } } static void display_state_release(struct display_state *display_state) @@ -897,30 +911,41 @@ static void display_ref_update(struct display_state *display_state, char code, const char *remote, const char *local, int summary_width) { - int width; - if (verbosity < 0) return; strbuf_reset(&display_state->buf); - if (!display_state->shown_url) { - strbuf_addf(&display_state->buf, _("From %.*s\n"), - display_state->url_len, display_state->url); - display_state->shown_url = 1; + switch (display_state->format) { + case DISPLAY_FORMAT_FULL: + case DISPLAY_FORMAT_COMPACT: { + int width; + + if (!display_state->shown_url) { + strbuf_addf(&display_state->buf, _("From %.*s\n"), + display_state->url_len, display_state->url); + display_state->shown_url = 1; + } + + width = (summary_width + strlen(summary) - gettext_width(summary)); + remote = prettify_refname(remote); + local = prettify_refname(local); + + strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary); + + if (display_state->format != DISPLAY_FORMAT_COMPACT) + print_remote_to_local(display_state, remote, local); + else + print_compact(display_state, remote, local); + + if (error) + strbuf_addf(&display_state->buf, " (%s)", error); + + break; } - - width = (summary_width + strlen(summary) - gettext_width(summary)); - remote = prettify_refname(remote); - local = prettify_refname(local); - - strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary); - if (!display_state->compact_format) - print_remote_to_local(display_state, remote, local); - else - print_compact(display_state, remote, local); - if (error) - strbuf_addf(&display_state->buf, " (%s)", error); + default: + BUG("unexpected display format %d", display_state->format); + }; strbuf_addch(&display_state->buf, '\n'); fputs(display_state->buf.buf, stderr); From patchwork Wed May 10 12:34:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236900 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 184E2C7EE23 for ; Wed, 10 May 2023 12:34:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237042AbjEJMes (ORCPT ); Wed, 10 May 2023 08:34:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237068AbjEJMek (ORCPT ); Wed, 10 May 2023 08:34:40 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 172FF83F1 for ; Wed, 10 May 2023 05:34:33 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 34C973200915; Wed, 10 May 2023 08:34:32 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Wed, 10 May 2023 08:34:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722071; x=1683808471; bh=Lq vKaXXSjS+TBnj8gSPxfC+VLjGy811a+k9Lf2eHT7Y=; b=kMM5qVRu7pWQpUYjZW 5cF/Dzip0thX4qTOUvbNjhKY04mp9oOsmiqhFr4+xeww88hO7UQ7u2xaFnbdu0f7 yxflVsnMKMZtbwd6jkmvSoa9KmYiU80jX7PF73POMTMGR0UFXjssGbRDhb4cwbZZ EWduxl7zDKJeI6ZV525fBks9GtTrUL6WIQRmvC/9jXX5BcU5+Vv2+D0ibOIyf2ND WftmB86+jsCLTEP7Y2N281QwKRo/sh4IbGrj/eIA6D8xgyu+SJlRZWHU2KsMFmAZ JypiPtjrd+8nos/DOpU3ydzqPOWsBu24Qqpgn2cr/NvFTQSlYmQIIHuQP37jWtVS Gh7A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722071; x=1683808471; bh=LqvKaXXSjS+TB nj8gSPxfC+VLjGy811a+k9Lf2eHT7Y=; b=ZeDtmxhpa/MPW29fxQ0sWXlvrdw5+ VngQ54DhyUmfCC04FeWRITFXFMUsjRa4cm1DCiXrJ77tPovjF+QPle1iAI46RXeb uZJ6KhOFPSNkvY98neOdezCjvmOXx08cwVrFZnLCKtsLdce5W28ZiJAd+tnJ9QC1 pKtDmqC7wlOMCtXgr/tWieA0LS13OAECTOHUIDDgjrtupnbSIlThV5UKUoOqm5V5 bzwYMxy7yM7o4MImUNekZaKre6VFow86D/2GylN9n2uqHCfX++Cq2cw3f3WaOhGj RWUHeNZNXyAruMKLm3RU5V6dUoAqw4Fdxxq9Nex6Xy0GTVgQZwXGAA/7Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:30 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 6686fe17 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:20 +0000 (UTC) Date: Wed, 10 May 2023 14:34:28 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 7/9] fetch: lift up parsing of "fetch.output" config variable Message-ID: <0c3dbcd09fb5e064601dc3fd9ac650cb496371e5.1683721293.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Parsing the display format happens inside of `display_state_init()`. As we only need to check for a simple config entry, this is a natural location to put this code as it means that display-state logic is neatly contained in a single location. We're about to introduce a new "porcelain" output format though that is intended to be parseable by machines, for example inside of a script. This format can be enabled by passing the `--porcelain` switch to git-fetch(1). As a consequence, we'll have to add a second callsite that influences the output format, which will become awkward to handle. Refactor the code such that callers are expected to pass the display format that is to be used into `display_state_init()`. This allows us to lift up the code into the main function, where we can then hook it into command line options parser in a follow-up commit. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 50 +++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 4c58ee503a..439d3c667b 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -104,8 +104,14 @@ static int fetch_write_commit_graph = -1; static int stdin_refspecs = 0; static int negotiate_only; +struct fetch_config { + enum display_format display_format; +}; + static int git_fetch_config(const char *k, const char *v, void *cb) { + struct fetch_config *fetch_config = cb; + if (!strcmp(k, "fetch.prune")) { fetch_prune_config = git_config_bool(k, v); return 0; @@ -144,6 +150,18 @@ static int git_fetch_config(const char *k, const char *v, void *cb) return 0; } + if (!strcmp(k, "fetch.output")) { + if (!v) + return config_error_nonbool(k); + else if (!strcasecmp(v, "full")) + fetch_config->display_format = DISPLAY_FORMAT_FULL; + else if (!strcasecmp(v, "compact")) + fetch_config->display_format = DISPLAY_FORMAT_COMPACT; + else + die(_("invalid value for '%s': '%s'"), + "fetch.output", v); + } + return git_default_config(k, v, cb); } @@ -800,14 +818,13 @@ static int refcol_width(const struct ref *ref_map, int compact_format) } static void display_state_init(struct display_state *display_state, struct ref *ref_map, - const char *raw_url) + const char *raw_url, enum display_format format) { - const char *format = "full"; int i; memset(display_state, 0, sizeof(*display_state)); - strbuf_init(&display_state->buf, 0); + display_state->format = format; if (raw_url) display_state->url = transport_anonymize_url(raw_url); @@ -824,15 +841,6 @@ static void display_state_init(struct display_state *display_state, struct ref * if (verbosity < 0) return; - git_config_get_string_tmp("fetch.output", &format); - if (!strcasecmp(format, "full")) - display_state->format = DISPLAY_FORMAT_FULL; - else if (!strcasecmp(format, "compact")) - display_state->format = DISPLAY_FORMAT_COMPACT; - else - die(_("invalid value for '%s': '%s'"), - "fetch.output", format); - switch (display_state->format) { case DISPLAY_FORMAT_FULL: case DISPLAY_FORMAT_COMPACT: @@ -1605,7 +1613,8 @@ static int backfill_tags(struct display_state *display_state, } static int do_fetch(struct transport *transport, - struct refspec *rs) + struct refspec *rs, + enum display_format display_format) { struct ref_transaction *transaction = NULL; struct ref *ref_map = NULL; @@ -1691,7 +1700,7 @@ static int do_fetch(struct transport *transport, if (retcode) goto cleanup; - display_state_init(&display_state, ref_map, transport->url); + display_state_init(&display_state, ref_map, transport->url, display_format); if (atomic_fetch) { transaction = ref_transaction_begin(&err); @@ -2069,7 +2078,8 @@ static inline void fetch_one_setup_partial(struct remote *remote) } static int fetch_one(struct remote *remote, int argc, const char **argv, - int prune_tags_ok, int use_stdin_refspecs) + int prune_tags_ok, int use_stdin_refspecs, + enum display_format display_format) { struct refspec rs = REFSPEC_INIT_FETCH; int i; @@ -2136,7 +2146,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack_atexit); sigchain_push(SIGPIPE, SIG_IGN); - exit_code = do_fetch(gtransport, &rs); + exit_code = do_fetch(gtransport, &rs, display_format); sigchain_pop(SIGPIPE); refspec_clear(&rs); transport_disconnect(gtransport); @@ -2146,6 +2156,9 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int cmd_fetch(int argc, const char **argv, const char *prefix) { + struct fetch_config config = { + .display_format = DISPLAY_FORMAT_FULL, + }; int i; const char *bundle_uri; struct string_list list = STRING_LIST_INIT_DUP; @@ -2165,7 +2178,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) free(anon); } - git_config(git_fetch_config, NULL); + git_config(git_fetch_config, &config); if (the_repository->gitdir) { prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; @@ -2302,7 +2315,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } else if (remote) { if (filter_options.choice || has_promisor_remote()) fetch_one_setup_partial(remote); - result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs); + result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs, + config.display_format); } else { int max_children = max_jobs; From patchwork Wed May 10 12:34:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236901 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81473C77B7D for ; Wed, 10 May 2023 12:35:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237076AbjEJMfF (ORCPT ); Wed, 10 May 2023 08:35:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36306 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237056AbjEJMen (ORCPT ); Wed, 10 May 2023 08:34:43 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0E81DA244 for ; Wed, 10 May 2023 05:34:38 -0700 (PDT) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.west.internal (Postfix) with ESMTP id 24B653200915; Wed, 10 May 2023 08:34:37 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 10 May 2023 08:34:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722076; x=1683808476; bh=HR taDev8Y9EJ65z4JfyvF2lkaP+uzw9mKaAmzAs/Z7I=; b=fW6yE/2itylFg5r8VS Vq4bYnl3ukLjhKxqEkdzmqH2rOftOk9HS+1ls700rLlfw8RHu2JNmdkKLKGBf4+d tipZa39bA3Jre0jMej9NjKbqW5JbQkb1flpkUbsgFaur3udZ8rBjngXlk8/CiZbh 3gVhcFC7y0A60wMYzGZX7Y2nch8sJrbSzVWQm95jea0M/0AaePpfWp/6wq4/Iv8G ygesxH5R7iraRAV0R5BsvxKKa7tneDRQvkxwQXCNt87FubjO1dEjDWb9RJLnW9Ti rPT0c/rocZJJoMAmee/sKV6uRqnrXxWNfaHR1m5JHSk4QeIfMqqm9+t7Ndj+h6SE lqNw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722076; x=1683808476; bh=HRtaDev8Y9EJ6 5z4JfyvF2lkaP+uzw9mKaAmzAs/Z7I=; b=HN2yOfYM5IpXGP+vNhSIDrLZbOOOX kobWUEt0BOqRasEmCHraZ5IpEBO4dCrV8xV63ZpvcCOcoj/4DPIu5v4lGPJksAkC n93NjY05w8hqLnXMC73YjmBIiVz2rkCqOZtnpeQcyRmHjgFi6IRDmK6x1ZaY9Qi0 u7/wTQOCcxHnD9Ja81xlBLNYWv2UguKwdIEeFZ+JKU01UTnPUIPj2Vb4aUT5Bt5G Mkc49vW82ysHNd6DuYfl6gGVGcHfMHJMgAbY6hcw7ZxyBGifP8BS1FHK8l0BorQF ubwFCpgOFssGL0ENQ4OpAPzwJKNWQpfWaO2x5hGgBj0BaiS6GVkvieWKw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:35 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id e7344253 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:25 +0000 (UTC) Date: Wed, 10 May 2023 14:34:32 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 8/9] fetch: move option related variables into main function Message-ID: <8e33a08c35fd083903bfaf1e90634e690981cd4d.1683721293.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The options of git-fetch(1) which we pass to `parse_options()` are declared globally in `builtin/fetch.c`. This means we're forced to use global variables for all the options, which is more likely to cause confusion than explicitly passing state around. Refactor the code to move the options into `cmd_fetch()`. Move variables that were previously forced to be declared globally and which are only used by `cmd_fetch()` into function-local scope. Signed-off-by: Patrick Steinhardt --- builtin/fetch.c | 197 ++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 97 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 439d3c667b..7a3d620c4c 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -75,13 +75,12 @@ static int fetch_prune_tags_config = -1; /* unspecified */ static int prune_tags = -1; /* unspecified */ #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */ -static int all, append, dry_run, force, keep, multiple, update_head_ok; +static int append, dry_run, force, keep, update_head_ok; static int write_fetch_head = 1; static int verbosity, deepen_relative, set_upstream, refetch; static int progress = -1; -static int enable_auto_gc = 1; -static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen; -static int max_jobs = -1, submodule_fetch_jobs_config = -1; +static int tags = TAGS_DEFAULT, update_shallow, deepen; +static int submodule_fetch_jobs_config = -1; static int fetch_parallel_config = 1; static int atomic_fetch; static enum transport_family family; @@ -92,17 +91,11 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP; static struct strbuf default_rla = STRBUF_INIT; static struct transport *gtransport; static struct transport *gsecondary; -static const char *submodule_prefix = ""; static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT; -static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; static struct refspec refmap = REFSPEC_INIT_FETCH; static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; static struct string_list server_options = STRING_LIST_INIT_DUP; static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP; -static int fetch_write_commit_graph = -1; -static int stdin_refspecs = 0; -static int negotiate_only; struct fetch_config { enum display_format display_format; @@ -178,92 +171,6 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset return 0; } -static struct option builtin_fetch_options[] = { - OPT__VERBOSITY(&verbosity), - OPT_BOOL(0, "all", &all, - N_("fetch from all remotes")), - OPT_BOOL(0, "set-upstream", &set_upstream, - N_("set upstream for git pull/fetch")), - OPT_BOOL('a', "append", &append, - N_("append to .git/FETCH_HEAD instead of overwriting")), - OPT_BOOL(0, "atomic", &atomic_fetch, - N_("use atomic transaction to update references")), - OPT_STRING(0, "upload-pack", &upload_pack, N_("path"), - N_("path to upload pack on remote end")), - OPT__FORCE(&force, N_("force overwrite of local reference"), 0), - OPT_BOOL('m', "multiple", &multiple, - N_("fetch from multiple remotes")), - OPT_SET_INT('t', "tags", &tags, - N_("fetch all tags and associated objects"), TAGS_SET), - OPT_SET_INT('n', NULL, &tags, - N_("do not fetch all tags (--no-tags)"), TAGS_UNSET), - OPT_INTEGER('j', "jobs", &max_jobs, - N_("number of submodules fetched in parallel")), - OPT_BOOL(0, "prefetch", &prefetch, - N_("modify the refspec to place all refs within refs/prefetch/")), - OPT_BOOL('p', "prune", &prune, - N_("prune remote-tracking branches no longer on remote")), - OPT_BOOL('P', "prune-tags", &prune_tags, - N_("prune local tags no longer on remote and clobber changed tags")), - OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"), - N_("control recursive fetching of submodules"), - PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules), - OPT_BOOL(0, "dry-run", &dry_run, - N_("dry run")), - OPT_BOOL(0, "write-fetch-head", &write_fetch_head, - N_("write fetched references to the FETCH_HEAD file")), - OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")), - OPT_BOOL('u', "update-head-ok", &update_head_ok, - N_("allow updating of HEAD ref")), - OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), - OPT_STRING(0, "depth", &depth, N_("depth"), - N_("deepen history of shallow clone")), - OPT_STRING(0, "shallow-since", &deepen_since, N_("time"), - N_("deepen history of shallow repository based on time")), - OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"), - N_("deepen history of shallow clone, excluding rev")), - OPT_INTEGER(0, "deepen", &deepen_relative, - N_("deepen history of shallow clone")), - OPT_SET_INT_F(0, "unshallow", &unshallow, - N_("convert to a complete repository"), - 1, PARSE_OPT_NONEG), - OPT_SET_INT_F(0, "refetch", &refetch, - N_("re-fetch without negotiating common commits"), - 1, PARSE_OPT_NONEG), - { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), - N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, - OPT_CALLBACK_F(0, "recurse-submodules-default", - &recurse_submodules_default, N_("on-demand"), - N_("default for recursive fetching of submodules " - "(lower priority than config files)"), - PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules), - OPT_BOOL(0, "update-shallow", &update_shallow, - N_("accept refs that update .git/shallow")), - OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"), - N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg), - OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")), - OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), - TRANSPORT_FAMILY_IPV4), - OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), - TRANSPORT_FAMILY_IPV6), - OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"), - N_("report that we have only objects reachable from this object")), - OPT_BOOL(0, "negotiate-only", &negotiate_only, - N_("do not fetch a packfile; instead, print ancestors of negotiation tips")), - OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), - OPT_BOOL(0, "auto-maintenance", &enable_auto_gc, - N_("run 'maintenance --auto' after fetching")), - OPT_BOOL(0, "auto-gc", &enable_auto_gc, - N_("run 'maintenance --auto' after fetching")), - OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates, - N_("check for forced-updates on all updated branches")), - OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph, - N_("write the commit-graph after fetching")), - OPT_BOOL(0, "stdin", &stdin_refspecs, - N_("accept refspecs from stdin")), - OPT_END() -}; - static void unlock_pack(unsigned int flags) { if (gtransport) @@ -2159,12 +2066,108 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) struct fetch_config config = { .display_format = DISPLAY_FORMAT_FULL, }; - int i; + const char *submodule_prefix = ""; const char *bundle_uri; struct string_list list = STRING_LIST_INIT_DUP; struct remote *remote = NULL; + int all = 0, multiple = 0; int result = 0; int prune_tags_ok = 1; + int enable_auto_gc = 1; + int unshallow = 0; + int max_jobs = -1; + int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT; + int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; + int fetch_write_commit_graph = -1; + int stdin_refspecs = 0; + int negotiate_only = 0; + int i; + + struct option builtin_fetch_options[] = { + OPT__VERBOSITY(&verbosity), + OPT_BOOL(0, "all", &all, + N_("fetch from all remotes")), + OPT_BOOL(0, "set-upstream", &set_upstream, + N_("set upstream for git pull/fetch")), + OPT_BOOL('a', "append", &append, + N_("append to .git/FETCH_HEAD instead of overwriting")), + OPT_BOOL(0, "atomic", &atomic_fetch, + N_("use atomic transaction to update references")), + OPT_STRING(0, "upload-pack", &upload_pack, N_("path"), + N_("path to upload pack on remote end")), + OPT__FORCE(&force, N_("force overwrite of local reference"), 0), + OPT_BOOL('m', "multiple", &multiple, + N_("fetch from multiple remotes")), + OPT_SET_INT('t', "tags", &tags, + N_("fetch all tags and associated objects"), TAGS_SET), + OPT_SET_INT('n', NULL, &tags, + N_("do not fetch all tags (--no-tags)"), TAGS_UNSET), + OPT_INTEGER('j', "jobs", &max_jobs, + N_("number of submodules fetched in parallel")), + OPT_BOOL(0, "prefetch", &prefetch, + N_("modify the refspec to place all refs within refs/prefetch/")), + OPT_BOOL('p', "prune", &prune, + N_("prune remote-tracking branches no longer on remote")), + OPT_BOOL('P', "prune-tags", &prune_tags, + N_("prune local tags no longer on remote and clobber changed tags")), + OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"), + N_("control recursive fetching of submodules"), + PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules), + OPT_BOOL(0, "dry-run", &dry_run, + N_("dry run")), + OPT_BOOL(0, "write-fetch-head", &write_fetch_head, + N_("write fetched references to the FETCH_HEAD file")), + OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")), + OPT_BOOL('u', "update-head-ok", &update_head_ok, + N_("allow updating of HEAD ref")), + OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), + OPT_STRING(0, "depth", &depth, N_("depth"), + N_("deepen history of shallow clone")), + OPT_STRING(0, "shallow-since", &deepen_since, N_("time"), + N_("deepen history of shallow repository based on time")), + OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"), + N_("deepen history of shallow clone, excluding rev")), + OPT_INTEGER(0, "deepen", &deepen_relative, + N_("deepen history of shallow clone")), + OPT_SET_INT_F(0, "unshallow", &unshallow, + N_("convert to a complete repository"), + 1, PARSE_OPT_NONEG), + OPT_SET_INT_F(0, "refetch", &refetch, + N_("re-fetch without negotiating common commits"), + 1, PARSE_OPT_NONEG), + { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), + N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, + OPT_CALLBACK_F(0, "recurse-submodules-default", + &recurse_submodules_default, N_("on-demand"), + N_("default for recursive fetching of submodules " + "(lower priority than config files)"), + PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules), + OPT_BOOL(0, "update-shallow", &update_shallow, + N_("accept refs that update .git/shallow")), + OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"), + N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg), + OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")), + OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), + TRANSPORT_FAMILY_IPV4), + OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), + TRANSPORT_FAMILY_IPV6), + OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"), + N_("report that we have only objects reachable from this object")), + OPT_BOOL(0, "negotiate-only", &negotiate_only, + N_("do not fetch a packfile; instead, print ancestors of negotiation tips")), + OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), + OPT_BOOL(0, "auto-maintenance", &enable_auto_gc, + N_("run 'maintenance --auto' after fetching")), + OPT_BOOL(0, "auto-gc", &enable_auto_gc, + N_("run 'maintenance --auto' after fetching")), + OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates, + N_("check for forced-updates on all updated branches")), + OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph, + N_("write the commit-graph after fetching")), + OPT_BOOL(0, "stdin", &stdin_refspecs, + N_("accept refspecs from stdin")), + OPT_END() + }; packet_trace_identity("fetch"); From patchwork Wed May 10 12:34:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13236902 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CDF7BC77B7D for ; Wed, 10 May 2023 12:35:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237107AbjEJMfH (ORCPT ); Wed, 10 May 2023 08:35:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36320 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237085AbjEJMep (ORCPT ); Wed, 10 May 2023 08:34:45 -0400 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 23CD57EE3 for ; Wed, 10 May 2023 05:34:42 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id EFD3E3200919; Wed, 10 May 2023 08:34:40 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Wed, 10 May 2023 08:34:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1683722080; x=1683808480; bh=Gw HAh7ymY1dL1n7gAHZxXdhUi5jHFwsCMP+QwVBgdNc=; b=X8jwkIduQyOGICVkAW i/KuzUpdIXjVsZ2WWb4ooIEkbaRD+NZs6QW/kYGkH6P7p16myj6lCAgtgg48JP8Q FM5shO1sN8C1g0007p3CL6bkjalrw0U4RWizmaZHgoiJa8tzWxUEVU63FbsysPiU rjUd/jh9XRKcIlMhrloP1ix3iVmwM4Zrs0pHvGkr2NW6xmZZG6JmWcz0nVBbbBo1 oiA6rUSrLk4hBUtS9hISE5sWGrG3LOcqSXjbm1cnTToe9rOmUcG9e6T/3WA+bj9Y N48JmY+7/S07ZP5p9qolr2DOXRBelbl6HE0i7dJ3JnrDRE8xVpvrjYxikw5quCSz Uzeg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm3; t=1683722080; x=1683808480; bh=GwHAh7ymY1dL1 n7gAHZxXdhUi5jHFwsCMP+QwVBgdNc=; b=D0LZW9EaBJnuavHA+Sq0zrR2H0K9Q 6SInG9//7Fe4nG6bjgzCXLSK+4lTBts8vybETI9XHnIwV2jkAh3qtDSGW9g3rMcr f7NkFNj1hXSQlHT2geyEMmslJ+YE7U2SGQzLZZUZnFHS9b3qkett867qc/Mw+twF DnIobbtR8y/8zBSOLufVh4WOIOr/Y85Ub70IG6m2siqERZIlYzA/sT6U39wF0LOc HrxUl6MrYA9CqcVSErJiJ8gL31dEFGKnt1qKM002WMwPkIVbp8s57+JAd3reWJOO Xkn5Tipa9AzN6YntjbwJDQ8MZYwWWY+at0Bxx24wJsl3LtWeN9sFN6Q5A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeegiedgfeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 10 May 2023 08:34:38 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 359bdb51 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 10 May 2023 12:34:29 +0000 (UTC) Date: Wed, 10 May 2023 14:34:36 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v5 9/9] fetch: introduce machine-parseable "porcelain" output format Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The output of git-fetch(1) is obviously designed for consumption by users, only: we neatly columnize data, we abbreviate reference names, we print neat arrows and we don't provide information about actual object IDs that have changed. This makes the output format basically unusable in the context of scripted invocations of git-fetch(1) that want to learn about the exact changes that the command performs. Introduce a new machine-parseable "porcelain" output format that is supposed to fix this shortcoming. This output format is intended to provide information about every reference that is about to be updated, the old object ID that the reference has been pointing to and the new object ID it will be updated to. Furthermore, the output format provides the same flags as the human-readable format to indicate basic conditions for each reference update like whether it was a fast-forward update, a branch deletion, a rejected update or others. The output format is quite simple: ``` \n ``` We assume two conditions which are generally true: - The old and new object IDs have fixed known widths and cannot contain spaces. - References cannot contain newlines. With these assumptions, the output format becomes unambiguously parseable. Furthermore, given that this output is designed to be consumed by scripts, the machine-readable data is printed to stdout instead of stderr like the human-readable output is. This is mostly done so that other data printed to stderr, like error messages or progress meters, don't interfere with the parseable data. A notable ommission here is that the output format does not include the remote from which a reference was fetched, which might be important information especially in the context of multi-remote fetches. But as such a format would require us to print the remote for every single reference update due to parallelizable fetches it feels wasteful for the most likely usecase, which is when fetching from a single remote. In a similar spirit, a second restriction is that this cannot be used with `--recurse-submodules`. This is because any reference updates would be ambiguous without also printing the repository in which the update happens. Considering that both multi-remote and submodule fetches are user-facing features, using them in conjunction with `--porcelain` that is intended for scripting purposes is likely not going to be useful in the majority of cases. With that in mind these restrictions feel acceptable. If usecases for either of these come up in the future though it is easy enough to add a new "porcelain-v2" format that adds this information. Signed-off-by: Patrick Steinhardt --- Documentation/fetch-options.txt | 7 ++ Documentation/git-fetch.txt | 9 ++ builtin/fetch.c | 88 ++++++++++++++---- t/t5574-fetch-output.sh | 159 ++++++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 19 deletions(-) diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 622bd84768..41fc7ca3c6 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -78,6 +78,13 @@ linkgit:git-config[1]. --dry-run:: Show what would be done, without making any changes. +--porcelain:: + Print the output to standard output in an easy-to-parse format for + scripts. See section OUTPUT in linkgit:git-fetch[1] for details. ++ +This is incompatible with `--recurse-submodules=[yes|on-demand]` and takes +precedence over the `fetch.output` config option. + ifndef::git-pull[] --[no-]write-fetch-head:: Write the list of remote refs fetched in the `FETCH_HEAD` diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index fba66f1460..f123139c58 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -204,6 +204,15 @@ representing the status of a single ref. Each line is of the form: -> [] ------------------------------- +When using `--porcelain`, the output format is intended to be +machine-parseable. In contrast to the human-readable output formats it +thus prints to standard output instead of standard error. Each line is +of the form: + +------------------------------- + +------------------------------- + The status of up-to-date refs is shown only if the --verbose option is used. diff --git a/builtin/fetch.c b/builtin/fetch.c index 7a3d620c4c..462fc86b99 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -52,6 +52,7 @@ enum display_format { DISPLAY_FORMAT_UNKNOWN = 0, DISPLAY_FORMAT_FULL, DISPLAY_FORMAT_COMPACT, + DISPLAY_FORMAT_PORCELAIN, }; struct display_state { @@ -754,6 +755,9 @@ static void display_state_init(struct display_state *display_state, struct ref * display_state->refcol_width = refcol_width(ref_map, display_state->format == DISPLAY_FORMAT_COMPACT); break; + case DISPLAY_FORMAT_PORCELAIN: + /* We don't need to precompute anything here. */ + break; default: BUG("unexpected display format %d", display_state->format); } @@ -824,8 +828,12 @@ static void print_compact(struct display_state *display_state, static void display_ref_update(struct display_state *display_state, char code, const char *summary, const char *error, const char *remote, const char *local, + const struct object_id *old_oid, + const struct object_id *new_oid, int summary_width) { + FILE *f = stderr; + if (verbosity < 0) return; @@ -858,12 +866,17 @@ static void display_ref_update(struct display_state *display_state, char code, break; } + case DISPLAY_FORMAT_PORCELAIN: + strbuf_addf(&display_state->buf, "%c %s %s %s", code, + oid_to_hex(old_oid), oid_to_hex(new_oid), local); + f = stdout; + break; default: BUG("unexpected display format %d", display_state->format); }; strbuf_addch(&display_state->buf, '\n'); - fputs(display_state->buf.buf, stderr); + fputs(display_state->buf.buf, f); } static int update_local_ref(struct ref *ref, @@ -881,7 +894,8 @@ static int update_local_ref(struct ref *ref, if (oideq(&ref->old_oid, &ref->new_oid)) { if (verbosity > 0) display_ref_update(display_state, '=', _("[up to date]"), NULL, - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return 0; } @@ -894,7 +908,8 @@ static int update_local_ref(struct ref *ref, */ display_ref_update(display_state, '!', _("[rejected]"), _("can't fetch into checked-out branch"), - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return 1; } @@ -905,12 +920,14 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("updating tag", ref, transaction, 0); display_ref_update(display_state, r ? '!' : 't', _("[tag update]"), r ? _("unable to update local ref") : NULL, - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return r; } else { display_ref_update(display_state, '!', _("[rejected]"), _("would clobber existing tag"), - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return 1; } } @@ -943,7 +960,8 @@ static int update_local_ref(struct ref *ref, r = s_update_ref(msg, ref, transaction, 0); display_ref_update(display_state, r ? '!' : '*', what, r ? _("unable to update local ref") : NULL, - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return r; } @@ -965,7 +983,8 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("fast-forward", ref, transaction, 1); display_ref_update(display_state, r ? '!' : ' ', quickref.buf, r ? _("unable to update local ref") : NULL, - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); strbuf_release(&quickref); return r; } else if (force || ref->force) { @@ -977,12 +996,14 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("forced-update", ref, transaction, 1); display_ref_update(display_state, r ? '!' : '+', quickref.buf, r ? _("unable to update local ref") : _("forced update"), - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); strbuf_release(&quickref); return r; } else { display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"), - remote_ref->name, ref->name, summary_width); + remote_ref->name, ref->name, + &ref->old_oid, &ref->new_oid, summary_width); return 1; } } @@ -1223,7 +1244,9 @@ static int store_updated_refs(struct display_state *display_state, display_ref_update(display_state, '*', *kind ? kind : "branch", NULL, rm->name, - "FETCH_HEAD", summary_width); + "FETCH_HEAD", + &rm->new_oid, &rm->old_oid, + summary_width); } } } @@ -1363,6 +1386,7 @@ static int prune_refs(struct display_state *display_state, for (ref = stale_refs; ref; ref = ref->next) { display_ref_update(display_state, '-', _("[deleted]"), NULL, _("(none)"), ref->name, + &ref->new_oid, &ref->old_oid, summary_width); warn_dangling_symref(stderr, dangling_msg, ref->name); } @@ -1795,7 +1819,8 @@ static int add_remote_or_group(const char *name, struct string_list *list) return 1; } -static void add_options_to_argv(struct strvec *argv) +static void add_options_to_argv(struct strvec *argv, + enum display_format format) { if (dry_run) strvec_push(argv, "--dry-run"); @@ -1831,6 +1856,8 @@ static void add_options_to_argv(struct strvec *argv) strvec_push(argv, "--ipv6"); if (!write_fetch_head) strvec_push(argv, "--no-write-fetch-head"); + if (format == DISPLAY_FORMAT_PORCELAIN) + strvec_pushf(argv, "--porcelain"); } /* Fetch multiple remotes in parallel */ @@ -1839,6 +1866,7 @@ struct parallel_fetch_state { const char **argv; struct string_list *remotes; int next, result; + enum display_format format; }; static int fetch_next_remote(struct child_process *cp, @@ -1858,7 +1886,7 @@ static int fetch_next_remote(struct child_process *cp, strvec_push(&cp->args, remote); cp->git_cmd = 1; - if (verbosity >= 0) + if (verbosity >= 0 && state->format != DISPLAY_FORMAT_PORCELAIN) printf(_("Fetching %s\n"), remote); return 1; @@ -1890,7 +1918,8 @@ static int fetch_finished(int result, struct strbuf *out, return 0; } -static int fetch_multiple(struct string_list *list, int max_children) +static int fetch_multiple(struct string_list *list, int max_children, + enum display_format format) { int i, result = 0; struct strvec argv = STRVEC_INIT; @@ -1903,10 +1932,10 @@ static int fetch_multiple(struct string_list *list, int max_children) strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc", "--no-write-commit-graph", NULL); - add_options_to_argv(&argv); + add_options_to_argv(&argv, format); if (max_children != 1 && list->nr != 1) { - struct parallel_fetch_state state = { argv.v, list, 0, 0 }; + struct parallel_fetch_state state = { argv.v, list, 0, 0, format }; const struct run_process_parallel_opts opts = { .tr2_category = "fetch", .tr2_label = "parallel/fetch", @@ -1930,7 +1959,7 @@ static int fetch_multiple(struct string_list *list, int max_children) strvec_pushv(&cmd.args, argv.v); strvec_push(&cmd.args, name); - if (verbosity >= 0) + if (verbosity >= 0 && format != DISPLAY_FORMAT_PORCELAIN) printf(_("Fetching %s\n"), name); cmd.git_cmd = 1; if (run_command(&cmd)) { @@ -2081,6 +2110,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) int fetch_write_commit_graph = -1; int stdin_refspecs = 0; int negotiate_only = 0; + int porcelain = 0; int i; struct option builtin_fetch_options[] = { @@ -2115,6 +2145,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules), OPT_BOOL(0, "dry-run", &dry_run, N_("dry run")), + OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")), OPT_BOOL(0, "write-fetch-head", &write_fetch_head, N_("write fetched references to the FETCH_HEAD file")), OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")), @@ -2220,6 +2251,26 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) fetch_config_from_gitmodules(sfjc, rs); } + + if (porcelain) { + switch (recurse_submodules_cli) { + case RECURSE_SUBMODULES_OFF: + case RECURSE_SUBMODULES_DEFAULT: + /* + * Reference updates in submodules would be ambiguous + * in porcelain mode, so we reject this combination. + */ + recurse_submodules = RECURSE_SUBMODULES_OFF; + break; + + default: + die(_("options '%s' and '%s' cannot be used together"), + "--porcelain", "--recurse-submodules"); + } + + config.display_format = DISPLAY_FORMAT_PORCELAIN; + } + if (negotiate_only && !negotiation_tip.nr) die(_("--negotiate-only needs one or more --negotiation-tip=*")); @@ -2339,10 +2390,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) max_children = fetch_parallel_config; /* TODO should this also die if we have a previous partial-clone? */ - result = fetch_multiple(&list, max_children); + result = fetch_multiple(&list, max_children, config.display_format); } - /* * This is only needed after fetch_one(), which does not fetch * submodules by itself. @@ -2361,7 +2411,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (max_children < 0) max_children = fetch_parallel_config; - add_options_to_argv(&options); + add_options_to_argv(&options, config.display_format); result = fetch_submodules(the_repository, &options, submodule_prefix, diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index 9890f6f381..90e6dcb9a7 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -61,6 +61,141 @@ test_expect_success 'fetch compact output' ' test_cmp expect actual ' +test_expect_success 'fetch porcelain output' ' + test_when_finished "rm -rf porcelain" && + + # Set up a bunch of references that we can use to demonstrate different + # kinds of flag symbols in the output format. + MAIN_OLD=$(git rev-parse HEAD) && + git branch "fast-forward" && + git branch "deleted-branch" && + git checkout -b force-updated && + test_commit --no-tag force-update-old && + FORCE_UPDATED_OLD=$(git rev-parse HEAD) && + git checkout main && + + # Clone and pre-seed the repositories. We fetch references into two + # namespaces so that we can test that rejected and force-updated + # references are reported properly. + refspecs="refs/heads/*:refs/unforced/* +refs/heads/*:refs/forced/*" && + git clone . porcelain && + git -C porcelain fetch origin $refspecs && + + # Now that we have set up the client repositories we can change our + # local references. + git branch new-branch && + git branch -d deleted-branch && + git checkout fast-forward && + test_commit --no-tag fast-forward-new && + FAST_FORWARD_NEW=$(git rev-parse HEAD) && + git checkout force-updated && + git reset --hard HEAD~ && + test_commit --no-tag force-update-new && + FORCE_UPDATED_NEW=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + - $MAIN_OLD $ZERO_OID refs/forced/deleted-branch + - $MAIN_OLD $ZERO_OID refs/unforced/deleted-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/unforced/fast-forward + ! $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/unforced/force-updated + * $ZERO_OID $MAIN_OLD refs/unforced/new-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/forced/fast-forward + + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/forced/force-updated + * $ZERO_OID $MAIN_OLD refs/forced/new-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/remotes/origin/fast-forward + + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/remotes/origin/force-updated + * $ZERO_OID $MAIN_OLD refs/remotes/origin/new-branch + EOF + + # Execute a dry-run fetch first. We do this to assert that the dry-run + # and non-dry-run fetches produces the same output. Execution of the + # fetch is expected to fail as we have a rejected reference update. + test_must_fail git -C porcelain fetch \ + --porcelain --dry-run --prune origin $refspecs >actual && + test_cmp expect actual && + + # And now we perform a non-dry-run fetch. + test_must_fail git -C porcelain fetch \ + --porcelain --prune origin $refspecs >actual 2>stderr && + test_cmp expect actual && + test_must_be_empty stderr +' + +test_expect_success 'fetch porcelain with multiple remotes' ' + test_when_finished "rm -rf porcelain" && + + git switch --create multiple-remotes && + git clone . porcelain && + git -C porcelain remote add second-remote "$PWD" && + git -C porcelain fetch second-remote && + + test_commit --no-tag multi-commit && + old_commit=$(git rev-parse HEAD~) && + new_commit=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + $old_commit $new_commit refs/remotes/origin/multiple-remotes + $old_commit $new_commit refs/remotes/second-remote/multiple-remotes + EOF + + git -C porcelain fetch --porcelain --all >actual 2>stderr && + test_cmp expect actual && + test_must_be_empty stderr +' + +test_expect_success 'fetch porcelain refuses to work with submodules' ' + test_when_finished "rm -rf porcelain" && + + cat >expect <<-EOF && + fatal: options ${SQ}--porcelain${SQ} and ${SQ}--recurse-submodules${SQ} cannot be used together + EOF + + git init porcelain && + test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=yes 2>stderr && + test_cmp expect stderr && + + test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=on-demand 2>stderr && + test_cmp expect stderr +' + +test_expect_success 'fetch porcelain overrides fetch.output config' ' + test_when_finished "rm -rf porcelain" && + + git switch --create config-override && + git clone . porcelain && + test_commit new-commit && + old_commit=$(git rev-parse HEAD~) && + new_commit=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + $old_commit $new_commit refs/remotes/origin/config-override + * $ZERO_OID $new_commit refs/tags/new-commit + EOF + + git -C porcelain -c fetch.output=compact fetch --porcelain >stdout 2>stderr && + test_must_be_empty stderr && + test_cmp expect stdout +' + +test_expect_success 'fetch --no-porcelain overrides previous --porcelain' ' + test_when_finished "rm -rf no-porcelain" && + + git switch --create no-porcelain && + git clone . no-porcelain && + test_commit --no-tag no-porcelain && + old_commit=$(git rev-parse --short HEAD~) && + new_commit=$(git rev-parse --short HEAD) && + + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + $old_commit..$new_commit no-porcelain -> origin/no-porcelain + EOF + + git -C no-porcelain fetch --porcelain --no-porcelain >stdout 2>stderr && + test_cmp expect stderr && + test_must_be_empty stdout +' + test_expect_success 'fetch output with HEAD' ' test_when_finished "rm -rf head" && git clone . head && @@ -90,6 +225,30 @@ test_expect_success 'fetch output with HEAD' ' test_cmp expect actual.err ' +test_expect_success 'fetch porcelain output with HEAD' ' + test_when_finished "rm -rf head" && + git clone . head && + COMMIT_ID=$(git rev-parse HEAD) && + + git -C head fetch --porcelain --dry-run origin HEAD >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID FETCH_HEAD + EOF + test_cmp expect actual && + + git -C head fetch --porcelain origin HEAD >actual && + test_cmp expect actual && + + git -C head fetch --porcelain --dry-run origin HEAD:foo >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID refs/heads/foo + EOF + test_cmp expect actual && + + git -C head fetch --porcelain origin HEAD:foo >actual && + test_cmp expect actual +' + test_expect_success 'fetch output with object ID' ' test_when_finished "rm -rf object-id" && git clone . object-id &&