我有一个存储库,其版本(语义版本控制)硬编码在其文件之一中。每次开发人员添加更改(我们将其称为类型 1 更改)时,我都需要检查这些更改并增加次要版本组件。如果开发人员添加类型 2 更改,我会增加补丁版本组件。
我为开发人员制定了一个约定:如果他们要添加类型 1 更改,则必须创建一个分支并将其命名为
A/ID
。如果他们要添加类型 2 更改,则必须创建一个分支并将其命名为 bugfix/A/ID
。
此外,我还编写了一些 Git hook(
commit-msg
,因为它会在 git commit
和 git merge
中调用)脚本,根据合并到默认分支的分支,自动递增相关版本组件。下面是我写的Git hook脚本:
#!/usr/bin/env python3
import subprocess
import sys
import pathlib
import re
def main():
default, base = "main", "package/__init__.py"
head = pathlib.Path(".git/MERGE_HEAD")
if not head.exists():
exit(0)
with head.open() as f:
commit = f.read().strip()
command = ["git", "name-rev", "--name-only", commit]
process = subprocess.run(command, capture_output=True, encoding="UTF-8")
if process.returncode != 0:
print(
f"Failing to perform `commit-msg` commit operations. The `{' '.join(command)}` command and its logs may be helpful.",
" ".join(process.args),
process.stderr,
sep="\n",
file=sys.stderr,
)
exit(process.returncode)
merge = process.stdout.strip()
command = ["git", "rev-parse", "--abbrev-ref", "HEAD"]
process = subprocess.run(command, capture_output=True, encoding="UTF-8")
if process.returncode != 0:
print(
f"Failing to perform `commit-msg` commit operations. The `{' '.join(command)}` command and its logs may be helpful.",
" ".join(process.args),
process.stderr,
sep="\n",
file=sys.stderr,
)
exit(process.returncode)
current = process.stdout.strip()
if current != default or (
not merge.startswith("A/") and not merge.startswith("bugfix/A/")
):
exit(0)
semver = re.compile(
r"(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?"
)
version = {"major": 0, "minor": 0, "patch": 0}
with open(base, mode="r", encoding="UTF-8") as f:
line, match = f.readline(), None
while line:
if line.startswith("__version__"):
match = re.match(r'__version__.*"(?P<version>.*?)"', line)
break
line = f.readline()
if match == None:
print(
"Failing to perform `commit-msg` commit operations. The Semantic Versioning regular expression cannot find the detection version in the Python module!",
file=sys.stderr,
)
exit(1)
match = semver.match(match.group("version"))
if match == None:
print(
"Failing to perform `commit-msg` commit operations. The detection version format in this repository does not match the Semantic Versioning format.",
file=sys.stderr,
)
exit(1)
version["major"], version["minor"], version["patch"] = (
int(match.group("major")),
int(match.group("minor")),
int(match.group("patch")),
)
if merge.startswith("A/"):
version["minor"] += 1
elif merge.startswith("bugfix/A/"):
version["patch"] += 1
with open(base, mode="r", encoding="UTF-8") as f:
module = f.read()
with open(base, mode="w", encoding="UTF-8") as f:
module = re.sub(
r'__version__ = "(?P<version>.*?)"',
f'__version__ = "{version["major"]}.{version["minor"]}.{version["patch"]}-rc"',
module,
)
f.write(module)
command = ["git", "add", base]
process = subprocess.run(command, capture_output=True, encoding="UTF-8")
if process.returncode != 0:
print(
f'Failing to perform `commit-msg` commit operations. The `{" ".join(command)}` command and its logs may be helpful.',
" ".join(process.args),
process.stderr,
sep="\n",
file=sys.stderr,
)
exit(process.returncode)
print("Upgraded.")
if __name__ == "__main__":
main()
脚本按预期工作,但有一个例外:在脚本末尾,您可以看到我正在使用
git add <FILE>
来包含之前对 Python 模块中硬编码的版本所做的更改。
此命令按预期工作并将更改添加到 Git 索引。 但是,在挂钩完成并出现合并提交消息后,当我接受该消息时,更改不会包含在合并提交中,而是单独保留在索引中!
我做错了什么?我在线且活跃,回答出现的问题。
我描述的前一个问题的解决方案是第一位的,但欢迎对问题的各个方面提出建议,包括对总体方法、Python 代码、Git 挂钩名称和哲学的更改。
我会尝试使用普通的
pre-merge-commit
钩子,选择 commit-msg
钩子似乎很奇怪“因为它会在 git commit
和 git merge
中被调用”,但如果没有被调用,它就会立即退出用于合并;此外,预提交和预合并提交并没有明确用于设置消息文本,这使得它们看起来不太可能在所有事情之后运行,但消息文本已经准备好并锁定。