Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add tools/docs/gen-renames.py

Add a new script that wraps git to trawl the repository history for
renames of .rst files in the Documentation/ directory.

Example usage:

tools/docs/gen-renames.py --rev v6.17-rc3 > Documentation/.renames.txt

The output format is simply:

<old path> SPACE <new path> NEWLINE

where neither <old path> nor <new path> contain the Documentation/
prefix or the .rst suffix. The file is sorted alphabetically.

We can suggest rerunning the script for future renames (and squash the
resulting change) or rerun it periodically to keep the file up to date.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Message-ID: <20250905144608.577449-2-vegard.nossum@oracle.com>

authored by

Vegard Nossum and committed by
Jonathan Corbet
2f1c9601 f874abea

+130
+130
tools/docs/gen-renames.py
··· 1 + #! /usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Copyright © 2025, Oracle and/or its affiliates. 5 + # Author: Vegard Nossum <vegard.nossum@oracle.com> 6 + 7 + """Trawl repository history for renames of Documentation/**.rst files. 8 + 9 + Example: 10 + 11 + tools/docs/gen-renames.py --rev HEAD > Documentation/.renames.txt 12 + """ 13 + 14 + import argparse 15 + import itertools 16 + import os 17 + import subprocess 18 + import sys 19 + 20 + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) 21 + parser.add_argument('--rev', default='HEAD', help='generate renames up to this revision') 22 + 23 + args = parser.parse_args() 24 + 25 + def normalize(path): 26 + prefix = 'Documentation/' 27 + suffix = '.rst' 28 + 29 + assert path.startswith(prefix) 30 + assert path.endswith(suffix) 31 + 32 + return path[len(prefix):-len(suffix)] 33 + 34 + class Name(object): 35 + def __init__(self, name): 36 + self.names = [name] 37 + 38 + def rename(self, new_name): 39 + self.names.append(new_name) 40 + 41 + names = { 42 + } 43 + 44 + for line in subprocess.check_output([ 45 + 'git', 'log', 46 + '--reverse', 47 + '--oneline', 48 + '--find-renames', 49 + '--diff-filter=RD', 50 + '--name-status', 51 + '--format=commit %H', 52 + # ~v4.8-ish is when Sphinx/.rst was added in the first place 53 + f'v4.8..{args.rev}', 54 + '--', 55 + 'Documentation/' 56 + ], text=True).splitlines(): 57 + # rename 58 + if line.startswith('R'): 59 + _, old, new = line[1:].split('\t', 2) 60 + 61 + if old.endswith('.rst') and new.endswith('.rst'): 62 + old = normalize(old) 63 + new = normalize(new) 64 + 65 + name = names.get(old) 66 + if name is None: 67 + name = Name(old) 68 + else: 69 + del names[old] 70 + 71 + name.rename(new) 72 + names[new] = name 73 + 74 + continue 75 + 76 + # delete 77 + if line.startswith('D'): 78 + _, old = line.split('\t', 1) 79 + 80 + if old.endswith('.rst'): 81 + old = normalize(old) 82 + 83 + # TODO: we could save added/modified files as well and propose 84 + # them as alternatives 85 + name = names.get(old) 86 + if name is None: 87 + pass 88 + else: 89 + del names[old] 90 + 91 + continue 92 + 93 + # 94 + # Get the set of current files so we can sanity check that we aren't 95 + # redirecting any of those 96 + # 97 + 98 + current_files = set() 99 + for line in subprocess.check_output([ 100 + 'git', 'ls-tree', 101 + '-r', 102 + '--name-only', 103 + args.rev, 104 + 'Documentation/', 105 + ], text=True).splitlines(): 106 + if line.endswith('.rst'): 107 + current_files.add(normalize(line)) 108 + 109 + # 110 + # Format/group/output result 111 + # 112 + 113 + result = [] 114 + for _, v in names.items(): 115 + old_names = v.names[:-1] 116 + new_name = v.names[-1] 117 + 118 + for old_name in old_names: 119 + if old_name == new_name: 120 + # A file was renamed to its new name twice; don't redirect that 121 + continue 122 + 123 + if old_name in current_files: 124 + # A file was recreated with a former name; don't redirect those 125 + continue 126 + 127 + result.append((old_name, new_name)) 128 + 129 + for old_name, new_name in sorted(result): 130 + print(f"{old_name} {new_name}")