不需要自己从 git
命令中获取数据。使用GitPython 是一个非常好的方式来做这个和很多其他git
操作。它甚至有“尽力而为”的支持Windows。
在安装了gitpython
之后,您可以执行以下操作:
import git
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
在使用这个库时需要考虑的一些事情。以下内容摘自gitpython.readthedocs.io
系统资源泄漏
因为GitPython倾向于泄漏系统资源,所以不适合长时间运行的进程(如守护进程)使用。它是在析构函数(如
__del__
方法中实现)仍然确定性运行的时代编写的。如果您仍想在这种情况下使用它,您将需要在代码库中搜索
__del__
实现,并在适当时调用这些实现。确保资源的正确清除的另一种方法是将GitPython分解为单独的进程,可以定期删除该进程。
ImportError: No module named gitpython
。你不能指望最终用户已经安装了gitpython
,要求他们在你的代码工作之前安装它会使它不可移植。除非你打算包括自动安装协议,否则这将不再是一个干净的解决方案。 - user5359531pip
/ requirements.txt
) 进行安装。哪里不“干净”呢? - crishojimport numpy as np
,但安装gitpython就超出了“干净”和“可移植”的范畴。我认为这是迄今为止最好的解决方案,因为它不会重复造轮子,隐藏了丑陋的实现,并且不会绕过使用子进程的git答案的hack方法。 - Jblascopip
或可以轻松安装pip
的机器映像(例如AMIs)。在这些现代场景中,pip
解决方案与“标准库”解决方案一样具有可移植性。 - Ryanimport subprocess
def get_git_revision_hash() -> str:
return subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('ascii').strip()
def get_git_revision_short_hash() -> str:
return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip()
在运行时
print(get_git_revision_hash())
print(get_git_revision_short_hash())
你将获得输出:
fd1cd173fc834f62fa7db3034efc5b8e0f3b43fe
fd1cd17
subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
命令获取分支名称。 - Ryan Allen.decode('ascii').strip()
以解码它(并移除换行符)。 - pfmcwd=os.path.dirname(os.path.realpath(__file__))
作为check_output
的参数添加。 - Kiprgit describe
命令是创建代码的易读版本号的好方法。从文档的示例中可以看出:使用类似 git.git 当前树这样的东西,我得到了:[torvalds@g5 git]$ git describe parent
v1.0.4-14-g2414721
即,我“父”分支的当前头是基于v1.0.4的,但由于其有一些在顶部的提交,因此描述在末尾添加了附加提交数量(“14”)和缩写对象名称(“2414721”)。
在Python中,您可以执行以下操作:
import subprocess
label = subprocess.check_output(["git", "describe"]).strip()
fatal: No names found, cannot describe anything.
- kynangit describe --always
将会回退到最后一次提交。 - Leonardo如果subprocess不是可移植的,而且您不想安装一个包来完成这么简单的事情,您也可以这样做。
import pathlib
def get_git_revision(base_path):
git_dir = pathlib.Path(base_path) / '.git'
with (git_dir / 'HEAD').open('r') as head:
ref = head.readline().split(' ')[-1].strip()
with (git_dir / ref).open('r') as git_hash:
return git_hash.readline().strip()
我只在我的代码库上测试过,但它似乎相当一致地工作。
这里是Greg答案的更完整版本:Greg的答案:
import subprocess
print(subprocess.check_output(["git", "describe", "--always"]).strip().decode())
或者,如果脚本是从存储库外部调用的:
import subprocess, os
print(subprocess.check_output(["git", "describe", "--always"], cwd=os.path.dirname(os.path.abspath(__file__))).strip().decode())
或者,如果脚本是从存储库外部调用的,并且您喜欢 pathlib
:
import subprocess
from pathlib import Path
print(subprocess.check_output(["git", "describe", "--always"], cwd=Path(__file__).resolve().parent).strip().decode())
check_output
中的 cwd=
参数来临时更改当前工作目录,并在执行命令之前执行,而不是使用 os.chdir
。 - Marcnumpy
在其setup.py
中有一个外观不错的多平台例程:
import os
import subprocess
# Return the git revision as a string
def git_version():
def _minimal_ext_cmd(cmd):
# construct minimal environment
env = {}
for k in ['SYSTEMROOT', 'PATH']:
v = os.environ.get(k)
if v is not None:
env[k] = v
# LANGUAGE is used on win32
env['LANGUAGE'] = 'C'
env['LANG'] = 'C'
env['LC_ALL'] = 'C'
out = subprocess.Popen(cmd, stdout = subprocess.PIPE, env=env).communicate()[0]
return out
try:
out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
GIT_REVISION = out.strip().decode('ascii')
except OSError:
GIT_REVISION = "Unknown"
return GIT_REVISION
env
字典对于跨平台功能是必要的。Yuji的答案并不需要,但也许它可以在UNIX和Windows上都起作用。 - ryanjdillon.decode('ascii')
正常工作 - 否则编码是未知的。 - z0rfrom numpy.setup import git_version
但是它没有起作用。 - jlanseysetup.py
中声明的函数,它不是 numpy
包的一部分,因此无法从 numpy
中导入。要使用它,您需要将此方法添加到自己的代码中的某个位置。 - ryanjdillon这是对于 Tomita Yuji 的回答的改进。
import subprocess
def get_git_revision_hash():
full_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'])
full_hash = str(full_hash, "utf-8").strip()
return full_hash
def get_git_revision_short_hash():
short_hash = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])
short_hash = str(short_hash, "utf-8").strip()
return short_hash
print(get_git_revision_hash())
print(get_git_revision_short_hash())
如果您需要比哈希更多的数据,可以使用 git-log
命令:
import subprocess
def get_git_hash():
return subprocess.check_output(['git', 'log', '-n', '1', '--pretty=tformat:%H']).strip()
def get_git_short_hash():
return subprocess.check_output(['git', 'log', '-n', '1', '--pretty=tformat:%h']).strip()
def get_git_short_hash_and_commit_date():
return subprocess.check_output(['git', 'log', '-n', '1', '--pretty=tformat:%h-%ad', '--date=short']).strip()
查看完整的格式选项列表,请参阅 git log --help
我遇到了这个问题,通过实现这个函数解决了它。 https://gist.github.com/NaelsonDouglas/9bc3bfa26deec7827cb87816cad88d59
from pathlib import Path
def get_commit(repo_path):
git_folder = Path(repo_path,'.git')
head_name = Path(git_folder, 'HEAD').read_text().split('\n')[0].split(' ')[-1]
head_ref = Path(git_folder,head_name)
commit = head_ref.read_text().replace('\n','')
return commit
r = get_commit('PATH OF YOUR CLONED REPOSITORY')
print(r)
我遇到了类似于OP的问题,但在我的情况下,我将源代码作为zip文件交付给客户端,尽管我知道他们将安装Python,但我不能假设他们将安装git。由于OP没有指定他的操作系统和是否安装了git,我认为我可以在这里做出贡献。
为了只获取提交的哈希值,Naelson Douglas's answer 是完美的,但要获得标签名称,我使用了 dulwich Python 包。它是一个简化的Python Git客户端。
安装了该包后,使用 pip install dulwich --global-option="--pure"
可以执行以下操作:
from dulwich import porcelain
def get_git_revision(base_path):
return porcelain.describe(base_path)
r = get_git_revision("PATH OF YOUR REPOSITORY's ROOT FOLDER")
print(r)
v0.1.2-1-gfb41223
,类似于 git describe返回的内容,这意味着我在标签v0.1.2之后有1次提交,并且提交的7位哈希值为fb41223。--pure
(该问题在此处有解释)而导致命令pip install
出错,请选择两种可能的解决方案之一:pip install urllib3 certifi && pip install dulwich --global-option="--pure"
然后不使用pure选项进行安装:pip install dulwich
。这将在您的系统中安装一些平台相关的文件,但它会提高软件包的性能。
git rev-parse HEAD
。输出的语法应该很明显。 - Mel Nicholsonsubprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip()
。 - Charlie Parker