From patchwork Wed May 6 15:29:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2273 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1778081431; bh=GuT7wuHLZcK5UO8HFFn55t+fZ1sjz3DwnkN5nAA83ZI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=BQa4OBYJTs3BatnbxH8pKxdmfBo5gqjvuZ8wYLkV2mw6G6uYlqNMhJmlzDfCR3Mjg FiG40BKgjpd6SHBAWDTki9FPaok4Z2O/dfRTZ8ayJ21HefXN6xrUFoP8jLMy2/Oh4r qevdepRVQ51Daq4LoEmgDhGzRnYNmhRPdmTt1NFk= Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7711D6A949 for ; Wed, 6 May 2026 09:30:31 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id JolTw_OdY4Lf for ; Wed, 6 May 2026 09:30:31 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1778081431; bh=GuT7wuHLZcK5UO8HFFn55t+fZ1sjz3DwnkN5nAA83ZI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=BQa4OBYJTs3BatnbxH8pKxdmfBo5gqjvuZ8wYLkV2mw6G6uYlqNMhJmlzDfCR3Mjg FiG40BKgjpd6SHBAWDTki9FPaok4Z2O/dfRTZ8ayJ21HefXN6xrUFoP8jLMy2/Oh4r qevdepRVQ51Daq4LoEmgDhGzRnYNmhRPdmTt1NFk= Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 65ADF6A937 for ; Wed, 6 May 2026 09:30:31 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1778081429; bh=2tCk8Rmfb+jQjn7CPuPHxmaEhYJkZTvg4mL2N4iGP5w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CSfvm+iSNFChKWPIrKVgpwupqXiSjVuy2vSHg1wIN8+ekY9aBvC+kNPEo0P/+NoCq Zfa+OrPLtMmRuKxOoALK2pFEyJ3+quQE35d1qT1UxgoZdMuQWUlAZLuOoDel1ovzkd qRMfPSALlnGLT2YpSUL1KaV1op26uPxfTfmstwNA= Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id AB9EA6A92E; Wed, 6 May 2026 09:30:29 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id vQxDQ_25I89l; Wed, 6 May 2026 09:30:29 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1778081425; bh=33Mlk4Uw3wqwfFtDfhhwhL3zap5/PHZlpEGHJcbF9Ao=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N92PbbNhNsX/zRy66BkBSUUKIA8qEXLNPKvSHI1cwuzE4vwAWcFjj/BT5TnB8pi7J MNA7h3s5hyzqtbTvRpos+mG5VDalB6pQT9MB90fsea7YNtY06eFmz0Z/giPs4nKJWa djIBqPcxl2lM5nP4mEetjhYmYqDeS592CDqwbjvQ= Received: from u-boot.org (unknown [174.51.25.52]) by mail.u-boot.org (Postfix) with ESMTPSA id 4A51A6A87B; Wed, 6 May 2026 09:30:25 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Wed, 6 May 2026 09:29:50 -0600 Message-ID: <20260506153006.529909-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260506153006.529909-1-sjg@u-boot.org> References: <20260506153006.529909-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: UCRUQ4O53KVYH3C2AHAKLCK56363WQDT X-Message-ID-Hash: UCRUQ4O53KVYH3C2AHAKLCK56363WQDT X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 1/6] u_boot_pylib: Add worktree helpers for branch-aware worktrees List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The existing add_worktree() always creates a detached worktree, which suits buildman's one-off build trees but not callers that want a worktree on a named branch they can iterate on (apply, reset, retry). Add ensure_worktree() and remove_worktree(): the former creates the worktree at a given path on a named branch reset to a given upstream ref, or resets and cleans an existing one to that ref so a re-run is recoverable; the latter removes the worktree by path. Callers own the path policy. Patman uses these for per-series review worktrees in a later commit. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index a7db37fd7df..ec326332d9b 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -445,6 +445,59 @@ def prune_worktrees(git_dir): raise OSError(f'git worktree prune: {result.stderr}') +def _is_worktree_registered(repo, path): + """Return True if git already has a worktree registered at path""" + out = command.output('git', '-C', repo, 'worktree', 'list', + '--porcelain') + target = os.path.realpath(path) + for line in out.splitlines(): + if line.startswith('worktree '): + registered = os.path.realpath(line[len('worktree '):]) + if registered == target: + return True + return False + + +def ensure_worktree(repo, path, branch_name, upstream_branch): + """Create or reuse a worktree at path on branch_name + + If a worktree at path already exists, reset it to upstream_branch + so the next operation starts clean. Otherwise create one via + 'git worktree add -B '. + + Args: + repo (str): Top-level dir of the repo to add the worktree under + path (str): Path where the worktree should live + branch_name (str): Branch to create/reuse in the worktree + upstream_branch (str): Ref to base the branch on (e.g. 'us/next') + + Return: + str: path, ready to be used as cwd + """ + if _is_worktree_registered(repo, path): + command.output('git', '-C', path, 'reset', '--hard', upstream_branch) + command.output('git', '-C', path, 'clean', '-fdx') + return path + + os.makedirs(os.path.dirname(path), exist_ok=True) + command.output('git', '-C', repo, 'worktree', 'add', + '-B', branch_name, path, upstream_branch) + return path + + +def remove_worktree(repo, path): + """Remove the worktree at path, if any + + Args: + repo (str): Top-level dir of the repo to add the worktree under + path (str): Path of the worktree to remove + """ + if not _is_worktree_registered(repo, path): + return + command.output('git', '-C', repo, 'worktree', 'remove', '--force', + path) + + def create_patches(branch, start, count, ignore_binary, series, signoff=True, git_dir=None, cwd=None): """Create a series of patches from the top of the current branch.