From patchwork Wed Sep 16 02:08:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lipman X-Patchwork-Id: 11778687 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EA5C259D for ; Wed, 16 Sep 2020 02:09:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CA7F320BED for ; Wed, 16 Sep 2020 02:09:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pSe9CgDt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726153AbgIPCJW (ORCPT ); Tue, 15 Sep 2020 22:09:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726039AbgIPCJU (ORCPT ); Tue, 15 Sep 2020 22:09:20 -0400 Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D2E87C06174A for ; Tue, 15 Sep 2020 19:09:19 -0700 (PDT) Received: by mail-qt1-x843.google.com with SMTP id g3so4951236qtq.10 for ; Tue, 15 Sep 2020 19:09:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=f9eKDJy4hWkm3jAbJQ2aVJclDrVaJIewda3Pxwtaktg=; b=pSe9CgDt4Pb6T7jZts+K266rFCHYhJiOvjLzHgbhV9DlJbbTL/Q6JSdFitUHcv6Lkf yeYzZjQ2qwIj+pUsnPieP4OImFn0Tw5FLNdxJsu7iImSU2bCqZEsrrExGK6pVtvJEFOi d0uI15srx4Gw/NJ+KUBI4Y7+GaDDX5gKBiw8BRWZFrnnz8hi3cbZLCFROqfHB5iDRXfU btnf3CgNgaQgUuyX2oCE34KE0PWf4ItiNM+LU8b8EgHPzqqoKxEk/XsD109MX19tOkJS wYrSbJS+zTolcF/gA345CrxASw5yVHmY21Ll+7a8w//g0r6zDEUfGvJxz5igb6TH66fd p7AA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=f9eKDJy4hWkm3jAbJQ2aVJclDrVaJIewda3Pxwtaktg=; b=oMEwcyRq/4DfPubSV7+hjsmjt9elAU1XDfc6tqZklmSemccv5NX/rMqQE67AVwDIJZ 2H/xlowlw83/jFDX150P0P0SbNcJ0g5k+T7PK8Gnd6GBAZrAzBvrptlFoqQ7/dWSjf1T Liao4I5MbB49OcMtj8ab7YVnMjiN0I39c5+PcIFgSp+1pdNuYaQPKVk3biNmuHGgYj4J qLirEWt1XfxQ6lLWxr6YhgNcqw9PmKVNofLwE69WQKt+Uuq0dTbjN08cCCbSrf4Eta1u yd7Hlp70Wr3HRuwr5jau7tI57dZ3Crk5J0a2QNDj0hJvLHjO6YtJicqltE9nCwRwXEgT ngEQ== X-Gm-Message-State: AOAM533/Gm+f1659eHEuBHaJdkxy1Xr7bWwKRKk+vY1rwy7/83L9tM98 i0fIr9iCijk+vrl2q7MQKhLlOWqAKIzTqmtz X-Google-Smtp-Source: ABdhPJwdxRHkSm7ulFuFWu/ftiqwdIpl70Kn6hagKb6Zb/KgKYVuVZ2hH7GuRnX6KSOOrFfB0uP14Q== X-Received: by 2002:ac8:17d9:: with SMTP id r25mr15860424qtk.107.1600222158886; Tue, 15 Sep 2020 19:09:18 -0700 (PDT) Received: from localhost.localdomain (c-98-229-3-81.hsd1.vt.comcast.net. [98.229.3.81]) by smtp.gmail.com with ESMTPSA id k52sm19380373qtc.56.2020.09.15.19.09.18 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 15 Sep 2020 19:09:18 -0700 (PDT) From: Aaron Lipman To: git@vger.kernel.org Cc: Aaron Lipman Subject: [PATCH v4 1/3] t3201: test multiple branch filter combinations Date: Tue, 15 Sep 2020 22:08:38 -0400 Message-Id: <20200916020840.84892-2-alipman88@gmail.com> X-Mailer: git-send-email 2.24.3 (Apple Git-128) In-Reply-To: <20200916020840.84892-1-alipman88@gmail.com> References: <20200913193140.66906-1-alipman88@gmail.com> <20200916020840.84892-1-alipman88@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Add tests covering the behavior of passing multiple contains/no-contains filters to git branch, e.g.: $ git branch --contains feature_a --contains feature_b $ git branch --no-contains feature_a --no-contains feature_b When passed more than one contains (or no-contains) filter, the tips of the branches returned must be reachable from any of the contains commits and from none of the the no-contains commits. This logic is useful to describe prior to enabling multiple merged/no-merged filters, so that future tests will demonstrate consistent behavior between merged/no-merged and contains/no-contains filters. Signed-off-by: Aaron Lipman --- t/t3201-branch-contains.sh | 47 +++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 40251c9f8f..3cb9dc6cca 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -171,6 +171,42 @@ test_expect_success 'Assert that --contains only works on commits, not trees & b test_must_fail git branch --no-contains $blob ' +test_expect_success 'multiple branch --contains' ' + git checkout -b side2 master && + >feature && + git add feature && + git commit -m "add feature" && + git checkout -b next master && + git merge side && + git branch --contains side --contains side2 >actual && + cat >expect <<-\EOF && + * next + side + side2 + EOF + test_cmp expect actual +' + +test_expect_success 'multiple branch --no-contains' ' + git branch --no-contains side --no-contains side2 >actual && + cat >expect <<-\EOF && + master + EOF + test_cmp expect actual +' + +test_expect_success 'branch --contains combined with --no-contains' ' + git checkout -b seen master && + git merge side && + git merge side2 && + git branch --contains side --no-contains side2 >actual && + cat >expect <<-\EOF && + next + side + EOF + test_cmp expect actual +' + # We want to set up a case where the walk for the tracking info # of one branch crosses the tip of another branch (and make sure # that the latter walk does not mess up our flag to see if it was @@ -200,15 +236,4 @@ test_expect_success 'branch --merged with --verbose' ' test_i18ncmp expect actual ' -test_expect_success 'branch --contains combined with --no-contains' ' - git branch --contains zzz --no-contains topic >actual && - cat >expect <<-\EOF && - master - side - zzz - EOF - test_cmp expect actual - -' - test_done From patchwork Wed Sep 16 02:08:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lipman X-Patchwork-Id: 11778689 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B4157618 for ; Wed, 16 Sep 2020 02:09:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 988AB20BED for ; Wed, 16 Sep 2020 02:09:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hMzvCiUL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726171AbgIPCJa (ORCPT ); Tue, 15 Sep 2020 22:09:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58844 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726125AbgIPCJW (ORCPT ); Tue, 15 Sep 2020 22:09:22 -0400 Received: from mail-qt1-x829.google.com (mail-qt1-x829.google.com [IPv6:2607:f8b0:4864:20::829]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF7F6C06174A for ; Tue, 15 Sep 2020 19:09:21 -0700 (PDT) Received: by mail-qt1-x829.google.com with SMTP id h6so4974285qtd.6 for ; Tue, 15 Sep 2020 19:09:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sCX8i/EMiMuJdCHdZEBkSX3WgPzjDZBzpvo+UKtcuwU=; b=hMzvCiUL5NAu0uGZ11sR/uo8e4aLQu5MAFYNzQkSqb7cADN/4i+gJpnV1G/5PDBMdt fbifhWmcKe6MVrTYOObUwn6uSykg3qjblE28BtlRXIrXM3KjZ5gBpXZYagnAULX+GCJo NBv39IVUTn9x53iXujzip4HgUNiPv0HoguQ8RnyHQiR3RjclJktHWIV39D4zy5mo8gfn n0/m5KeADmuSPrRsJvBZR5ysOwQHa89YnVXZd6SXO8hI4VGNCPPaUlqGA5OCSLA2qpaL Xl48/8eL/6X/oH2HmS7H7TBzQAtYEaRFCIq7OLjfBwhyr+811hhYebTVEmGKrarsmxT6 NlMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sCX8i/EMiMuJdCHdZEBkSX3WgPzjDZBzpvo+UKtcuwU=; b=EpnslHu8UL3nHFpC1LNhCoTac+n5bqHyvrzIaoHhJxWFeH3K6p/ocP80ZJs2LfIkLh Vfi/T7VvPihd/U2uvrMU+Va9kso9DthRqBnPuSBcHhAQ6iIlApeY6Be/lnchxvj5ZTYw rsOrx8p0eCeiJwID1DgrZrLP33nvJI9sykcqlGN0L86SblS2wpoEfrjyXqwgJKeNt7kl sgMe9GBbE073y0064v0jwWSG+xB6/OZzc2y/tDL7bifMiFo/A2pUJ64PuaRRmKxmoTH8 U2hnzixcMRJK5ibFfspmJ+iBvAgd6dgF8+KApn4V9gHLasYVlp7CW2VJBMM0J5zln46f X3Jg== X-Gm-Message-State: AOAM530guIxMOFJg3hVp3zHzS4KBXOZqhJZXp3UxzbkhnydPVjhXXlCo fuQXczc9u75OsKPjsgZRhrJRElCDq0yNHcIe X-Google-Smtp-Source: ABdhPJzGe9kY9RJ2sbeqCyteeMdy3xkXnXbO0jDQs8Gg+7JsaxiMX4crryJpqfj+dDeArpfDfqbXLA== X-Received: by 2002:aed:2767:: with SMTP id n94mr21683854qtd.237.1600222160920; Tue, 15 Sep 2020 19:09:20 -0700 (PDT) Received: from localhost.localdomain (c-98-229-3-81.hsd1.vt.comcast.net. [98.229.3.81]) by smtp.gmail.com with ESMTPSA id k52sm19380373qtc.56.2020.09.15.19.09.20 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 15 Sep 2020 19:09:20 -0700 (PDT) From: Aaron Lipman To: git@vger.kernel.org Cc: Aaron Lipman Subject: [PATCH v4 2/3] Doc: cover multiple contains/no-contains filters Date: Tue, 15 Sep 2020 22:08:39 -0400 Message-Id: <20200916020840.84892-3-alipman88@gmail.com> X-Mailer: git-send-email 2.24.3 (Apple Git-128) In-Reply-To: <20200916020840.84892-1-alipman88@gmail.com> References: <20200913193140.66906-1-alipman88@gmail.com> <20200916020840.84892-1-alipman88@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Update documentation for "git branch", "git for-each-ref" and "git tag" with notes explaining what happens when passed multiple --contains or --no-contains filters. This behavior is useful to document prior to enabling multiple merged/no-merged filters, in order to demonstrate consistent behavior between merged/no-merged and contains/no-contains filters. Signed-off-by: Aaron Lipman --- Documentation/filters.txt | 3 +++ Documentation/git-branch.txt | 2 ++ Documentation/git-for-each-ref.txt | 5 +++++ Documentation/git-tag.txt | 5 +++++ 4 files changed, 15 insertions(+) create mode 100644 Documentation/filters.txt diff --git a/Documentation/filters.txt b/Documentation/filters.txt new file mode 100644 index 0000000000..4ee17afc01 --- /dev/null +++ b/Documentation/filters.txt @@ -0,0 +1,3 @@ +When combining multiple `--contains` and `--no-contains` filters, only +references that contain at least one of the `--contains` commits and +contain none of the `--no-contains` commits are shown. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 03c0824d52..aa5e4da142 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -370,6 +370,8 @@ serve four related but different purposes: - `--no-merged` is used to find branches which are candidates for merging into HEAD, since those branches are not fully contained by HEAD. +include::filters.txt[] + SEE ALSO -------- linkgit:git-check-ref-format[1], diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 616ce46087..c207ed9551 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -408,6 +408,11 @@ Note also that multiple copies of an object may be present in the object database; in this case, it is undefined which copy's size or delta base will be reported. +NOTES +----- + +include::filters.txt[] + SEE ALSO -------- linkgit:git-show-ref[1] diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index f6d9791780..dadbd71d62 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -377,6 +377,11 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1 include::date-formats.txt[] +NOTES +----- + +include::filters.txt[] + SEE ALSO -------- linkgit:git-check-ref-format[1]. From patchwork Wed Sep 16 02:08:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lipman X-Patchwork-Id: 11778691 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2DF7B618 for ; Wed, 16 Sep 2020 02:09:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0341720BED for ; Wed, 16 Sep 2020 02:09:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Y2ELrmLh" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726192AbgIPCJe (ORCPT ); Tue, 15 Sep 2020 22:09:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726155AbgIPCJZ (ORCPT ); Tue, 15 Sep 2020 22:09:25 -0400 Received: from mail-qv1-xf2e.google.com (mail-qv1-xf2e.google.com [IPv6:2607:f8b0:4864:20::f2e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 361DAC061788 for ; Tue, 15 Sep 2020 19:09:25 -0700 (PDT) Received: by mail-qv1-xf2e.google.com with SMTP id b13so2796350qvl.2 for ; Tue, 15 Sep 2020 19:09:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=j3GkaB3U0fkyFxwRPtK0wnejfYC7QOOh5EhGZhYoi1M=; b=Y2ELrmLhY9ch4sJZsY0K6V9/6eRUuwo6d4afr/THC5QuBSUWkzxR/ge1FycmWkxouM liTTXID/xQurN6lf2mE75CRt95KyVOZ8LaUkyxJGTWB3Np1SEx0RQ3YVGOCPuWT0r9V/ gvkjeGboCpjHPuMaULB9n7hwE/XnsO7hIOv79Md0+mj40sGiE1FxcmHpSDaA3db8YAIT vLtK7g+B2E9z6smYi3McnSVu6+LGCWeIvmJ4uj530FxYF/lms1IK9YQNpJ0L5HNToHpi 4fGqPznMDejH6mzLXNVmdfUh7QOTXAl7yjA0rMx33OhU+CxrsJ2lzT2zDtfU1De2SKj4 vTLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=j3GkaB3U0fkyFxwRPtK0wnejfYC7QOOh5EhGZhYoi1M=; b=DrKkMV22eiwhsYgRMWnb93pwD44u5oiOCGDQUIMcEQ/4xpLebYJ/h1Bd9ivEi2qSUv sB0IQlDg2dmfQrBENKD/6e5V86UYfk2xobB4pBtgaDWK8C7eg3JLcdmctzWCne8Ehor0 50Z8AKLOIY6UeGFeylkjZw4po2KwBZO8dMSrI+8R7HIWxNDgNB6t4+C0pR8fYx0EdquP FzDf8502jfjMkYdkE/NtUO7s/H1f+yNkFs+YqorA/poxEQKOtD+weQ8TYlpnEV5i0sAi egyMZVZdj9R/wnzZKOMuJ5h/VjZDJlTAXEqXFEQv7Bwd87v3UZsaFCBpzlcvxUdHhlMV MT+Q== X-Gm-Message-State: AOAM533UGdym6seXnobjiRvPOnK5bEHYvAu8GWlctoVK0vdUbn7Q+315 YborgbBekwQRFWTr3h2PwYVyvGZTE56WG7CQ X-Google-Smtp-Source: ABdhPJxxzIMLuT5gWneBGDDlMaUG/qO1ZgosJKRMD2Z6GWI9Nwt/vafnWHgBnR4Z+3lRmCuiMY3RNw== X-Received: by 2002:a0c:c543:: with SMTP id y3mr4651630qvi.47.1600222163126; Tue, 15 Sep 2020 19:09:23 -0700 (PDT) Received: from localhost.localdomain (c-98-229-3-81.hsd1.vt.comcast.net. [98.229.3.81]) by smtp.gmail.com with ESMTPSA id k52sm19380373qtc.56.2020.09.15.19.09.22 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 15 Sep 2020 19:09:22 -0700 (PDT) From: Aaron Lipman To: git@vger.kernel.org Cc: Aaron Lipman Subject: [PATCH v4 3/3] ref-filter: allow merged and no-merged filters Date: Tue, 15 Sep 2020 22:08:40 -0400 Message-Id: <20200916020840.84892-4-alipman88@gmail.com> X-Mailer: git-send-email 2.24.3 (Apple Git-128) In-Reply-To: <20200916020840.84892-1-alipman88@gmail.com> References: <20200913193140.66906-1-alipman88@gmail.com> <20200916020840.84892-1-alipman88@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Enable ref-filter to process multiple merged and no-merged filters, and extend functionality to git branch, git tag and git for-each-ref. This provides an easy way to check for branches that are "graduation candidates:" $ git branch --no-merged master --merged next If passed more than one merged (or more than one no-merged) filter, refs must be reachable from any one of the merged commits, and reachable from none of the no-merged commits. Signed-off-by: Aaron Lipman --- Documentation/filters.txt | 4 ++ Documentation/git-branch.txt | 8 ++-- Documentation/git-for-each-ref.txt | 8 ++-- Documentation/git-tag.txt | 6 +-- builtin/branch.c | 6 +-- builtin/for-each-ref.c | 2 +- builtin/tag.c | 8 ++-- ref-filter.c | 64 ++++++++++++++++-------------- ref-filter.h | 12 +++--- t/t3200-branch.sh | 4 -- t/t3201-branch-contains.sh | 27 +++++++++++++ t/t6302-for-each-ref-filter.sh | 4 +- t/t7004-tag.sh | 4 +- 13 files changed, 92 insertions(+), 65 deletions(-) diff --git a/Documentation/filters.txt b/Documentation/filters.txt index 4ee17afc01..9bae46d84c 100644 --- a/Documentation/filters.txt +++ b/Documentation/filters.txt @@ -1,3 +1,7 @@ When combining multiple `--contains` and `--no-contains` filters, only references that contain at least one of the `--contains` commits and contain none of the `--no-contains` commits are shown. + +When combining multiple `--merged` and `--no-merged` filters, only +references that are reachable from at least one of the `--merged` +commits and from none of the `--no-merged` commits are shown. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index aa5e4da142..290b90639c 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -11,7 +11,7 @@ SYNOPSIS 'git branch' [--color[=] | --no-color] [--show-current] [-v [--abbrev= | --no-abbrev]] [--column[=] | --no-column] [--sort=] - [(--merged | --no-merged) []] + [--merged []] [--no-merged []] [--contains []] [--no-contains []] [--points-at ] [--format=] [(-r | --remotes) | (-a | --all)] @@ -252,13 +252,11 @@ start-point is either a local or remote-tracking branch. --merged []:: Only list branches whose tips are reachable from the - specified commit (HEAD if not specified). Implies `--list`, - incompatible with `--no-merged`. + specified commit (HEAD if not specified). Implies `--list`. --no-merged []:: Only list branches whose tips are not reachable from the - specified commit (HEAD if not specified). Implies `--list`, - incompatible with `--merged`. + specified commit (HEAD if not specified). Implies `--list`. :: The name of the branch to create or delete. diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index c207ed9551..7b9cf0ef1f 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -11,7 +11,7 @@ SYNOPSIS 'git for-each-ref' [--count=] [--shell|--perl|--python|--tcl] [(--sort=)...] [--format=] [...] [--points-at=] - (--merged[=] | --no-merged[=]) + [--merged[=]] [--no-merged[=]] [--contains[=]] [--no-contains[=]] DESCRIPTION @@ -76,13 +76,11 @@ OPTIONS --merged[=]:: Only list refs whose tips are reachable from the - specified commit (HEAD if not specified), - incompatible with `--no-merged`. + specified commit (HEAD if not specified). --no-merged[=]:: Only list refs whose tips are not reachable from the - specified commit (HEAD if not specified), - incompatible with `--merged`. + specified commit (HEAD if not specified). --contains[=]:: Only list refs which contain the specified commit (HEAD if not diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index dadbd71d62..cc667d7d01 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -15,7 +15,7 @@ SYNOPSIS 'git tag' [-n[]] -l [--contains ] [--no-contains ] [--points-at ] [--column[=] | --no-column] [--create-reflog] [--sort=] [--format=] - [--[no-]merged []] [...] + [--merged ] [--no-merged ] [...] 'git tag' -v [--format=] ... DESCRIPTION @@ -149,11 +149,11 @@ This option is only applicable when listing tags without annotation lines. --merged []:: Only list tags whose commits are reachable from the specified - commit (`HEAD` if not specified), incompatible with `--no-merged`. + commit (`HEAD` if not specified). --no-merged []:: Only list tags whose commits are not reachable from the specified - commit (`HEAD` if not specified), incompatible with `--merged`. + commit (`HEAD` if not specified). --points-at :: Only list tags of the given object (HEAD if not diff --git a/builtin/branch.c b/builtin/branch.c index e82301fb1b..efb30b8820 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -26,7 +26,7 @@ #include "commit-reach.h" static const char * const builtin_branch_usage[] = { - N_("git branch [] [-r | -a] [--merged | --no-merged]"), + N_("git branch [] [-r | -a] [--merged] [--no-merged]"), N_("git branch [] [-l] [-f] []"), N_("git branch [] [-r] (-d | -D) ..."), N_("git branch [] (-m | -M) [] "), @@ -688,8 +688,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) !show_current && !unset_upstream && argc == 0) list = 1; - if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr || - filter.no_commit) + if (filter.with_commit || filter.no_commit || + filter.reachable_from || filter.unreachable_from || filter.points_at.nr) list = 1; if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current + diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 57489e4eab..9d1ecda2b8 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -9,7 +9,7 @@ static char const * const for_each_ref_usage[] = { N_("git for-each-ref [] []"), N_("git for-each-ref [--points-at ]"), - N_("git for-each-ref [(--merged | --no-merged) []]"), + N_("git for-each-ref [--merged []] [--no-merged []]"), N_("git for-each-ref [--contains []] [--no-contains []]"), NULL }; diff --git a/builtin/tag.c b/builtin/tag.c index 5cbd80dc3e..ecf011776d 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -26,7 +26,7 @@ static const char * const git_tag_usage[] = { "\t\t []"), N_("git tag -d ..."), N_("git tag -l [-n[]] [--contains ] [--no-contains ] [--points-at ]\n" - "\t\t[--format=] [--[no-]merged []] [...]"), + "\t\t[--format=] [--merged ] [--no-merged ] [...]"), N_("git tag -v [--format=] ..."), NULL }; @@ -457,8 +457,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (argc == 0) cmdmode = 'l'; else if (filter.with_commit || filter.no_commit || - filter.points_at.nr || filter.merge_commit || - filter.lines != -1) + filter.reachable_from || filter.unreachable_from || + filter.points_at.nr || filter.lines != -1) cmdmode = 'l'; } @@ -509,7 +509,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die(_("--no-contains option is only allowed in list mode")); if (filter.points_at.nr) die(_("--points-at option is only allowed in list mode")); - if (filter.merge_commit) + if (filter.reachable_from || filter.unreachable_from) die(_("--merged and --no-merged options are only allowed in list mode")); if (cmdmode == 'd') return for_each_tag_name(argv, delete_tag, NULL); diff --git a/ref-filter.c b/ref-filter.c index 110bcd741a..785785a757 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2167,9 +2167,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * obtain the commit using the 'oid' available and discard all * non-commits early. The actual filtering is done later. */ - if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { - commit = lookup_commit_reference_gently(the_repository, oid, - 1); + if (filter->reachable_from || filter->unreachable_from || + filter->with_commit || filter->no_commit || filter->verbose) { + commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!commit) return 0; /* We perform the filtering for the '--contains' option... */ @@ -2231,13 +2231,20 @@ void ref_array_clear(struct ref_array *array) } } -static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) +static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata, int reachable) { struct rev_info revs; int i, old_nr; - struct ref_filter *filter = ref_cbdata->filter; struct ref_array *array = ref_cbdata->array; struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr); + struct commit_list *rl; + + struct commit_list *check_reachable_list = reachable ? + ref_cbdata->filter->reachable_from : + ref_cbdata->filter->unreachable_from; + + if (!check_reachable_list) + return; repo_init_revisions(the_repository, &revs, NULL); @@ -2247,8 +2254,11 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) to_clear[i] = item->commit; } - filter->merge_commit->object.flags |= UNINTERESTING; - add_pending_object(&revs, &filter->merge_commit->object, ""); + for (rl = check_reachable_list; rl; rl = rl->next) { + struct commit *merge_commit = rl->item; + merge_commit->object.flags |= UNINTERESTING; + add_pending_object(&revs, &merge_commit->object, ""); + } revs.limited = 1; if (prepare_revision_walk(&revs)) @@ -2263,14 +2273,19 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) int is_merged = !!(commit->object.flags & UNINTERESTING); - if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE)) + if (is_merged == reachable) array->items[array->nr++] = array->items[i]; else free_array_item(item); } clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS); - clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS); + + while (check_reachable_list) { + struct commit *merge_commit = pop_commit(&check_reachable_list); + clear_commit_marks(merge_commit, ALL_REV_FLAGS); + } + free(to_clear); } @@ -2322,8 +2337,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int clear_contains_cache(&ref_cbdata.no_contains_cache); /* Filters that need revision walking */ - if (filter->merge_commit) - do_merge_filter(&ref_cbdata); + do_merge_filter(&ref_cbdata, DO_MERGE_FILTER_REACHABLE); + do_merge_filter(&ref_cbdata, DO_MERGE_FILTER_UNREACHABLE); return ret; } @@ -2541,31 +2556,22 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; struct object_id oid; - int no_merged = starts_with(opt->long_name, "no"); + struct commit *merge_commit; BUG_ON_OPT_NEG(unset); - if (rf->merge) { - if (no_merged) { - return error(_("option `%s' is incompatible with --merged"), - opt->long_name); - } else { - return error(_("option `%s' is incompatible with --no-merged"), - opt->long_name); - } - } - - rf->merge = no_merged - ? REF_FILTER_MERGED_OMIT - : REF_FILTER_MERGED_INCLUDE; - if (get_oid(arg, &oid)) die(_("malformed object name %s"), arg); - rf->merge_commit = lookup_commit_reference_gently(the_repository, - &oid, 0); - if (!rf->merge_commit) + merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0); + + if (!merge_commit) return error(_("option `%s' must point to a commit"), opt->long_name); + if (starts_with(opt->long_name, "no")) + commit_list_insert(merge_commit, &rf->unreachable_from); + else + commit_list_insert(merge_commit, &rf->reachable_from); + return 0; } diff --git a/ref-filter.h b/ref-filter.h index 8ecc33cdfa..2d13928455 100644 --- a/ref-filter.h +++ b/ref-filter.h @@ -23,6 +23,9 @@ #define FILTER_REFS_DETACHED_HEAD 0x0020 #define FILTER_REFS_KIND_MASK (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD) +#define DO_MERGE_FILTER_UNREACHABLE 0 +#define DO_MERGE_FILTER_REACHABLE 1 + struct atom_value; struct ref_sorting { @@ -54,13 +57,8 @@ struct ref_filter { struct oid_array points_at; struct commit_list *with_commit; struct commit_list *no_commit; - - enum { - REF_FILTER_MERGED_NONE = 0, - REF_FILTER_MERGED_INCLUDE, - REF_FILTER_MERGED_OMIT - } merge; - struct commit *merge_commit; + struct commit_list *reachable_from; + struct commit_list *unreachable_from; unsigned int with_commit_tag_algo : 1, match_as_path : 1, diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 028c88d1b2..c24c6632ee 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -1299,10 +1299,6 @@ test_expect_success '--merged catches invalid object names' ' test_must_fail git branch --merged 0000000000000000000000000000000000000000 ' -test_expect_success '--merged is incompatible with --no-merged' ' - test_must_fail git branch --merged HEAD --no-merged HEAD -' - test_expect_success '--list during rebase' ' test_when_finished "reset_rebase" && git checkout master && diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 3cb9dc6cca..efea5c4971 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -187,6 +187,16 @@ test_expect_success 'multiple branch --contains' ' test_cmp expect actual ' +test_expect_success 'multiple branch --merged' ' + git branch --merged next --merged master >actual && + cat >expect <<-\EOF && + master + * next + side + EOF + test_cmp expect actual +' + test_expect_success 'multiple branch --no-contains' ' git branch --no-contains side --no-contains side2 >actual && cat >expect <<-\EOF && @@ -195,6 +205,14 @@ test_expect_success 'multiple branch --no-contains' ' test_cmp expect actual ' +test_expect_success 'multiple branch --no-merged' ' + git branch --no-merged next --no-merged master >actual && + cat >expect <<-\EOF && + side2 + EOF + test_cmp expect actual +' + test_expect_success 'branch --contains combined with --no-contains' ' git checkout -b seen master && git merge side && @@ -207,6 +225,15 @@ test_expect_success 'branch --contains combined with --no-contains' ' test_cmp expect actual ' +test_expect_success 'branch --merged combined with --no-merged' ' + git branch --merged seen --no-merged next >actual && + cat >expect <<-\EOF && + * seen + side2 + EOF + test_cmp expect actual +' + # We want to set up a case where the walk for the tracking info # of one branch crosses the tip of another branch (and make sure # that the latter walk does not mess up our flag to see if it was diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index 35408d53fd..781e470aea 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -437,8 +437,8 @@ test_expect_success 'check %(if:notequals=)' ' test_cmp expect actual ' -test_expect_success '--merged is incompatible with --no-merged' ' - test_must_fail git for-each-ref --merged HEAD --no-merged HEAD +test_expect_success '--merged is compatible with --no-merged' ' + git for-each-ref --merged HEAD --no-merged HEAD ' test_expect_success 'validate worktree atom' ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 74b637deb2..05f411c821 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -2015,8 +2015,8 @@ test_expect_success '--merged can be used in non-list mode' ' test_cmp expect actual ' -test_expect_success '--merged is incompatible with --no-merged' ' - test_must_fail git tag --merged HEAD --no-merged HEAD +test_expect_success '--merged is compatible with --no-merged' ' + git tag --merged HEAD --no-merged HEAD ' test_expect_success '--merged shows merged tags' '