From patchwork Wed Apr 19 12:31:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216770 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 B4FB3C77B73 for ; Wed, 19 Apr 2023 12:32:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233314AbjDSMcA (ORCPT ); Wed, 19 Apr 2023 08:32:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50508 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233276AbjDSMbu (ORCPT ); Wed, 19 Apr 2023 08:31:50 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E24416B1F for ; Wed, 19 Apr 2023 05:31:32 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 88E63320005D; Wed, 19 Apr 2023 08:31:31 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Wed, 19 Apr 2023 08:31:31 -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=1681907490; x=1681993890; bh=EX kqlSAoEwBzSYVd3Wt8Qnb1bZB5P9tjg2P/qfwr94I=; b=pdshrNWdzFlCKikE6O XXg51XHZB4/9UkXtlbKyFjYGiRW8pGz1yzIdHmKeRGhmYBUXkCwWOpk/rBywCdF4 NvyjphL4ATK6wihwcpymGh4qTJq2qWgC5CjVg25XSFqce6fZ6Nt+WN5eH2pRdz8h fxtlR2ecUl7tjf52TH52gfFeRB3us1weTwkfG95LU19on8weFpvx4BKJiM+KJb1W /VnTyZ7BQ25blUsCeY3ZT06Ioh6O6hnGBtZtk4JVayBThJWS60pTwA8kjbaCB+fq lGrggXjLGSTrrrjNwxfz3epIeAEiZtWx7uHYJgLiOhpJVolVH0Y+ImWVoo27olyD t7Dg== 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=1681907490; x=1681993890; bh=EXkqlSAoEwBzS YVd3Wt8Qnb1bZB5P9tjg2P/qfwr94I=; b=LqzRqzrjft/5RuGCPQjxHcX8QKE63 3RTwIMAf/8R7CzS7lNpHCipFmDe7mmn7Jcv1QlXJdzQjfhhTmCh4xiw0dobglAJq k3DV5dumVVWPBWzsY+svAFwmbzkL8atHaEbtydTSVy4u1KfyUVdG0h89MG1893rb 8+pRIII6x//G15O57jOOOa/vZOjLgqyj4jZ2LYtmu4gXlT0cQHwqTHQqwq2XKVmA 2Zu2VFQEauuMOzyEW0m44KZcLxyNwY02WS6RqZTUiuUjw/m/5PAXyYoBKvh8nvCq wmfMIWGjeECssAfaGWzCvfw/mTPv8c8zuZMSl23fL2QN9Rm4hWSQATq5g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:29 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id bebc6d69 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:16 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:26 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 1/8] fetch: split out tests for output format Message-ID: <0d0d50d14c557f8313747e7d0e104c2c0819dab9.1681906948.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 Wed Apr 19 12:31:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216771 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 5ED28C6FD18 for ; Wed, 19 Apr 2023 12:32:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233339AbjDSMcC (ORCPT ); Wed, 19 Apr 2023 08:32:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233284AbjDSMbu (ORCPT ); Wed, 19 Apr 2023 08:31:50 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1A8115A02 for ; Wed, 19 Apr 2023 05:31:34 -0700 (PDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 438CB320093C; Wed, 19 Apr 2023 08:31:34 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Wed, 19 Apr 2023 08:31:34 -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=1681907493; x=1681993893; bh=f0 lY46jX/9ioKReivKjVaIlQtLCXt+4Vs3frBIihva0=; b=NSFXdOrxAgjT8azQU3 WSgN9BfKbzUZSxHinSFwzvjEGpUrvvlqo2AsndjuGGhogtEdPsig99V2BeewRjeo tuh2FWxme7V8+qTF7i4pyE4yhIQDNdjqK0xPftifEFVms+CkocMTPUTNa6b4C1/e dMlLw6WX4pZsn8Mnfcl7JfK8IIBD6EpXwHHayVGKxO3P/g4PtIcf/1YuWnzqIe1z RMHXr9Qfqt1PzzDfG6b2lSWlbNiLP6ZJsfc6WxjX8SP1tr8T1fl80v0U+DmmWOg8 Lno50KrzwrsExZPsEozQ15eofHmaFq9fszi5nrH8W3cMVL9Rqvj2uvqeFruHL9Tq kmcQ== 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=1681907493; x=1681993893; bh=f0lY46jX/9ioK ReivKjVaIlQtLCXt+4Vs3frBIihva0=; b=MR3UbSz4NvUen836jTvtl2wFPHtqM LCHBUOK5RzX0qnb+N+OFWHP4QJt3QFURtqdFB9cBFFzse4Z4k2rkMYvf3eLrirbr 18FK7qSP8lbH8FsGcUxCHLLvMwWE4jxoCROU5wFtlnLr0elYBOus5o0G7lpiEXsD Ig2Uvz6ogTqAPCRcSB6wZtQ/8ANUlTc0gTFO/F1AbKpj/p3qg+HPjwj1GbQgj6b4 4nIomtBjQkKG3iVd7wVPepf4YyDCafW805/sKtYG/Dd5kd7enWEPnQDw/8lgiYmV fj0g7xOJoWPSYXPeF9To0tAt+0dr3K+59mcxtXmzXbIXsj+Axc+vwBrRQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:33 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id a6e6a129 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:20 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:31 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 2/8] fetch: add a test to exercise invalid output formats Message-ID: <29d2c58914b7270a4603cd65565c06ff74355e96.1681906948.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 Wed Apr 19 12:31:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216772 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 D1AE4C77B73 for ; Wed, 19 Apr 2023 12:32:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233188AbjDSMcP (ORCPT ); Wed, 19 Apr 2023 08:32:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233331AbjDSMby (ORCPT ); Wed, 19 Apr 2023 08:31:54 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E102916DD6 for ; Wed, 19 Apr 2023 05:31:38 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 1B1C33200937; Wed, 19 Apr 2023 08:31:38 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 19 Apr 2023 08:31:38 -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=1681907497; x=1681993897; bh=Zz 2cabaXclVnL/zZPo/SpLNzTgDLgOWbLFQpPzOlKLM=; b=h3baep8WTHLCb1RM5z ogRF8U8kJGKhh+61Xh3KMOk9kl0sKYlldq1H8UAYlOyv93Z+XHMgjpAw1aWybeBI I6kFKX8NRsImFgLMDbiw7vd90AgQ5/R/X763yMHtAVb9g7E/HahkRW7U1Hx+agKo c/7c8J2+JGiBmylLVG/1Tbd5w+oynRu3LxAcgdRcLq8h/08WM8GfP7NLWBwejunG mMPutXuxDmep8aw0daI1wwG2ysXC9hKlP3fmQaKnqZsB+GxnYd6+hedZFE/OZM6r EhKIKhYiv18ucGiOM3sA3HvaHr1xK7ghgQNR88DynMVF56YOQ8oVOmiBD/4LU+22 YmFw== 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=1681907497; x=1681993897; bh=Zz2cabaXclVnL /zZPo/SpLNzTgDLgOWbLFQpPzOlKLM=; b=YQ87w99a0Zs6x5f9kRSo+xjtFyZQO 6bCBxHOOSzV9IZHyra67J2XBUQkVaCIbTpra07REYgr2dhd98H8pO/g6N8g8U2l9 I+hbIw7gCuVtuphgGeOmwVbhri+JyCRnVlgtDxWR1KKTApfH7xFTPXwCckytz9D4 xXdNo9r9e0ptyhByDWCZgiAhvyhQv7atCctdAj0lDNzM/XtKYig9RdFo1JKj2jJv 2c/HwA92EAavUGIRR9w3Z9jWJxWmbia+qgF+TyBLspTN2xR9QObaNGQwVdQ5/yEx 37MGJ/mLtFBoaRf024e+1/9BA+c5lyRLNrwbh5iNatttOKflt2k4QEO7A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeljeetffevheeggeetkeetieduieeiie egieegtdffheegkefhjeehfeekhfevleenucffohhmrghinhepghhithhhuhgsrdgtohhm necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepphhsse hpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:36 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 99cdbfe5 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:24 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:35 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 3/8] fetch: fix missing from-reference when fetching HEAD:foo Message-ID: <596e12f03a296d753ee6fe8face9522edc9e397e.1681906948.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 displaying reference updates, we print a line that looks similar to the following: ``` * branch master -> master ``` The "branch" bit changes depending on what kind of reference we're updating, while both of the right-hand references are computed by stripping well-known prefixes like "refs/heads/" or "refs/tags". The logic is kind of intertwined though and not easy to follow: we precompute both the kind (e.g. "branch") and the what, which is the abbreviated remote reference name, in `store_updated_refs()` and then pass it down the call chain to `display_ref_update()`. There is a set of different cases here: - When the remote reference name is "HEAD" we assume no kind and will thus instead print "[new ref]". We keep what at the empty string. - When the remote reference name has a well-known prefix then the kind would be "branch", "tag" or "remote-tracking branch". The what is the reference with the well-known prefix stripped and in fact matches the output that `prettify_refname()` would return. - Otherwise, we'll again assume no kind and keep the what set to the fully qualified reference name. Now there is a bug with the first case here, where the remote reference name is "HEAD". As noted, "what" will be set to the empty string. And that seems to be intentional because we also use this information to update the FETCH_HEAD, and in case we're updating HEAD we seemingly don't want to append that to our FETCH_HEAD value. But as mentioned, we also use this value to display reference updates. And while the call to `display_ref_update()` correctly figures out that we meant "HEAD" when `what` is empty, the call to `update_local_ref()` doesn't. `update_local_ref()` will then call `display_ref_update()` with the empty string and cause the following broken output: ``` $ git fetch --dry-run 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 work as expected: ``` $ git fetch --dry-run origin HEAD From https://github.com/git/git * branch HEAD -> FETCH_HEAD $ git fetch --dry-run origin master From https://github.com/git/git * branch master -> FETCH_HEAD * branch master -> origin/master ``` Fix this bug by instead unconditionally passing the full reference name to `display_ref_update()` which learns to call `prettify_refname()` on it. This does fix the above bug and is otherwise functionally the same as `prettify_refname()` would only ever strip the well-known prefixes just as intended. So 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 | 19 +++++++++++++++++++ 2 files changed, 38 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..55f0f05b6a 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -54,6 +54,25 @@ 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 --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 +' + test_expect_success '--no-show-forced-updates' ' mkdir forced-updates && ( From patchwork Wed Apr 19 12:31:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216773 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 23D2DC6FD18 for ; Wed, 19 Apr 2023 12:32:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233287AbjDSMc0 (ORCPT ); Wed, 19 Apr 2023 08:32:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51342 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233340AbjDSMcC (ORCPT ); Wed, 19 Apr 2023 08:32:02 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CA2ED3A91 for ; Wed, 19 Apr 2023 05:31:42 -0700 (PDT) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.west.internal (Postfix) with ESMTP id E2C2932005BC; Wed, 19 Apr 2023 08:31:41 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Wed, 19 Apr 2023 08:31:42 -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=1681907501; x=1681993901; bh=mm 6PKNyyYoj2jYr078aPB49Fz5/wmNwiE9w3CDe8spM=; b=YkMpRc8/zlJcPYpBxO ONthXhNEa7RuNPU51GLwnv1Cn1zMW7q3FnHlQj7PM6//GjE6ezkQrrZas0KYOPQj xffgS3rnLyHrpaYKntB574yC0z2OxPwh4MNG5FuxDN7zDFm8IgG/ZbsBp6ABPUqm n7g82iN9Rdc3fbmYv1i1wxXCaZHvrow+UtvWmnIZLzGi6yrJO+DCNku9n1Ii8/ij jh2Tyjq32WgS64GczcEaNO7hj+1w/+Mc66lUIpkhV+g1HHafVz26CKpifxroU3S5 2J5Zj+o3buhMxnotKo6APWQLm3HP26sBOEAhdfqvaG+9qYIj/XFXzqkv0jPnY93j IEZg== 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=1681907501; x=1681993901; bh=mm6PKNyyYoj2j Yr078aPB49Fz5/wmNwiE9w3CDe8spM=; b=Wzdf2BF20ANT7TDw0rDTnZxfCz48N 5g5cxjj5pY32t0BgJNUezAYdZ6swiwGl1xa/QQ/8w/JIR5Hl0ONbW4Cxgk0dIeDM j+CsmlBVnkAphITMO1rs3TXrzyKghg3PFH5Nr9g+7gGhuVH4OcLYCgo4enRwzJSS qkMWVPac4i9MiYyKlsvH9VwOQG/hgJmDJVkKLniWwbOVHrmItsfUdp6YdAXotPvI G4b5ncqHhgZrIZmVNZIpFXSFXbh9ZpNGVVoqmhrDpMgKOreMy4cG0KsNYOWqI125 2NiUdFmDExOTrf0cIBr7BI3LSD82OO09GY54tU+eeJqggkFj+BIfNrfBw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:40 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id f7fd668e (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:28 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:39 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 4/8] fetch: introduce `display_format` enum Message-ID: <8571363be1943ed12dd5295593509bae92194933.1681906948.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 | 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 Wed Apr 19 12:31:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216774 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 A06ACC6FD18 for ; Wed, 19 Apr 2023 12:32:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233312AbjDSMcf (ORCPT ); Wed, 19 Apr 2023 08:32:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233252AbjDSMcM (ORCPT ); Wed, 19 Apr 2023 08:32:12 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56C7116F82 for ; Wed, 19 Apr 2023 05:31:48 -0700 (PDT) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id B317A320092D; Wed, 19 Apr 2023 08:31:46 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Wed, 19 Apr 2023 08:31:46 -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=1681907506; x=1681993906; bh=PS n/Dyz8LJGa/2dDrbydOPuEBURUbhdA0f7gLLW+/gI=; b=Xb5tvIRSXgUMulmpwO Wjc73Yc8WL3ebeHTjC5Za3uses2o4ATar+XQt/2J4M9XrPSNZqXMsEfgNuZ3eslK aXov8yc4z79nxcp+pHu1Z9SN8H/DjBw1O1V/ZPtmINEiK7CT3N9B3uDtg96S3nOn GpCyWPZLso7biiC1zJmI8UC6Fi86HJnjXGeIffW03U1kIGoQoVzjTV7XHnnNZ7yB 3XajIoHKAKRkn+zMsZNiAi88mKZKxt4mCdXeRCNgW9pzx3C0sd0KEk06lBD3+0yF UwO0UUvR+aF+rnVEObjEk0RKJqbm+j5cZSwg/09N+Ko5AleyjYONYimovCoHnDbN EVlA== 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=1681907506; x=1681993906; bh=PSn/Dyz8LJGa/ 2dDrbydOPuEBURUbhdA0f7gLLW+/gI=; b=foh9khLiAHrAP7z8fpEA8oAhbKMM7 NKYtDgzBuwbDYj+nGK45R8o6SJoElr4eRM14PzgkJg+fKETNxdLZyq+AJ01qlg4/ Ngo1S5lr6f/1ibl7mXywROkp3gXbGNxxfxG5Q3XTiOzX9AafvDIwDMc33n/ypXq7 hliVfjZzODWMbMPU8kaxncCu/5PU5FlfQpgixF3MM4HJL/Xog7VEcjWdGvruhec4 Qoxlv5NlZYbmc9eKzm1twD/jlwEp8sXFye08HNV9t5WcY5GP3Dah59lUNPV+rKFf KvROTc2fPtS34Sv1Q66OLLIikPygpWyQpuTXTJ9Hnq5jd60dHDy5UOQvQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:45 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 047232c7 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:32 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:43 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 5/8] fetch: move display format parsing 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 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 Wed Apr 19 12:31:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216775 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 92188C6FD18 for ; Wed, 19 Apr 2023 12:32:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233326AbjDSMcl (ORCPT ); Wed, 19 Apr 2023 08:32:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50306 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232888AbjDSMcW (ORCPT ); Wed, 19 Apr 2023 08:32:22 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 014471444E for ; Wed, 19 Apr 2023 05:31:51 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 9B92D320005D; Wed, 19 Apr 2023 08:31:50 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Wed, 19 Apr 2023 08:31:50 -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=1681907510; x=1681993910; bh=dc aaVihIO0hHIWcxe9g49DuRBG/knwYTu2CMuvLVqP8=; b=CjBzDJsBrxwBvKr8T1 tEbGucFUCIaGmdI91Pvns9t/niaKAZTbds9fr7fXe8TOeG/Gfr1pDpchl5P+ynZ5 nZIrdzr3JVH7VusSf5lNf0trJfdbPc9rTh3ulnh1PsprR3K3WBOiwaj0Yl8TIsog dyBYrx72pjx//yn9dFSIFHzr9gv2uWKRS8F2HMH61dKy0LXcCusJn+ef8bc2k0gK 9Navt6CejOhuQsbAm/3GsR+PcX5QgfzxXQa6atSZOrz6NXGRclL8TyxLvRlf+xpo fsvSpIeJIY4DvpW+xOZtYTWYfIwmydswEHIXGDyEPVT8lfQnJgT4dDVBIW3tA5qt +JaA== 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=1681907510; x=1681993910; bh=dcaaVihIO0hHI Wcxe9g49DuRBG/knwYTu2CMuvLVqP8=; b=kQPOD6R62xzGWODq2i1Hhwbye3JBQ VzJJ9kOH8JXQo2D7EShf8VWOuIGSyRFKQHgJFJwdcaoNpzHQitA9Gbi6J1dcLMtL XtLI0hjYmmvOSzr2BfAbMZ7Q3423mqj7BYLm+EXMhG+nbQLM7nbFtjYx1aOBBnTC Np36oH/XslDfFG/bidnCWrSpRd5NnGkgY5h6Hgf1bHXL/nTgwLXQb+MFl8ro+4fV oWULTR4P7q7S0E/KEHI6hcn2cqW7hB8ZmSf+ZCbgSFCSX7UhypmH4tBYwR/5LO9q ZbinWoKiovD7PpwdMeBDyCtkzTaVqmDjvTJuFO7VeF1aAmM1XBcjbCmYA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:49 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 13e4a56b (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:36 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:47 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 6/8] fetch: move option related variables into main function Message-ID: <640a8840e1b87ec8ea985dd2299e1bab584d516d.1681906949.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 | 194 ++++++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 96 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index bcc156a9ce..81581b0033 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -79,9 +79,8 @@ static int all, append, dry_run, force, keep, multiple, 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,108 @@ 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 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 Apr 19 12:31:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216776 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 3D5B3C6FD18 for ; Wed, 19 Apr 2023 12:32:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233335AbjDSMcr (ORCPT ); Wed, 19 Apr 2023 08:32:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51342 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233285AbjDSMc0 (ORCPT ); Wed, 19 Apr 2023 08:32:26 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7FB6A167F7 for ; Wed, 19 Apr 2023 05:31:55 -0700 (PDT) Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 7220E32002E2; Wed, 19 Apr 2023 08:31:54 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute6.internal (MEProxy); Wed, 19 Apr 2023 08:31:54 -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=1681907514; x=1681993914; bh=dD MHPNvwaXQf4RY9h1marCRFPTtAg3XCiPzp/CyB9ss=; b=R71/Oo/wmEcm/iMyVU v1zsSPnQr69gHwGea5w5AUs4E0BeDT2PyYavo4lUjXMIPD+J6t3XR2aYRxY+2/yf e8OpQGIA46ULxN+y8mv1rLzDCVqn7Ar2iFjrcG56gsBGXEvNKjFGo1fX0N5GZRQ+ mhf1GNGbponrDPMAwbHNVSapbXSJz9CKOwR/ejTkjJ4IIPIhC+79UNeMt1DBPS8+ 8uogKmMxdWi4p6G/ZpAip0QJdMhX5I4OrWC+d5LHFqHUskE+kAsts2LtS21O2xiH uvOmxOijrWVf8wqORZghhLhan5rpzCvrKLkJo98yWFK0tLhhcAr8o3Vnh0I9I+jK KwPw== 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=1681907514; x=1681993914; bh=dDMHPNvwaXQf4 RY9h1marCRFPTtAg3XCiPzp/CyB9ss=; b=iiLAyEusbYGwafIPyHmMqib6DsOiT eRlicC2uzf3GK/dhMGt4PczFuqWFUgloNOZYgpZxmR3HtVgrkZxItEmXrNdoTQHX X8OItkUmdCXldaYrr0zEtBCjmHgVUJplpkam6X9GfX9W1cer5xtFTeq1bH4z9Fg8 hj++OpbJfBk2ltMQss9ri5yxIqu3+G6+rRv+d81RKn8ApaTV7TCBEMeNE47vyngV X3OEMd1WMTQ1+SdAnq3ZmO3QSyDJu4tP4a00UQyYYjEGu3+X8NH4cvH9RfRlXKof 67w6EzNCxQSwXsH6/IXELmxPEOAqJe/x/Y+U3tO+L61JQW/6dClgVZWPA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:53 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id 7d198abb (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:40 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:51 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 7/8] fetch: introduce new `--output-format` option Message-ID: <3b2cad066a3b3446fc335d6944a62bf79b0779bb.1681906949.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 output format more directly. Signed-off-by: Patrick Steinhardt --- Documentation/fetch-options.txt | 5 ++++ builtin/fetch.c | 17 +++++++++++ t/t5574-fetch-output.sh | 50 +++++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 12 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 81581b0033..22ba75a958 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -2050,6 +2050,21 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, return exit_code; } +static int opt_parse_output_format(const struct option *opt, const char *arg, int unset) +{ + enum display_format *format = opt->value; + if (unset || !arg) + return 1; + else if (!strcmp(arg, "full")) + *format = DISPLAY_FORMAT_FULL; + else if (!strcmp(arg, "compact")) + *format = DISPLAY_FORMAT_COMPACT; + else + return error(_("unsupported output format '%s'"), arg); + + return 0; +} + int cmd_fetch(int argc, const char **argv, const char *prefix) { const char *bundle_uri; @@ -2101,6 +2116,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")), diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index 55f0f05b6a..5144d5ed21 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 -> * From patchwork Wed Apr 19 12:31:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13216777 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 E14C7C77B73 for ; Wed, 19 Apr 2023 12:32:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233262AbjDSMc5 (ORCPT ); Wed, 19 Apr 2023 08:32:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52326 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233316AbjDSMci (ORCPT ); Wed, 19 Apr 2023 08:32:38 -0400 Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0F924167F3 for ; Wed, 19 Apr 2023 05:32:01 -0700 (PDT) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 6684432005C1; Wed, 19 Apr 2023 08:31:58 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Wed, 19 Apr 2023 08:31:58 -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=1681907518; x=1681993918; bh=4j Km3COaVfcWMPsVHEsG8aIlM26R/58ojhp2L+Y18wU=; b=aktVzpeWSgLTK8CEd9 VzRiNhXzpk0qr4O031wTtYWsnTY+deWVFmZJ/Zc8hWaOAlhBmjenpVQPDbP/emds OB4xrx45HQ3LDevfwtgiN0b6kz/cLM5bS0qUtKnjms3vBg4maPzcQAUTS7ggKFjK 0d8eDW7/pPUYUS3YhSHJcE9m9LV5mp1Hfx//h2JaR0Pt6MEOqg8fs1RsEw7oJ2/t +88GUk6yDKYYvGzd/3yd0OvuMonlqcudjJfeCI9WUeMF/RZR4w80xX5l/hwZ8EX8 d2gxdlCVXL36oEInMsOttJ4a0vtNOZscDpQLj0NazfUf4IdRqJG9o0sBgPTojfqQ QgiA== 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=1681907518; x=1681993918; bh=4jKm3COaVfcWM PsVHEsG8aIlM26R/58ojhp2L+Y18wU=; b=X3JRne+quAVltUrVQcJhyRil0wZF3 pGdV4PidZOTB8W9YinCwkuRvt5y3dnxN+ljeTX4haD9/Kzy6aCz15sWQRo+SIRdK TkoQj7s+Ium8oNCqpJmcFM7OSuX+zQgWuK20Ydybc18XKcsWm8GqHC3Qyw7x8IlO sVXfUvZo+xk9KhOrUDGgH+QQWC3UqXvaZrMUrsK0yXaiZm8yLB3VxIbRvzP/7RbU 8+Uy0hoFeznhuju/iE2i5osWtLNRqqFYsgEDbo1k/iTn+ZFzpMDujLfxoB78p0re SuZm4GF40cBhOmVu+fVxL3TrF0o9Pdtqaxjwm5jF5eIwp3jQIWPwVjeTw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrfedttddgheefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehgtd erredttddvnecuhfhrohhmpefrrghtrhhitghkucfuthgvihhnhhgrrhguthcuoehpshes phhkshdrihhmqeenucggtffrrghtthgvrhhnpeeukedtvedtffevleejtefgheehieegke eluddvfeefgeehgfeltddtheejleffteenucevlhhushhtvghrufhiiigvpedunecurfgr rhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 19 Apr 2023 08:31:56 -0400 (EDT) Received: by pks.im (OpenSMTPD) with ESMTPSA id e6b34094 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 19 Apr 2023 12:31:44 +0000 (UTC) Date: Wed, 19 Apr 2023 14:31:55 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Jonathan Tan Subject: [PATCH 8/8] fetch: introduce machine-parseable "porcelain" output format Message-ID: <301138da039451519c6e60d6126e7756a54d346f.1681906949.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 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. Signed-off-by: Patrick Steinhardt --- Documentation/config/fetch.txt | 4 +- Documentation/fetch-options.txt | 4 +- Documentation/git-fetch.txt | 17 ++++++- builtin/fetch.c | 50 +++++++++++++++----- t/t5574-fetch-output.sh | 84 +++++++++++++++++++++++++++++++++ 5 files changed, 142 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 22ba75a958..a99e24448b 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 { @@ -745,8 +746,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); } } @@ -815,8 +819,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; @@ -849,12 +857,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, @@ -872,7 +885,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; } @@ -885,7 +899,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; } @@ -896,12 +911,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; } } @@ -934,7 +951,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; } @@ -956,7 +974,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) { @@ -968,12 +987,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; } } @@ -1214,7 +1235,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); } } } @@ -1354,6 +1377,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); } @@ -2059,6 +2083,8 @@ static int opt_parse_output_format(const struct option *opt, const char *arg, in *format = DISPLAY_FORMAT_FULL; else if (!strcmp(arg, "compact")) *format = DISPLAY_FORMAT_COMPACT; + else if (!strcmp(arg, "porcelain")) + *format = DISPLAY_FORMAT_PORCELAIN; else return error(_("unsupported output format '%s'"), arg); @@ -2201,6 +2227,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) display_format = DISPLAY_FORMAT_FULL; else if (!strcasecmp(format, "compact")) display_format = DISPLAY_FORMAT_COMPACT; + else if (!strcasecmp(format, "porcelain")) + display_format = DISPLAY_FORMAT_PORCELAIN; else die(_("invalid value for '%s': '%s'"), "fetch.output", format); diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh index 5144d5ed21..28d02a93e4 100755 --- a/t/t5574-fetch-output.sh +++ b/t/t5574-fetch-output.sh @@ -80,6 +80,72 @@ test_expect_success 'fetch compact output' ' 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 && @@ -99,6 +165,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 && (