https://gcc.gnu.org/g:75dc88863cfe75fe3e8d274a3408962f1b0c9c3b
commit 75dc88863cfe75fe3e8d274a3408962f1b0c9c3b Author: Tobias Burnus <[email protected]> Date: Thu Apr 2 19:30:45 2026 +0000 git_update_version.py: Support vendor-branch version bumps This patch incorporates commits dbd927be10e and subsequent bug fix cc7f48e65b9 from the OG15 branch. contrib/ChangeLog: * gcc-changelog/git_repository.py (parse_git_revisions): Optional exclude_branch_name argument. Skip over merge commits for merges from exclude branch. * gcc-changelog/git_update_version.py: Add --suffix, --exclude-branch and --last-commit to handle vendor branches. Handle merges. Diff: --- contrib/gcc-changelog/git_repository.py | 12 ++++- contrib/gcc-changelog/git_update_version.py | 70 +++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/contrib/gcc-changelog/git_repository.py b/contrib/gcc-changelog/git_repository.py index 8703b45f8967..9fc036395b65 100755 --- a/contrib/gcc-changelog/git_repository.py +++ b/contrib/gcc-changelog/git_repository.py @@ -31,7 +31,8 @@ except ImportError: from git_commit import GitCommit, GitInfo, decode_path -def parse_git_revisions(repo_path, revisions, ref_name=None): +def parse_git_revisions(repo_path, revisions, ref_name=None, + exclude_branch_name=None): repo = Repo(repo_path) def commit_to_info(commit): @@ -67,6 +68,8 @@ def parse_git_revisions(repo_path, revisions, ref_name=None): except ValueError: return None + exclude_branch = (repo.commit(exclude_branch_name) + if exclude_branch_name is not None else None) parsed_commits = [] if '..' in revisions: commits = list(repo.iter_commits(revisions)) @@ -74,6 +77,13 @@ def parse_git_revisions(repo_path, revisions, ref_name=None): commits = [repo.commit(revisions)] for commit in commits: + if exclude_branch is not None: + if repo.is_ancestor(commit, exclude_branch): + continue + # Exlude merge commit + if (len(commit.parents) == 2 + and repo.is_ancestor(commit.parents[1], exclude_branch)): + continue git_commit = GitCommit(commit_to_info(commit.hexsha), commit_to_info_hook=commit_to_info, ref_name=ref_name) diff --git a/contrib/gcc-changelog/git_update_version.py b/contrib/gcc-changelog/git_update_version.py index f4c024220113..da0e0421a381 100755 --- a/contrib/gcc-changelog/git_update_version.py +++ b/contrib/gcc-changelog/git_update_version.py @@ -23,6 +23,8 @@ import datetime import logging import os import re +import shutil +import sys from git import Repo @@ -69,14 +71,14 @@ def read_timestamp(path): return f.read() -def prepend_to_changelog_files(repo, folder, git_commit, add_to_git): +def prepend_to_changelog_files(repo, folder, git_commit, add_to_git, suffix): if not git_commit.success: logging.info(f"While processing {git_commit.info.hexsha}:") for error in git_commit.errors: logging.info(error) raise AssertionError() for entry, output in git_commit.to_changelog_entries(use_commit_ts=True): - full_path = os.path.join(folder, entry, 'ChangeLog') + full_path = os.path.join(folder, entry, 'ChangeLog' + suffix) logging.info('writing to %s' % full_path) if os.path.exists(full_path): with open(full_path) as f: @@ -96,7 +98,10 @@ active_refs = ['master', 'releases/gcc-13', 'releases/gcc-14', 'releases/gcc-15'] parser = argparse.ArgumentParser(description='Update DATESTAMP and generate ' - 'ChangeLog entries') + 'ChangeLog entries', + epilog='For vendor branches, only; e.g: -s .suffix ' + '-x releases/gcc-15 -l ' + '`git log -1 --pretty=format:%H --grep "Vendor Bump"`') parser.add_argument('-g', '--git-path', default='.', help='Path to git repository') parser.add_argument('-p', '--push', action='store_true', @@ -109,26 +114,43 @@ parser.add_argument('-c', '--current', action='store_true', help='Modify current branch (--push argument is ignored)') parser.add_argument('-i', '--ignore', action='append', help='list of commits to ignore') +# Useful only for vendor branches +parser.add_argument('-s', '--suffix', default="", + help='suffix for the ChangeLog and DATESTAMP files') +parser.add_argument('-l', '--last-commit', + help='hash of the last DATESTAMP commit') +parser.add_argument('-x', '--exclude-branch', + help='commits to be ignored if in this branch') args = parser.parse_args() repo = Repo(args.git_path) origin = repo.remotes['origin'] -def update_current_branch(ref_name=None): +def update_current_branch(ref_name=None, suffix="", last_commit_ref=None, + exclude_branch=None): commit = repo.head.commit commit_count = 1 - while commit: - if (commit.author.email == '[email protected]' - and commit.message.strip() == 'Daily bump.'): - break - # We support merge commits but only with 2 parensts - assert len(commit.parents) <= 2 - commit = commit.parents[-1] - commit_count += 1 - - logging.info('%d revisions since last Daily bump' % commit_count) + if last_commit_ref is not None: + commit = repo.commit(last_commit_ref) + else: + while commit: + if (commit.author.email == '[email protected]' + and commit.message.strip() == 'Daily bump.'): + break + # We support merge commits but only with 2 parensts + assert len(commit.parents) <= 2 + commit = commit.parents[-1] + commit_count += 1 + logging.info('%d revisions since last Daily bump' % commit_count) + datestamp_path = os.path.join(args.git_path, 'gcc/DATESTAMP') + if suffix != "": + if not os.path.exists(datestamp_path + suffix): + logging.info('Create DATESTAMP%s by copying DATESTAMP' % suffix) + shutil.copyfile(datestamp_path, datestamp_path + suffix) + datestamp_path += suffix + if (read_timestamp(datestamp_path) != current_timestamp or args.dry_mode or args.current): head = repo.head.commit @@ -138,11 +160,14 @@ def update_current_branch(ref_name=None): if len(head.parents) == 2: head = head.parents[1] commits = parse_git_revisions(args.git_path, '%s..%s' - % (commit.hexsha, head.hexsha), ref_name) + % (commit.hexsha, head.hexsha), ref_name, + exclude_branch) commits = [c for c in commits if c.info.hexsha not in ignored_commits] + if last_commit_ref is not None: + logging.info('%d revisions since last Daily bump' % len(commits)) for git_commit in reversed(commits): prepend_to_changelog_files(repo, args.git_path, git_commit, - not args.dry_mode) + not args.dry_mode, args.suffix) if args.dry_mode: diff = repo.git.diff('HEAD') patch = os.path.join(args.dry_mode, @@ -175,8 +200,17 @@ if args.ignore is not None: if args.current: logging.info('=== Working on the current branch ===') - update_current_branch() + if args.suffix != "" and args.last_commit is None: + logging.error('--suffix requires --last-commit') + sys.exit(1) + update_current_branch(None, args.suffix, args.last_commit, + args.exclude_branch) else: + if args.suffix != "" or args.last_commit is not None \ + or update_current_branch is not None: + logging.error('--suffix, --last-commit and --exclude-branch ' + 'require --current') + sys.exit(1) for ref in origin.refs: assert ref.name.startswith('origin/') name = ref.name[len('origin/'):] @@ -189,7 +223,7 @@ else: branch.checkout() origin.pull(rebase=True) logging.info('branch pulled and checked out') - update_current_branch(name) + update_current_branch(name, args.suffix) assert not repo.index.diff(None) logging.info('branch is done') logging.info('')
