Linux maintainer tooling and workflows
 help / color / mirror / Atom feed
From: Breno Leitao <leitao@debian.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
	 kernel-team@meta.com, Breno Leitao <leitao@debian.org>
Subject: [PATCH b4 v2] prep: add --cleanup-older-than option to clean up stale branches
Date: Tue, 04 Aug 2026 05:24:58 -0700	[thread overview]
Message-ID: <20260804-cleanup-v2-1-8c8df5d66e8f@debian.org> (raw)

B4 is so useful that I have too many branches now, create a way to
easily remove old branches.

Add a new --cleanup-older-than DAYS option that archives and removes
prep-tracked branches whose latest commit is older than the specified
number of days. Each matching branch goes through the normal per-branch
confirmation prompt.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes in v2:
- Rebased onto master; option moved into exclusive group, help
  clarified.
- Age no longer truncated to whole days
- Documented in prep.rst.
- Link to v1: https://patch.msgid.link/20260323-cleanup-v1-1-cbf209f3de43@debian.org
---
 docs/contributor/prep.rst | 18 ++++++++++++++++++
 src/b4/command.py         |  7 +++++++
 src/b4/ez.py              | 43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/docs/contributor/prep.rst b/docs/contributor/prep.rst
index 20b34d7..bc470d4 100644
--- a/docs/contributor/prep.rst
+++ b/docs/contributor/prep.rst
@@ -354,6 +354,16 @@ patches, cover letters, and tracking information from your series.
 Afterwards, b4 deletes the branch(es) and all related tags from your local
 repository.
 
+If prep-managed branches have piled up over time, you can select them by
+age instead of by name::
+
+    b4 prep --cleanup-older-than 180
+
+This finds every prep-managed branch whose latest commit is older than the
+given number of days, skipping the one you currently have checked out. Each
+matching branch is then archived and deleted through the same confirmation
+prompt as above, so nothing goes away without your say-so.
+
 .. _prep_flags:
 
 Prep command flags
@@ -522,6 +532,14 @@ modifying defaults for some of these flags.
 
   .. versionadded:: v0.13
 
+``--cleanup-older-than DAYS``
+  Same as ``--cleanup``, but picks the branches by age rather than by
+  name: every prep-managed branch whose latest commit is older than
+  DAYS days is archived and deleted, one confirmation prompt at a time.
+  The currently checked out branch is always left alone.
+
+  .. versionadded:: v0.16
+
 ``--claim [BRANCH]``
   Re-stamps the cover letter and every patch on a prep branch under
   your current git identity (defaults to the current branch). B4
diff --git a/src/b4/command.py b/src/b4/command.py
index b8f7646..8a8c96f 100644
--- a/src/b4/command.py
+++ b/src/b4/command.py
@@ -1010,6 +1010,13 @@ def setup_parser() -> argparse.ArgumentParser:
         nargs='*',
         help='Archive and remove prep-tracked branches and all associated sent/ tags',
     )
+    spp_g.add_argument(
+        '--cleanup-older-than',
+        metavar='DAYS',
+        type=int,
+        default=None,
+        help='Archive and remove prep-tracked branches older than DAYS days',
+    )
     spp_g.add_argument(
         '--claim',
         metavar='BRANCH',
diff --git a/src/b4/ez.py b/src/b4/ez.py
index ac3949a..483ebac 100644
--- a/src/b4/ez.py
+++ b/src/b4/ez.py
@@ -3625,6 +3625,46 @@ def _cleanup_branch(branch: str) -> None:
     logger.info('Wrote: %s', tarpath)
 
 
+def _get_branch_latest_commit_age_days(branch: str) -> Optional[float]:
+    """Return the age in days of the latest commit on *branch*, or None on error."""
+    lines = b4.git_get_command_lines(None, ['log', '-1', '--format=%ct', branch])
+    if not lines:
+        return None
+    try:
+        commit_ts = int(lines[0])
+    except ValueError:
+        return None
+    return (time.time() - commit_ts) / 86400
+
+
+def cleanup_older_than(older_than_days: int) -> None:
+    """Find prep-tracked branches whose latest commit exceeds *older_than_days* and clean them up.
+
+    The currently checked-out branch is always skipped.  Each matching
+    branch is passed to ``_cleanup_branch``, which prompts the user for
+    confirmation before archiving and deleting it.
+    """
+    mybranches = get_prep_managed_branches(None)
+    if not mybranches:
+        logger.info('No b4-tracked branches found')
+        sys.exit(0)
+
+    curbranch = b4.git_get_current_branch()
+    old_branches = []
+    for branch in mybranches:
+        if branch == curbranch:
+            logger.debug('Skipping currently checked out branch: %s', branch)
+            continue
+        age = _get_branch_latest_commit_age_days(branch)
+        if age is not None and age > older_than_days:
+            old_branches.append(branch)
+    if not old_branches:
+        logger.info('No branches older than %d days found', older_than_days)
+        return
+    for branch in old_branches:
+        _cleanup_branch(branch)
+
+
 def cleanup(branches: List[str]) -> None:
     if not branches:
         # Show all b4-tracked branches
@@ -4076,6 +4116,9 @@ def cmd_prep(cmdargs: argparse.Namespace) -> None:
     if cmdargs.show_info:
         return show_info(cmdargs.show_info)
 
+    if cmdargs.cleanup_older_than is not None:
+        return cleanup_older_than(cmdargs.cleanup_older_than)
+
     if cmdargs.cleanup is not None:
         return cleanup(cmdargs.cleanup)
 

---
base-commit: 62c5a3c2f841dd6533a9009e6ab4fee104bf3b04
change-id: 20260323-cleanup-4dea45140971

Best regards,
--  
Breno Leitao <leitao@debian.org>


             reply	other threads:[~2026-08-04 12:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-04 12:24 Breno Leitao [this message]
2026-08-04 18:04 ` [PATCH b4 v2] prep: add --cleanup-older-than option to clean up stale branches Konstantin Ryabitsev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260804-cleanup-v2-1-8c8df5d66e8f@debian.org \
    --to=leitao@debian.org \
    --cc=kernel-team@meta.com \
    --cc=konstantin@linuxfoundation.org \
    --cc=tools@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox