From patchwork Thu Apr 27 11:13:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225375 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 9C231C77B73 for ; Thu, 27 Apr 2023 11:13:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243669AbjD0LNR (ORCPT ); Thu, 27 Apr 2023 07:13:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57250 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243319AbjD0LNQ (ORCPT ); Thu, 27 Apr 2023 07:13:16 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 96064BB for ; Thu, 27 Apr 2023 04:13:12 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 0EBB65C01ED; Thu, 27 Apr 2023 07:13:12 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Thu, 27 Apr 2023 07:13:12 -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=1682593992; x=1682680392; bh=uh DuGh10NEiU9R4gNKeRZf63piqr/2JZ4nLpJDfrrGA=; b=oziDUXUDWb9EK9Z0Qw hGC8FS4KBdcY0AUlOpEX//oRcCX3OFh77gTeNkXVEzsASLHvHRST9uVMeXrhsQJ2 wm0bjxikhsJbtc/27CzEP0gT4cu/cRK6rJoM+jQ/QKODT4xV6tzbyWMfCmI9zodL xvG4UXMT1XEoXzyUzJNURAcnsXhT4BWG4u2F4nMi/B5QDk4c6Eo+oY2nbTNUXyVa 944CAaKhDomGK4mxCRErxIlUiyGIZs2ZjlLhd4vVXLMx5iXPiuG9NzvC4Cbb+qf/ 3m7CC52AwMSeoRC0lMk9gJkcvfJXfbbMJmHQj04O542maaLkESzXv6EyvJ9rhQkI dx1Q== 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=1682593992; x=1682680392; bh=uhDuGh10NEiU9 R4gNKeRZf63piqr/2JZ4nLpJDfrrGA=; b=fdl1Nxe6aVY/WhKPF1BQwGEQxuBKD efbmYlx+JoIiM4KtdrtRMgRECIMCmaZ5G2hzgtEmHGMHf4v6inU+iiSo90IbAubr 0cXIJ494PI/JhDBrWRNiodIglwQMNsqerzhoH1HI5L2hEiCHtGTH2AokYuzXf6qS 6JRsSbOhVg2eDWp3dnWZiI3tJ0V08v+hR1yAAcClhYgW2REwuZoZHbNDjqfQgZht 2wUvFf3asdu0myHeoJgPRkh8wkPn/kGbKnRPIo41HoXdg2beK5dD/Yd2GPWLIyEN TtubejBSBYPvGLBX47xPkSKc2siXffbHAGiriTWcfu1KahozCE9NHzbyQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:10 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 4b733560 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:12:41 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:08 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 1/8] fetch: split out tests for output format Message-ID: <0d0d50d14c557f8313747e7d0e104c2c0819dab9.1682593865.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'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 Thu Apr 27 11:13:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225376 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 D298AC77B73 for ; Thu, 27 Apr 2023 11:13:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243693AbjD0LN3 (ORCPT ); Thu, 27 Apr 2023 07:13:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57270 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243051AbjD0LNR (ORCPT ); Thu, 27 Apr 2023 07:13:17 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B36D44B9 for ; Thu, 27 Apr 2023 04:13:16 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 9A34F5C0232; Thu, 27 Apr 2023 07:13:15 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Thu, 27 Apr 2023 07:13: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=1682593995; x=1682680395; bh=7q MNBqxjQ/PwtwPViD44HUP10UcferELzA/tDp9RlBM=; b=oH/kYynqXk/43f9H+b qaPT+cYpbd9FrSNkyYbCkclWEwciRQwlDcevrNK660cs1ziP6k4BFH1oXOQ/6TLE 5Dk/kLxJbXkL2vRYUBWLcHViXmhay4yWPfBXz9QEHMLNagxPhEM4leR3MTACdHps PnMP7ZeM4PSNb7dCdnTopwfxaDS51ObWZSye+T8rE1htqNhSEX16JK2D5UhIC84K qlSS6Gg4auJdafh6LUhGJnPJMByfb9hYd3ThVfHZFDpOSjXdEt1MeTjgzIgDAIpg Xm+t38EKt7kY/Dt+BWhTLcQ/8MaqcGe/wfxMH4oF2etNdsF/pwjmxmWOIwT/Umrc g1Gw== 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=1682593995; x=1682680395; bh=7qMNBqxjQ/Pwt wPViD44HUP10UcferELzA/tDp9RlBM=; b=SDUygrQndtN7D0m7fcNANDlypTWiC f/KwdQmB0n0sLidrDMcJkkXCLW0omUTJYBD4siwmZ1oK+FAYkucTa4mp7bZVX1bc cadTcLsevIHHwV/rvlPdKcLRB7LIlb+l91l2lsqgbSVw5PPLgKWHtV9CfEwhNJIM pX0QpAMHdjaA8pFhVnxl0ELHqQPbR3VUndizUO58fX8rUzQlrk6iqkfSA9+ZZ7aP piOKGBTtd7pHxhcy0IFNAm7BRos87ajdPEYgngBNlWALGXVoHOe9O2iIEQF4H2wt HSJ+EkVsNEnQzg5tZYrS18LDzbJTrGriCBpG78uw3oXlgb6aQptuAf0JQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:14 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 39666953 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:12:45 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:12 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 2/8] fetch: add a test to exercise invalid output formats Message-ID: <29d2c58914b7270a4603cd65565c06ff74355e96.1682593865.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 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 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index f91b654d38..0e45c27007 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -7,6 +7,23 @@ 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 >actual 2>&1 && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ} + EOF + test_cmp expect actual && + + test_must_fail git -C clone -c fetch.output=garbage fetch origin >actual 2>&1 && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ} + EOF + test_cmp expect actual +' + test_expect_success 'fetch aligned output' ' git clone . full-output && test_commit looooooooooooong-tag && From patchwork Thu Apr 27 11:13:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225377 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 ADBE2C77B73 for ; Thu, 27 Apr 2023 11:13:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243319AbjD0LNf (ORCPT ); Thu, 27 Apr 2023 07:13:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57466 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243692AbjD0LN3 (ORCPT ); Thu, 27 Apr 2023 07:13:29 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E7D0C49DE for ; Thu, 27 Apr 2023 04:13:20 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 5794D5C020D; Thu, 27 Apr 2023 07:13:20 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 27 Apr 2023 07:13: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=1682594000; x=1682680400; bh=o1 ZXgEnbiFgI0dxoWXI2p92/CznREiJEU2ynBA2/nrY=; b=aJ0OxP8IeOTzCF/tPk Niu0w/pd79JBjINZdpMdYp2Dk5YPPJnbdqDzCyJzOMJNgiAqbkghXO2KqRmhc6we rpd7JRcbZ+XgA4zjoZtyV5u8ZdQTT+Mpaoa/cWLShhcznRUXszvKWaanyi0Njf5Y y1Pt4O1LTlYcHilV71ZwxBL/TjztXu9bMvx41vPeBIdyFbm1BgX9Fe9ldEgJlzlI F9C4mOknVsX5jQ07zI5UAmZzRAiKhvDApEolZLrpgIo6gSo2pPIVbII1GbVXCUj7 OmLIcaD1wWpI1oklAUbeWzQY0aAqpyPk6/JSJdyiAB+uCtzThhkbfWclptOKhCIA flDA== 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=1682594000; x=1682680400; bh=o1ZXgEnbiFgI0 dxoWXI2p92/CznREiJEU2ynBA2/nrY=; b=Ct0ep9WPpyTWcGHP8TDp2wS9EsqX5 V5JIEgFPD6u5G5zwW9myVKT0u6RRq/icdwjpwounOH3rDGzyDczsdXRQr4g6f8LG 30xhX1YJ9XVpWIk+ugLA/qrjplksg9do4h4RzcwvmWIasNYFiL4KlGxmQu1Qs7ss LcWH0XY84xAbX5zZUzgQ8d1LanBB9ezyDYe8Rg1WtHai16brYuddiLg05/xzipKQ bJ33m3zNJKllGtlCx0olipMxEqPURHJ8eMe5+1lxWeJRioJ9SS2QXHsG6l0qMDAy wB7upCm1lyTLo8NQ36vDp5Dkfqi/d2/9PrDYMn9EyEBg5ld0ZdVVaoUZg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepleejteffveehgeegteekteeiudeiieeigeeigedtffehgeekhfejheefkefhveel necuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlhhushhtvghrufhiiigvpedune curfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:18 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id e81d3453 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:12:49 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:16 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 3/8] fetch: fix missing from-reference when fetching HEAD:foo Message-ID: 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 it is not intended when displaying the updated references and would cause us to miss the left-hand side of the displayed reference update: ``` $ git fetch origin HEAD:foo From https://github.com/git/git * [new ref] -> foo ``` The HEAD string is clearly missing from the left-hand side of the arrow, which is further stressed by the point that the following commands show the left-hand side as expected: ``` $ git fetch origin HEAD From https://github.com/git/git * branch HEAD -> FETCH_HEAD $ git fetch origin master From https://github.com/git/git * branch master -> FETCH_HEAD * branch master -> origin/master ``` 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 bug to occur, 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 fix the bug 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" and "what" 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 | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index c310d89878..7c64f0c562 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 0e45c27007..b9dcdade63 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -54,6 +54,31 @@ test_expect_success 'fetch compact output' ' test_cmp expect actual ' +test_expect_success 'fetch output with HEAD and --dry-run' ' + test_when_finished "rm -rf head" && + git clone . head && + + git -C head fetch --dry-run origin HEAD >actual 2>&1 && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * branch HEAD -> FETCH_HEAD + EOF + test_cmp expect actual && + + git -C head fetch origin HEAD >actual 2>&1 && + test_cmp expect actual && + + git -C head fetch --dry-run origin HEAD:foo >actual 2>&1 && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * [new ref] HEAD -> foo + EOF + test_cmp expect actual && + + git -C head fetch origin HEAD:foo >actual 2>&1 && + test_cmp expect actual +' + test_expect_success '--no-show-forced-updates' ' mkdir forced-updates && ( From patchwork Thu Apr 27 11:13: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: 13225378 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 3FF42C77B61 for ; Thu, 27 Apr 2023 11:13:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243576AbjD0LNh (ORCPT ); Thu, 27 Apr 2023 07:13:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243660AbjD0LN3 (ORCPT ); Thu, 27 Apr 2023 07:13:29 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9601A55A7 for ; Thu, 27 Apr 2023 04:13:24 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 0DDEB5C020D; Thu, 27 Apr 2023 07:13:24 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 27 Apr 2023 07:13: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=1682594004; x=1682680404; bh=vC VEl1KkpKG0GXeFBBIhQGMaTh7+rZP/uELoIa6WyCY=; b=AOwWufHtv6+As2+A9j 5s1QiUtN1ZMv3fK/rzZVslPRhT5EISvnpdefu0WbkN8X3dmJ+i6gFdb03Z7XF1MY 48/AtMPWmiX6b6SjGtJvMwgcWv6luKlKCS5hOyXvqp4SPnO631URY7p6ZkPzOc9w CEltJWlAmOKRaEANQGAY8VnZVHYU0Jv76GV4XoTPwJfmdVNgSi53N8QXC3F/IQ7Q Jp9UtmvkWQBZ/OL6GYI8hxUgVe2hWhjA0fSID/pC2WLytqycNvr96WOuitfkl117 7xwrrHP+k4/SL2oKA1H7SoYR09ufnAUDhjXox5+TFKC7Rw1tyCvyK6ns0zvvZiSJ 3qww== 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=1682594004; x=1682680404; bh=vCVEl1KkpKG0G XeFBBIhQGMaTh7+rZP/uELoIa6WyCY=; b=O/LVO1u0NFbSdiJoek/XmnKCvJzXH DXZxLeol8kuH4nhfpNIJUFAcOBlwOt8ThKOrOnOdQnA1yhzlHKmnPOPr7OoPIplM Wojqd4qYJh0+ETBdh441qy78rhcYA7SN/EykyullxpltocvgML5HVhQjKoYBwqAV jCV6HcodGePvw6RJLWnL4tZcrDr1cSFx111xCXJuvOzhLVvNXirAwME12qOafiSy yqfwgfzblmrne2VOGZ0VsP2s+SETBjkRONAPh30RIgMwvyT/BqDJFic5dLcB2TFG VO9vXqtfidYMFDJg0JT8vp1UEh5Y3eHmHTO2zSYmPcdCybjvxERqoHzhg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:22 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 9b900bd2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:12:53 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:20 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 4/8] fetch: introduce `display_format` enum 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 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 | 101 ++++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 37 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 7c64f0c562..e03fcd1b2f 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; @@ -784,7 +790,6 @@ static int refcol_width(const struct ref *ref, int compact_format) 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; @@ -809,31 +814,42 @@ 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 = 10; - for (rm = ref_map; rm; rm = rm->next) { - int width; + switch (display_state->format) { + case DISPLAY_FORMAT_FULL: + case DISPLAY_FORMAT_COMPACT: { + struct ref *rm; - if (rm->status == REF_STATUS_REJECT_SHALLOW || - !rm->peer_ref || - !strcmp(rm->name, "HEAD")) - continue; + display_state->refcol_width = 10; + for (rm = ref_map; rm; rm = rm->next) { + int width; - width = refcol_width(rm, display_state->compact_format); + if (rm->status == REF_STATUS_REJECT_SHALLOW || + !rm->peer_ref || + !strcmp(rm->name, "HEAD")) + continue; - /* - * 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; + width = refcol_width(rm, display_state->format == DISPLAY_FORMAT_COMPACT); + + /* + * 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; + } + + break; + } + default: + BUG("unexpected display foramt %d", display_state->format); } } @@ -904,30 +920,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 Thu Apr 27 11:13:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225379 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 C6ABCC77B73 for ; Thu, 27 Apr 2023 11:13:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243671AbjD0LNj (ORCPT ); Thu, 27 Apr 2023 07:13:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243678AbjD0LNb (ORCPT ); Thu, 27 Apr 2023 07:13:31 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7E7F55BF for ; Thu, 27 Apr 2023 04:13:29 -0700 (PDT) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 114FD5C0233; Thu, 27 Apr 2023 07:13:29 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Thu, 27 Apr 2023 07:13:29 -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=1682594009; x=1682680409; bh=k1 Irg+K2Ks7P6+3Wg70FgcscNVTm1zQzldeRekZGlfw=; b=Avll/nX3cLabU7x461 huFK8mzovhgcWKfRVh3krT6tu4m4N1OpKftyPa+3rRK3DUOjOX2SObJt8iu5shVD szSBrhFEIBjW0IcnrN3iJC2hGhDMkF3hEgAzvHSTb0slitYgXqdltn/cZnM8Wy8I 6iK0xkji+xrO5rssP0nElV13nKG3CypMBUm4zgNHNIkpluEqShl4nGUOjwyBhC9O /gszVF3lJGMu6cQ368cVkQufb+mq2kqkRGW/EfD9YUQlBl+emCj9Vt85ikZB3feN doF+UYGJtYiXXyWegVAxJ0oygMBiMzUnyh2OigR+3mhkLNUxVOc/qBoGhaJlUDsR doYQ== 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=1682594009; x=1682680409; bh=k1Irg+K2Ks7P6 +3Wg70FgcscNVTm1zQzldeRekZGlfw=; b=SUC8/14DnHw3s2rEUcGfA3FjTd8bC kdrlyXaWOsOfSD+O4aQdli8y2+Gc3XOvCL4o+aHBKbAy5ZBCmVPhhgQ7OejobfFM alG2XS4777q3lVcLCQYnxE1RquxYW703TA5erYBelGmNtSyZxVpZTlj49WqZ2eAg hQDKrCMR/oPC+yZcmj5flekTxqruxZ0b/3rBR9cggEdeSUxj3BCo71N+5OChKWGl LUoUlwzU0UHIJdIpRxqzmC1Ws4NNrX/E6sAY2ZWaccYSJdUHRVx/WpJgt0399OYH gUnmcjV8gxwNJ6iWs4RURkve1BfSJsZKVyB4Y3bkLcSxF7xCEMDtqVWUw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:27 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id c535e891 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:12:58 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:25 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 5/8] fetch: move display format parsing into main function Message-ID: <4990d35998ea5b6a16acce106edfaf3c68e4a01e.1682593865.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 output format though that is intended to be parseable by machines, for example inside of a script. In that case it becomes a bit awkward of an interface if you have to call git-fetch(1) with the `fetch.output` config key set. We're thus going to introduce a new `--output-format` switch for git-fetch(1) so that the output format can be configured more directly. This means we'll have to hook parsing of the display format into the command line options parser. Having the code to determine the actual output format scattered across two different sites is hard to reason about though. 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 | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index e03fcd1b2f..bcc156a9ce 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -788,14 +788,13 @@ static int refcol_width(const struct ref *ref, 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); @@ -812,15 +811,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: { @@ -1614,7 +1604,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; @@ -1700,7 +1691,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); @@ -2076,7 +2067,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; @@ -2143,7 +2135,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); @@ -2155,6 +2147,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) { int i; const char *bundle_uri; + enum display_format display_format = DISPLAY_FORMAT_UNKNOWN; struct string_list list = STRING_LIST_INIT_DUP; struct remote *remote = NULL; int result = 0; @@ -2181,6 +2174,19 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (display_format == DISPLAY_FORMAT_UNKNOWN) { + const char *format = "full"; + + git_config_get_string_tmp("fetch.output", &format); + if (!strcasecmp(format, "full")) + display_format = DISPLAY_FORMAT_FULL; + else if (!strcasecmp(format, "compact")) + display_format = DISPLAY_FORMAT_COMPACT; + else + die(_("invalid value for '%s': '%s'"), + "fetch.output", format); + } + if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT) recurse_submodules = recurse_submodules_cli; @@ -2309,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, + display_format); } else { int max_children = max_jobs; From patchwork Thu Apr 27 11:13:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225380 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 4B999C77B61 for ; Thu, 27 Apr 2023 11:13:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243720AbjD0LNs (ORCPT ); Thu, 27 Apr 2023 07:13:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57478 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243051AbjD0LNf (ORCPT ); Thu, 27 Apr 2023 07:13:35 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 614A65263 for ; Thu, 27 Apr 2023 04:13:33 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id CD5D55C01ED; Thu, 27 Apr 2023 07:13:32 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Thu, 27 Apr 2023 07:13: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=1682594012; x=1682680412; bh=yX s4KeKNyryWqJ0ulQNz5o/4DTQGtptm9k7Tbl6erAs=; b=E65yBJHWSzN550qSuy paNppqXK6tyw00VSEK+/S0Li++Ll8jrXkLbBJGPXGDlrPLWwgFj51nr+SoNNC4HD a0+ycCafv4voA146vzQ56bmN6brGOqFSDAWWGxiAh78DkGRv6xoam5RauWk6dB9Q UzFYHGi8XNzbt4A7RW0vWudqzwlhy8MY+eJKobj4Sp76CjRDuRIxyoguYWAVXi0a 2w6dKZ0CRNWmN39MOLDh4iKVTdRZ9c7ZGZiwW8l64ifcg05C4xhGtK6K9YGSmgXm qtn4oBnGpxtlaYB7XFgLBL2PkKUvbnBHwjRcDCx9tCNLfli/lxFarUnzWr9htrjB ShjA== 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=1682594012; x=1682680412; bh=yXs4KeKNyryWq J0ulQNz5o/4DTQGtptm9k7Tbl6erAs=; b=BzyNd5C5mhUU/FDP2SjZvyPU20q1S T90YwURc9c2HA0jPEuNNuh4PNo+PzPb6Fa9WqaN3wh7Hbu/TXFu+OaD+ytlnK9pb wwVko18IHiR5Wuf2ldDwarF6twzosHigSPyMSGt6rO6TpYRwT++HxK3FmqZt1aIU QwLUc4qi3yEhm0/AnM6VVz+Q4v2fdEVrO+BH06QcCDnm5p7i45L91InY52iWYLCm 8uxzh+JboPwe3XZaqWKkBqgaE7EjyLxSc1fyjUOzpMKYsCDxyef2uKRXMpzcqYzQ YlJQU1VGYCVd//bZ8uDP1wmEtgtu09/LDcjhrEIDha+KYpnBUjMHwH+xQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:31 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id b950d71c (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:13:02 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:29 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 6/8] fetch: move option related variables into main function 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 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 bcc156a9ce..97a510649c 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; static int git_fetch_config(const char *k, const char *v, void *cb) { @@ -160,92 +153,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) @@ -2145,13 +2052,109 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int cmd_fetch(int argc, const char **argv, const char *prefix) { - int i; const char *bundle_uri; + const char *submodule_prefix = ""; enum display_format display_format = DISPLAY_FORMAT_UNKNOWN; 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 Thu Apr 27 11:13:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225381 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 DD7D9C77B73 for ; Thu, 27 Apr 2023 11:13:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243675AbjD0LNt (ORCPT ); Thu, 27 Apr 2023 07:13:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57674 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243431AbjD0LNj (ORCPT ); Thu, 27 Apr 2023 07:13:39 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4227344B9 for ; Thu, 27 Apr 2023 04:13:37 -0700 (PDT) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id AFC3D5C01ED; Thu, 27 Apr 2023 07:13:36 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Thu, 27 Apr 2023 07:13:36 -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=1682594016; x=1682680416; bh=Wk 5xUhK6Ey2dS/9v4sBBQMtiDo0SF6wA2rIjgkeuxfU=; b=UwQTDckpMDAdfSivuP +5HwTTFB2fM9Iwsu0lkYNysfVNZJYsYpe7bWMCM+qeMp/F6TmkvsvSkc7eNLSKyq ZDty6+6hJGxkOItYva8YIGd0vdxtLVoTKs7RuAhfIVdZknP7Rd0/gnrGefg8g/sS 4FaW5hJuzC/6AZGqIDirgbpFX6uHICTiROrTIZlHz669FgIY8DMqipDE6ncXp1+t z+ZP10CZKlC1usXj/cVfjRZV6GJEFVnFYHw2UjNFbTRMcgAdcNSj/pWuBvxwA0cP yYQhsOAu+E56BRYHLvzeYvzGYWUJbqAn+6m7miI2Nvh9GtTey/7IKch5tIBwrB0o Eu6w== 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=1682594016; x=1682680416; bh=Wk5xUhK6Ey2dS /9v4sBBQMtiDo0SF6wA2rIjgkeuxfU=; b=gGYBW27N3ICIQBjS5G7iroix5TV8H OmR9c6OA2vnyQYskR/yZoe4ISq4vAEOkbZv2dPFr36M+U38kVcWBg9i6rlnMkP4s wTutMCLna7IVFv/cGvZNxrp4c0vKDC7hmipm7caQzN+UR+fPY+pOVtvsaObEQ7cf /AcevifjPIqdHx6+EJS9k7as2JmDPmvd6Lrjy7Tai6WQtz9WbIXOME6afJARGF+c /No7ERQWISXWbRVFUOLtKgphmNk04Z6UJ59aYF5ODA3c1720pdYus111WCFfSLRY Hd+6t/oxvOS0Bx7L9LBpIWFqOTbET+1ilomI6v58gZgsmnpzBevR0hAAg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:35 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id e25ea291 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:13:06 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:33 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 7/8] fetch: introduce new `--output-format` option Message-ID: <0335e5eeb4ded336c5ff7c8888c8aab9dfed2505.1682593865.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 It is only possible to configure the output format that git-fetch(1) uses by setting it via a config key. While this interface may be fine as long as we only have the current "full" and "compact" output formats, where it is unlikely that the user will have to change them regularly. But we're about to introduce a new machine-parseable interface where the current mechanism feels a little bit indirect and rigid. Introduce a new `--output-format` option that allows the user to change the desired format more directly. Signed-off-by: Patrick Steinhardt --- Documentation/fetch-options.txt | 5 +++ builtin/fetch.c | 48 ++++++++++++++++++---- t/t5574-fetch-output.sh | 72 +++++++++++++++++++++++++++------ 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 622bd84768..654f96f79d 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -78,6 +78,11 @@ linkgit:git-config[1]. --dry-run:: Show what would be done, without making any changes. +--output-format:: + Control how ref update status is printed. Valid values are + `full` and `compact`. Default value is `full`. See section + OUTPUT in linkgit:git-fetch[1] for detail. + ifndef::git-pull[] --[no-]write-fetch-head:: Write the list of remote refs fetched in the `FETCH_HEAD` diff --git a/builtin/fetch.c b/builtin/fetch.c index 97a510649c..30099b2ac3 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -52,6 +52,13 @@ enum display_format { DISPLAY_FORMAT_UNKNOWN = 0, DISPLAY_FORMAT_FULL, DISPLAY_FORMAT_COMPACT, + DISPLAY_FORMAT_MAX, +}; + +static const char * const display_formats[DISPLAY_FORMAT_MAX] = { + NULL, + "full", + "compact", }; struct display_state { @@ -1879,7 +1886,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; @@ -1894,6 +1902,9 @@ static int fetch_multiple(struct string_list *list, int max_children) "--no-write-commit-graph", NULL); add_options_to_argv(&argv); + if (format != DISPLAY_FORMAT_UNKNOWN) + strvec_pushf(&argv, "--output-format=%s", display_formats[format]); + if (max_children != 1 && list->nr != 1) { struct parallel_fetch_state state = { argv.v, list, 0, 0 }; const struct run_process_parallel_opts opts = { @@ -2050,6 +2061,29 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, return exit_code; } +static enum display_format parse_display_format(const char *format) +{ + for (int i = 0; i < ARRAY_SIZE(display_formats); i++) + if (display_formats[i] && !strcmp(display_formats[i], format)) + return i; + return DISPLAY_FORMAT_UNKNOWN; +} + +static int opt_parse_output_format(const struct option *opt, const char *arg, int unset) +{ + enum display_format *format = opt->value, parsed; + + if (unset || !arg) + return 1; + + parsed = parse_display_format(arg); + if (parsed == DISPLAY_FORMAT_UNKNOWN) + return error(_("unsupported output format '%s'"), arg); + *format = parsed; + + return 0; +} + int cmd_fetch(int argc, const char **argv, const char *prefix) { const char *bundle_uri; @@ -2102,6 +2136,8 @@ 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_CALLBACK(0, "output-format", &display_format, N_("format"), N_("output format"), + opt_parse_output_format), 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")), @@ -2181,11 +2217,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) const char *format = "full"; git_config_get_string_tmp("fetch.output", &format); - if (!strcasecmp(format, "full")) - display_format = DISPLAY_FORMAT_FULL; - else if (!strcasecmp(format, "compact")) - display_format = DISPLAY_FORMAT_COMPACT; - else + + display_format = parse_display_format(format); + if (display_format == DISPLAY_FORMAT_UNKNOWN) die(_("invalid value for '%s': '%s'"), "fetch.output", format); } @@ -2339,7 +2373,7 @@ 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, display_format); } diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index b9dcdade63..662c960f94 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -24,14 +24,37 @@ test_expect_success 'fetch with invalid output format configuration' ' test_cmp expect actual ' +test_expect_success 'fetch with invalid output format via command line' ' + test_must_fail git fetch --output-format >actual 2>&1 && + cat >expect <<-EOF && + error: option \`output-format${SQ} requires a value + EOF + test_cmp expect actual && + + test_must_fail git fetch --output-format= origin >actual 2>&1 && + cat >expect <<-EOF && + error: unsupported output format ${SQ}${SQ} + EOF + test_cmp expect actual && + + test_must_fail git fetch --output-format=garbage origin >actual 2>&1 && + cat >expect <<-EOF && + error: unsupported output format ${SQ}garbage${SQ} + EOF + test_cmp expect actual +' + test_expect_success 'fetch aligned output' ' - git clone . full-output && + test_when_finished "rm -rf full-cfg full-cli" && + git clone . full-cfg && + git clone . full-cli && test_commit looooooooooooong-tag && - ( - cd full-output && - git -c fetch.output=full fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && + + git -C full-cfg -c fetch.output=full fetch origin >actual-cfg 2>&1 && + git -C full-cli fetch --output-format=full origin >actual-cli 2>&1 && + test_cmp actual-cfg actual-cli && + + grep -e "->" actual-cfg | cut -c 22- >actual && cat >expect <<-\EOF && main -> origin/main looooooooooooong-tag -> looooooooooooong-tag @@ -40,13 +63,16 @@ test_expect_success 'fetch aligned output' ' ' test_expect_success 'fetch compact output' ' - git clone . compact && + test_when_finished "rm -rf compact-cfg compact-cli" && + git clone . compact-cli && + git clone . compact-cfg && test_commit extraaa && - ( - cd compact && - git -c fetch.output=compact fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && + + git -C compact-cfg -c fetch.output=compact fetch origin >actual-cfg 2>&1 && + git -C compact-cli fetch --output-format=compact origin >actual-cli 2>&1 && + test_cmp actual-cfg actual-cli && + + grep -e "->" actual-cfg | cut -c 22- >actual && cat >expect <<-\EOF && main -> origin/* extraaa -> * @@ -54,6 +80,28 @@ test_expect_success 'fetch compact output' ' test_cmp expect actual ' +test_expect_success 'fetch compact output with multiple remotes' ' + test_when_finished "rm -rf compact-cfg compact-cli" && + + git clone . compact-cli && + git -C compact-cli remote add second-remote "$PWD" && + git clone . compact-cfg && + git -C compact-cfg remote add second-remote "$PWD" && + test_commit multi-commit && + + git -C compact-cfg -c fetch.output=compact fetch --all >actual-cfg 2>&1 && + git -C compact-cli fetch --output-format=compact --all >actual-cli 2>&1 && + test_cmp actual-cfg actual-cli && + + grep -e "->" actual-cfg | cut -c 22- >actual && + cat >expect <<-\EOF && + main -> origin/* + multi-commit -> * + main -> second-remote/* + EOF + test_cmp expect actual +' + test_expect_success 'fetch output with HEAD and --dry-run' ' test_when_finished "rm -rf head" && git clone . head && From patchwork Thu Apr 27 11:13:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13225382 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 BD176C77B73 for ; Thu, 27 Apr 2023 11:14:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243698AbjD0LOA (ORCPT ); Thu, 27 Apr 2023 07:14:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243715AbjD0LNr (ORCPT ); Thu, 27 Apr 2023 07:13:47 -0400 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 141A05BB1 for ; Thu, 27 Apr 2023 04:13:42 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 821D45C023D; Thu, 27 Apr 2023 07:13:41 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 27 Apr 2023 07:13: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=1682594021; x=1682680421; bh=dA zXLKtxHaWSMz+0If6TCHCCexqwv7bMpfzg1V5L0O0=; b=kgO4tQEc2qWeAAoUaf soL8mbsxTfyliPQH91ajO2YKB4OLFUltLr+G6lQndq/FpSTKKFDZ49WbjceR7r5O cTxDnMuRwXFfsQH53M2WntehSHiMczBI4nmZtaPLEy/EjEQGV2aJx3I5enYrWaQA db0Qh+xxYTx8Uz5JBIHXAK6Esbzx65UnS6wOAmv8J0Hm/G9vBrdpRaNBBL5PgPcr XkKzOShEII3DRRsBpNpuRjQUy46Jop81ySQcUjpFHlUN4BtFkZuB9YmyCWoQzas4 fbXglR/brH+/QafZVIq0ZIA7lQPukXHLr2MBgffDD1SV5DdQvQhclsCDu1ri+Xrj jsyA== 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=1682594021; x=1682680421; bh=dAzXLKtxHaWSM z+0If6TCHCCexqwv7bMpfzg1V5L0O0=; b=IBGrdI6KD+Vc6Rj9qDJ/M3TFDljXU vNLDerXrSEwNeLXrS3vAsbWNgIOa4HkJVxI3JugetdrnM5S/cHRKJz/9tZyrMrj6 EdA0D61LfeWW5mi6G/ii7MbanKcDpXIXzIw9Gr6WkGZz2I6UeW/UcCuNG8ORzqwR 8IOE/gDnXy0+4uW2A7RPUqh6wU+dRtHzNc2zT4z5dG8NWDL0djyJ5F2ypvo598eo eCruN+OSid+cPrR8j5cZVggg+fXowGJvqoNwo0zFVhcpGvhgvEZ66jkhZQNlZPIT rluaHl4tNKQBeqszBNLzcRZGNI1caD82QUViTfv1KtVwmhlAStEm6IEGQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfeduiedgfeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesghdtreertddtvdenucfhrhhomheprfgrthhr ihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimheqnecuggftrfgrthhtvg hrnhepueektdevtdffveeljeetgfehheeigeekleduvdeffeeghefgledttdehjeelffet necuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 27 Apr 2023 07:13:39 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 4dab03d4 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Thu, 27 Apr 2023 11:13:11 +0000 (UTC) Date: Thu, 27 Apr 2023 13:13:38 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Junio C Hamano , Felipe Contreras , Glen Choo , Jonathan Tan , Jacob Keller Subject: [PATCH v2 8/8] 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. If usecases come up for this 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/config/fetch.txt | 4 +- Documentation/fetch-options.txt | 4 +- Documentation/git-fetch.txt | 17 ++++++- builtin/fetch.c | 47 +++++++++++++----- t/t5574-fetch-output.sh | 84 +++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 17 deletions(-) diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt index 568f0f75b3..70734226c0 100644 --- a/Documentation/config/fetch.txt +++ b/Documentation/config/fetch.txt @@ -52,8 +52,8 @@ fetch.pruneTags:: fetch.output:: Control how ref update status is printed. Valid values are - `full` and `compact`. Default value is `full`. See section - OUTPUT in linkgit:git-fetch[1] for detail. + `full`, `compact` and `porcelain`. Default value is `full`. + See section OUTPUT in linkgit:git-fetch[1] for detail. fetch.negotiationAlgorithm:: Control how information about the commits in the local repository diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 654f96f79d..5ca8a67fe8 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -80,8 +80,8 @@ linkgit:git-config[1]. --output-format:: Control how ref update status is printed. Valid values are - `full` and `compact`. Default value is `full`. See section - OUTPUT in linkgit:git-fetch[1] for detail. + `full`, `compact` and `porcelain`. Default value is `full`. + See section OUTPUT in linkgit:git-fetch[1] for detail. ifndef::git-pull[] --[no-]write-fetch-head:: diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index fba66f1460..efd22cd372 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -197,13 +197,26 @@ The output of "git fetch" depends on the transport method used; this section describes the output when fetching over the Git protocol (either locally or via ssh) and Smart HTTP protocol. -The status of the fetch is output in tabular form, with each line -representing the status of a single ref. Each line is of the form: +The output format can be chosen either via the `fetch.output` config +(see linkgit:git-config[1]), or via the `--output-format` switch. +Supported values include: + +For the `full` and `compact` output formats, the status of the fetch is +output in tabular, with each line representing the status of a single +ref. Each line is of the form: ------------------------------- -> [] ------------------------------- +The `porcelain` 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 30099b2ac3..abe6b8879d 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, DISPLAY_FORMAT_MAX, }; @@ -59,6 +60,7 @@ static const char * const display_formats[DISPLAY_FORMAT_MAX] = { NULL, "full", "compact", + "porcelain", }; struct display_state { @@ -752,8 +754,11 @@ static void display_state_init(struct display_state *display_state, struct ref * break; } + case DISPLAY_FORMAT_PORCELAIN: + /* We don't need to precompute anything here. */ + break; default: - BUG("unexpected display foramt %d", display_state->format); + BUG("unexpected display format %d", display_state->format); } } @@ -822,8 +827,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; @@ -856,12 +865,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, @@ -879,7 +893,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; } @@ -892,7 +907,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; } @@ -903,12 +919,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; } } @@ -941,7 +959,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; } @@ -963,7 +982,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) { @@ -975,12 +995,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; } } @@ -1221,7 +1243,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); } } } @@ -1361,6 +1385,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); } diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index 662c960f94..d88ad8af31 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -102,6 +102,72 @@ test_expect_success 'fetch compact output with multiple remotes' ' test_cmp expect actual ' +test_expect_success 'fetch porcelain output' ' + test_when_finished "rm -rf porcelain-cfg porcelain-cli" && + + # 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-cli && + git clone . porcelain-cfg && + git -C porcelain-cfg fetch origin $refspecs && + git -C porcelain-cli 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-cfg -c fetch.output=porcelain fetch --dry-run --prune origin $refspecs >actual-dry-run-cfg && + test_must_fail git -C porcelain-cli fetch --output-format=porcelain --dry-run --prune origin $refspecs >actual-dry-run-cli && + test_cmp actual-dry-run-cfg actual-dry-run-cli && + test_cmp expect actual-dry-run-cfg && + + # And now we perform a non-dry-run fetch. + test_must_fail git -C porcelain-cfg -c fetch.output=porcelain fetch --prune origin $refspecs >actual-cfg && + test_must_fail git -C porcelain-cli fetch --output-format=porcelain --prune origin $refspecs >actual-cli && + test_cmp actual-cfg actual-cli && + test_cmp expect actual-cfg && + + # Ensure that the dry-run and non-dry-run output matches. + test_cmp actual-dry-run-cfg actual-cfg +' + test_expect_success 'fetch output with HEAD and --dry-run' ' test_when_finished "rm -rf head" && git clone . head && @@ -127,6 +193,24 @@ test_expect_success 'fetch output with HEAD and --dry-run' ' test_cmp expect actual ' +test_expect_success 'fetch porcelain output with HEAD and --dry-run' ' + test_when_finished "rm -rf head" && + git clone . head && + COMMIT_ID=$(git rev-parse HEAD) && + + git -C head fetch --output-format=porcelain --dry-run origin HEAD >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID FETCH_HEAD + EOF + test_cmp expect actual && + + git -C head fetch --output-format=porcelain --dry-run origin HEAD:foo >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID refs/heads/foo + EOF + test_cmp expect actual +' + test_expect_success '--no-show-forced-updates' ' mkdir forced-updates && (