在Python脚本中获取当前的git哈希

时间:2013-02-20 21:03:29

标签: python git git-hash

我想在Python脚本的输出中包含当前的git哈希值(作为生成该输出的代码的版本号)。

如何在Python脚本中访问当前的git哈希?

12 个答案:

答案 0 :(得分:112)

无需自己动手从git命令获取数据。 GitPython是一个非常好的方法来完成这个以及很多其他git的工作。它甚至可以为Windows提供“尽力而为”的支持。

pip install gitpython之后你可以做

import git
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha

答案 1 :(得分:79)

This post包含命令,Greg's answer包含子进程命令。

import subprocess

def get_git_revision_hash():
    return subprocess.check_output(['git', 'rev-parse', 'HEAD'])

def get_git_revision_short_hash():
    return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'])

答案 2 :(得分:77)

git describe命令是创建代码的人类可呈现“版本号”的好方法。从文档中的示例:

  

使用像git.git当前树这样的东西,我得到:

     
[torvalds@g5 git]$ git describe parent
v1.0.4-14-g2414721
     

即。我的“父”分支的当前头部基于v1.0.4,但由于它有一些提交,因此describe添加了额外提交的数量(“14”)和提交本身的缩写对象名称(“2414721”)最后。

在Python中,您可以执行以下操作:

import subprocess
label = subprocess.check_output(["git", "describe"]).strip()

答案 3 :(得分:9)

numpy在其setup.py

中看起来很漂亮multi-platform routine
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

答案 4 :(得分:4)

这是对 Yuji 'Tomita' Tomita 回答的改进。

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())

答案 5 :(得分:3)

这是Greg's answer的更完整版本:

import subprocess
print(subprocess.check_output(["git", "describe", "--always"]).strip().decode())

或者,如果脚本是从仓库外部调用的:

import subprocess, os
os.chdir(os.path.dirname(__file__))
print(subprocess.check_output(["git", "describe", "--always"]).strip().decode())

答案 6 :(得分:2)

如果您想要比散列更多的数据,则可以使用lapply(df_numeric_names, function(x) { boxplot.stats(df$x)$out }) - output [[1]] NULL [[2]] NULL [[3]] NULL [[4]] NULL [[5]] NULL

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()

答案 7 :(得分:1)

如果由于某种原因没有git,但是有git repo(找到了.git文件夹),则可以从.git / fetch / heads / [branch]中获取提交哈希值

例如,我使用在存储库根目录下运行的以下快速且肮脏的Python代码段来获取提交ID:

git_head = '.git\\HEAD'

# Open .git\HEAD file:
with open(git_head, 'r') as git_head_file:
    # Contains e.g. ref: ref/heads/master if on "master"
    git_head_data = str(git_head_file.read())

# Open the correct file in .git\ref\heads\[branch]
git_head_ref = '.git\\%s' % git_head_data.split(' ')[1].replace('/', '\\').strip()

# Get the commit hash ([:7] used to get "--short")
with open(git_head_ref, 'r') as git_head_ref_file:
    commit_id = git_head_ref_file.read().strip()[:7]

答案 8 :(得分:1)

如果你像我一样:

  • 多平台,因此子流程可能会在一天内崩溃
  • 使用Python 2.7,因此GitPython不可用
  • 不想只为此使用Numpy
  • 已经使用Sentry(旧的折旧版本:raven)

然后(由于Shell无法检测到当前文件路径,因此无法在Shell上运行,请用当前文件路径替换BASE_DIR):

import os
import raven

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(raven.fetch_git_sha(BASE_DIR))

就是这样。

我一直在寻找另一种解决方案,因为我想迁移到sentry_sdk并离开raven,但也许有些人希望继续使用raven一段时间。

Here was the discussion that get me into this stackoverflow issue

因此也可以使用不带乌鸦的乌鸦代码(请参见讨论):

from __future__ import absolute_import

import os.path

__all__ = 'fetch_git_sha'


def fetch_git_sha(path, head=None):
    """
    >>> fetch_git_sha(os.path.dirname(__file__))
    """
    if not head:
        head_path = os.path.join(path, '.git', 'HEAD')

        with open(head_path, 'r') as fp:
            head = fp.read().strip()

        if head.startswith('ref: '):
            head = head[5:]
            revision_file = os.path.join(
                path, '.git', *head.split('/')
            )
        else:
            return head
    else:
        revision_file = os.path.join(path, '.git', 'refs', 'heads', head)

    if not os.path.exists(revision_file):
        # Check for Raven .git/packed-refs' file since a `git gc` may have run
        # https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery
        packed_file = os.path.join(path, '.git', 'packed-refs')
        if os.path.exists(packed_file):
            with open(packed_file) as fh:
                for line in fh:
                    line = line.rstrip()
                    if line and line[:1] not in ('#', '^'):
                        try:
                            revision, ref = line.split(' ', 1)
                        except ValueError:
                            continue
                        if ref == head:
                            return revision

    with open(revision_file) as fh:
        return fh.read().strip()

我将此文件命名为versioning.py,并在需要导入文件路径作为参数的地方导入“ fetch_git_sha”。

希望对您有所帮助;)

答案 9 :(得分:1)

我遇到了这个问题并通过实现这个功能解决了它。 https://gist.github.com/NaelsonDouglas/9bc3bfa26deec7827cb87816cad88d59

MarksDriver

答案 10 :(得分:1)

我遇到了与 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,类似于 returned by git describe,这意味着我 1 提交之后标签 v0.1.2 和提交的 7 位哈希值是 fb41223

它有一些限制:目前它没有显示存储库是否脏和always shows a 7-digit hash的选项,但是不需要安装 git,因此可以选择权衡。< /p>

编辑:如果由于选项 pip install 导致命令 --pure 出错(问题解释为 here),请选择两者之一可能的解决方案:

  1. 首先安装 Dulwich 软件包的依赖项: pip install urllib3 certifi && pip install dulwich --global-option="--pure"
  2. 不使用纯选项安装:pip install dulwich。这将在您的系统中安装一些平台相关文件,但它会improve the package's performance

答案 11 :(得分:0)

如果子进程不是可移植的,并且您不想安装软件包来完成这种简单的操作,则也可以这样做。

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()

我仅在我的存储库上对此进行了测试,但它似乎表现得非常稳定。