From patchwork Wed Dec 17 02:28:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 955 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=1765938581; bh=eQ6ClwPUAK3DC5f/C2agOxlqe5//SJ2AgYKT+EJhZ1M=; 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=ritSBD+QIEJFKJSsjgZIFxLdA4Oh4pSattvhj9/D6A0znfsHJWI/JrnrB4VrYZFQX aEoCy0nfhLMnmPmrCUMyLuywLSTFMw97BQgl6nWySbWpyw3pX5k2B4nj3sgVka9k7/ wcGx5gfFGH8t0hNT7cu+DpTQds5IUzfmfK5cXMK3nwbt+BR0xco4L42hPf3rM2ocyK DAaz6UplLAEoravhxuKBMbyRQIsx+Ionf3akJm09EmDAd/fV4RSgo8MKybCh/ml8m9 H+x2wqsfZebR7mfnKpXU434fD8r6loCsXdiwcnG7gFHFTNo983tTKLwowZjfbRuNW6 VsXQ3b00qQWZg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 0EAB668BC2 for ; Tue, 16 Dec 2025 19:29:41 -0700 (MST) 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 QzNBR7582RXk for ; Tue, 16 Dec 2025 19:29:41 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938580; bh=eQ6ClwPUAK3DC5f/C2agOxlqe5//SJ2AgYKT+EJhZ1M=; 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=lEdbBscrL2cKvieVGpFpa53r/f1u9u6ZmS/vfN9JaNpnRicM21vShE713ZwFxhZgB l0Y1h1uVcGayufGBmV1CUsgYoDztEIqtrH+HExpeTDKnh5IDBlJY6g9OsA4NhUgKQP laUfC/rFCjM6u9Ym+naHoqB2+juu8y25ytxVPgkFpMjxYMs+nEPT4ZIn7GqpNUf/mt VJr3N5ecr7ESVB7Sr0CQfc1/7flqU9O9Tqj4//iWfjvGLNRu6EXGamc6qySuwhg3+l kd+9bvit3eDVCmBL2bt5VhGIUmyjyp1VKbkmY+YKXe9uegormPZZfE8O5vFtXSKE6P bA4eAmGKbm3Iw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id F0FD76897B for ; Tue, 16 Dec 2025 19:29:40 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938578; bh=zgd3KuoOYD0b/gGu0stp35uyxZ5nQIu0tMi5AXz9Jvg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H0QPV6FlIR2CPN8DiC+53qZcrIs2tisGMkW374ffD80vSnBOtC4ASWXLqO8W6eDr3 do9bdULnMuHxtAzaDprDoX3z8dfFrwIhmtElD5xI2WobiW/c3Ld9UAVDF/d2MQdGD3 z15h/PLTGmKPNCHRttyehb6yrH7iavUz+dd74H5rAn+eiSheEIqccn9HemkMfrmja7 lIZIXGq0cxQFtqz7Fuxb7tGqMMqLp5qVs+yos3pa2w3tz32tmOMVEEoXMxOX/k+9jV /2N6/8C4J1V/fLhBUTGE9yQZer71NAxmHKwSay2hzhQ8EWPUIbg4DbakUKtr0FERvU EjvN5VHx3J/HQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id F02EA68B96; Tue, 16 Dec 2025 19:29:38 -0700 (MST) 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 GuHSWTmxlkVl; Tue, 16 Dec 2025 19:29:38 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1765938574; bh=Wvnv26SI+rtlF3ogFXPX+fyzKMe+gH7r2paZuvZwmk4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=whsKJ5Eoc+tCPMzcS8K4/yMzzHep+VzEtyc5uXEnDK2c/ncMojtxwl7Rd/d33+pKA jTmnTishlfGxsFqkgXfYHhtOgB4ft7b0kcj60MbuLIDkB8mg1JYoIDxsYpkC9DiKni 99oSez5weQZy/8vzHpfXwjcp7Z/uAYM8CsQFHkp19/fbND/X5FN47g6FznKysSM31j MnUzVTqZwu177kCK7EZqwDhVhl4HYN6e4WI5WU7XdK63/bQHfJW5hhnaNaHHC4gU3T eOLrbDtw5a1HEZbq+3QD4E0VUKtaqn9Pvyp+U7p+r6nqIH4Cl6HtpIb1nlgRZNYYV6 P+fPduxjj88og== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 0C4AB6884F; Tue, 16 Dec 2025 19:29:33 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Tue, 16 Dec 2025 19:28:01 -0700 Message-ID: <20251217022823.392557-13-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251217022823.392557-1-sjg@u-boot.org> References: <20251217022823.392557-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: B5WUKAK3HIMNPBS64OUNPOGZZ6VOUEVU X-Message-ID-Hash: B5WUKAK3HIMNPBS64OUNPOGZZ6VOUEVU 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 , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 12/24] pickman: Fix merge selection to follow first-parent chain 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 Fix get_next_commits() to use --first-parent when finding the next merge commit. Without this, git log returns commits in topological order which can find merges from different subsystems that were merged later, rather than following the mainline merge order. The fix uses a two-step approach: 1. Use --first-parent to find the next merge on the mainline 2. Get all commits up to that merge (without --first-parent to include the merged branch's commits) Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- tools/pickman/control.py | 40 ++++++++++++++++++++++++++-------------- tools/pickman/ftest.py | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/tools/pickman/control.py b/tools/pickman/control.py index e6b7539ea34..892100f3479 100644 --- a/tools/pickman/control.py +++ b/tools/pickman/control.py @@ -151,7 +151,7 @@ def get_next_commits(dbs, source): """Get the next set of commits to cherry-pick from a source Finds commits between the last cherry-picked commit and the next merge - commit in the source branch. + commit on the first-parent (mainline) chain of the source branch. Args: dbs (Database): Database instance @@ -169,20 +169,38 @@ def get_next_commits(dbs, source): if not last_commit: return None, False, f"Source '{source}' not found in database" - # Get commits between last_commit and source HEAD (oldest first) - # Format: hash|short_hash|author|subject|parents - # Using | as separator since subject may contain colons + # First, find the next merge commit on the first-parent chain + # This ensures we follow the mainline and find merges in order + fp_output = run_git([ + 'log', '--reverse', '--first-parent', '--format=%H|%h|%an|%s|%P', + f'{last_commit}..{source}' + ]) + + if not fp_output: + return [], False, None + + # Find the first merge on the first-parent chain + merge_hash = None + for line in fp_output.split('\n'): + if not line: + continue + parts = line.split('|') + parents = parts[-1].split() + if len(parents) > 1: + merge_hash = parts[0] + break + + # Now get all commits from last_commit to the merge (or end of branch) + # Without --first-parent to include commits from merged branches log_output = run_git([ 'log', '--reverse', '--format=%H|%h|%an|%s|%P', - f'{last_commit}..{source}' + f'{last_commit}..{merge_hash or source}' ]) if not log_output: return [], False, None commits = [] - merge_found = False - for line in log_output.split('\n'): if not line: continue @@ -191,16 +209,10 @@ def get_next_commits(dbs, source): short_hash = parts[1] author = parts[2] subject = '|'.join(parts[3:-1]) # Subject may contain separator - parents = parts[-1].split() commits.append(CommitInfo(commit_hash, short_hash, subject, author)) - # Check if this is a merge commit (has multiple parents) - if len(parents) > 1: - merge_found = True - break - - return commits, merge_found, None + return commits, bool(merge_hash), None def do_next_set(args, dbs): diff --git a/tools/pickman/ftest.py b/tools/pickman/ftest.py index 80aa73f8a5b..784e8dd5d1b 100644 --- a/tools/pickman/ftest.py +++ b/tools/pickman/ftest.py @@ -840,14 +840,27 @@ class TestNextSet(unittest.TestCase): database.Database.instances.clear() - # Mock git log with commits including a merge - log_output = ( + # First-parent log (to find next merge on mainline) + fp_log_output = ( 'aaa111|aaa111a|Author 1|First commit|abc123\n' 'bbb222|bbb222b|Author 2|Second commit|aaa111\n' 'ccc333|ccc333c|Author 3|Merge branch feature|bbb222 ddd444\n' 'eee555|eee555e|Author 4|After merge|ccc333\n' ) - command.TEST_RESULT = command.CommandResult(stdout=log_output) + # Full log (to get all commits up to the merge) + full_log_output = ( + 'aaa111|aaa111a|Author 1|First commit|abc123\n' + 'bbb222|bbb222b|Author 2|Second commit|aaa111\n' + 'ccc333|ccc333c|Author 3|Merge branch feature|bbb222 ddd444\n' + ) + + def mock_git(pipe_list): + cmd = pipe_list[0] if pipe_list else [] + if '--first-parent' in cmd: + return command.CommandResult(stdout=fp_log_output) + return command.CommandResult(stdout=full_log_output) + + command.TEST_RESULT = mock_git args = argparse.Namespace(cmd='next-set', source='us/next') with terminal.capture() as (stdout, _): @@ -931,11 +944,25 @@ class TestGetNextCommits(unittest.TestCase): dbs.source_set('us/next', 'abc123') dbs.commit() - log_output = ( + # First-parent log (to find next merge on mainline) + fp_log_output = ( 'aaa111|aaa111a|Author 1|First commit|abc123\n' 'bbb222|bbb222b|Author 2|Merge branch|aaa111 ccc333\n' + 'ddd444|ddd444d|Author 3|After merge|bbb222\n' ) - command.TEST_RESULT = command.CommandResult(stdout=log_output) + # Full log (to get all commits up to the merge) + full_log_output = ( + 'aaa111|aaa111a|Author 1|First commit|abc123\n' + 'bbb222|bbb222b|Author 2|Merge branch|aaa111 ccc333\n' + ) + + def mock_git(pipe_list): + cmd = pipe_list[0] if pipe_list else [] + if '--first-parent' in cmd: + return command.CommandResult(stdout=fp_log_output) + return command.CommandResult(stdout=full_log_output) + + command.TEST_RESULT = mock_git commits, merge_found, error = control.get_next_commits(dbs, 'us/next')