228

Pythonスクリプトの出力に現在のgitハッシュを含めたいと思います(その出力を生成したコードのバージョン番号として)。

Pythonスクリプトで現在のgitハッシュにアクセスするにはどうすればよいですか?

4

12 に答える 12

269

gitコマンドからデータを自分で取得することをハックする必要はありません。GitPythonは、これや他の多くのことを行うための非常に優れた方法ですgit。Windowsの「ベストエフォート」サポートもあります。

pip install gitpythonあなたができる後

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

このライブラリを使用する際に考慮すべき点。以下はgitpython.readthedocs.ioから抜粋したものです

システムリソースの漏洩

GitPythonは、システムリソースをリークする傾向があるため、長時間実行されるプロセス(デーモンなど)には適していません。これは、(メソッドに実装されている)デストラクタが__del__まだ決定論的に実行されていた時代に書かれました。

それでもそのようなコンテキストで使用したい場合は、コードベースで__del__実装を検索し、適切と思われるときに自分で呼び出すことをお勧めします。

リソースの適切なクリーンアップを保証するもう1つの方法は、GitPythonを、定期的に削除できる別のプロセスに分解することです。

于 2016-12-18T16:03:44.110 に答える
144

この投稿にはコマンドが含まれており、Gregの回答にはサブプロセスコマンドが含まれています。

import 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
于 2014-02-20T07:40:24.757 に答える
116

この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()
于 2013-02-20T21:06:49.187 に答える
16

グレッグの答えのより完全なバージョンは次のとおりです。

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())
于 2019-08-28T00:40:41.307 に答える
15

numpyその中に見栄えの良いマルチプラットフォームルーチンがあります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
于 2016-10-21T06:56:43.257 に答える
11

サブプロセスが移植可能でなく、これほど単純なことを行うためにパッケージをインストールしたくない場合は、これを行うこともできます。

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

私は自分のリポジトリでこれをテストしただけですが、かなり一貫して機能しているようです。

于 2019-05-21T20:11:50.900 に答える
6

これは、ゆうじ「富田」富田の答えを改良したものです。

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())
于 2021-02-20T14:57:59.903 に答える
4

ハッシュよりも少し多くのデータが必要な場合は、次を使用できます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

于 2020-08-26T14:37:21.903 に答える
2

何らかの理由で利用可能なgitがないが、gitリポジトリがある場合(.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]
于 2020-01-28T14:13:05.767 に答える
1

あなたが私のようなら:

  • マルチプラットフォームなので、サブプロセスがいつかクラッシュする可能性があります
  • Python 2.7を使用しているため、GitPythonは使用できません
  • そのためだけにNumpyを使いたくない
  • すでにセントリーを使用しています(古い減価償却バージョン:レイヴン)

次に(シェルは現在のファイルパスを検出しないため、これはシェルでは機能しません。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))

それでおしまい。

sendry_sdkに移行してレイヴンを離れたいと思ったので、別の解決策を探していましたが、しばらくの間レイヴンを使い続けたいと思う人もいるかもしれません。

これが私をこのスタックオーバーフローの問題に巻き込む議論でした

したがって、レイヴンなしでレイヴンのコードを使用することも可能です(説明を参照):

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」をインポートします。

それがあなたの何人かを助けることを願っています;)

于 2020-09-07T09:44:51.713 に答える
1

私はこの問題に遭遇し、この関数を実装することで問題を解決しました。 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)
于 2021-07-01T19:08:49.973 に答える
1

OPと同様の問題が発生しましたが、私の場合、ソースコードをzipファイルとしてクライアントに配信しており、Pythonがインストールされていることはわかっていますが、gitがインストールされているとは限りません。OPは彼のオペレーティングシステムを指定していなかったので、彼がgitをインストールしていれば、私はここで貢献できると思います。

コミットのハッシュのみを取得するには、Naelson Douglasの答えは完璧でしたが、タグ名を付けるために、dulwichpythonパッケージを使用しています。これは、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)

ここでこのコードを1つのリポジトリで実行したところ、git describeによって返されるv0.1.2-1-gfb41223ものと同様の出力が表示されました。つまり、タグv0.1.2の後に1コミットであり、コミットの7桁のハッシュはfb41223です。

いくつかの制限があります。現在、リポジトリがダーティであるかどうかを表示するオプションはなく、常に7桁のハッシュが表示されますが、gitをインストールする必要がないため、トレードオフを選択できます。

編集:pip installオプションが原因でコマンドにエラーが発生した場合--pure(問題はここで説明されています)、2つの可能な解決策のいずれかを選択してください。

  1. 最初にDulwichパッケージの依存関係をインストールします。 pip install urllib3 certifi && pip install dulwich --global-option="--pure"
  2. 純粋なオプションなしでインストールしますpip install dulwich。これにより、プラットフォームに依存するファイルがシステムにインストールされますが、パッケージのパフォーマンスが向上します
于 2021-07-28T20:30:17.123 に答える