Geçerli git karmasını bir Python betiğinde edinin


165

Geçerli git karma bir Python betiği ( bu çıkışı üreten kodun sürüm numarası olarak) çıkışına dahil etmek istiyorum.

Python betiğimdeki mevcut git karmasına nasıl erişebilirim?


7
git rev-parse HEADKomut satırından başlayın . Çıktı sözdizimi açık olmalıdır.
Mel Nicholson

Yanıtlar:


96

git describeKomut kodunun bir insan-prezentabl "sürüm numarası" yaratmanın iyi bir yoldur. Belgelerdeki örneklerden:

Geçerli ağaç git.git gibi bir şeyle:

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

yani "ana" dalımın şu anki başkanı v1.0.4'e dayanıyor, ancak bunun üzerinde birkaç taahhüt bulunduğundan, açıklama ek taahhütlerin sayısını ("14") ve taahhüt için kısaltılmış bir nesne adını ekledi kendisi ("2414721").

Python içinden aşağıdakine benzer bir şey yapabilirsiniz:

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

3
Kod, git repo mevcut olmadan çalıştırılırsa, sürüm yazdırma kodunun kırılacağı dezavantajı vardır. Örneğin, üretimde. :)
JosefAssad

5
@JosefAssad: Üretimde bir sürüm tanımlayıcısına ihtiyacınız varsa, dağıtım prosedürünüz yukarıdaki kodu çalıştırmalı ve sonuç üretime dağıtılan koda "fırınlanmalıdır".
Greg Hewgill

14
Eğer etiket yoksa git açıklamanın başarısız olacağını unutmayın:fatal: No names found, cannot describe anything.
kynan

40
git describe --alwaysetiket bulunmazsa son işleme geri dönecek
Leonardo

5
@CharlieParker: git describenormalde en az bir etiket gerektirir. Herhangi bir etiketiniz yoksa, --alwaysseçeneği kullanın. Daha fazla bilgi için git açıklama belgelerine bakın .
Greg Hewgill

190

Komuttan gitkendiniz veri almak için hacklemeye gerek yok . GitPython bunu ve diğer birçok şeyi yapmanın çok güzel bir yoludur git. Hatta Windows için "en iyi çaba" desteğine sahiptir.

Sonra pip install gitpythonyapabilirsin

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

9
Değil emin Bu olduğunda size taşınabilir diyoruz nasıl @crishoj: ImportError: No module named gitpython. gitpythonYüklü son kullanıcıya güvenemezsiniz ve kodunuz çalışmaya başlamadan önce bunları yüklemelerini gerektiremezsiniz. Otomatik kurulum protokollerini dahil etmeyeceğiniz sürece, bu noktada artık temiz bir çözüm değildir.
user5359531

39
@ user5359531 Farklı olmaya yalvarıyorum. GitPython, platforma özgü ayrıntıları soyutlayan saf bir Python uygulaması sağlar ve tüm platformlarda standart paket araçları ( pip/ requirements.txt) kullanılarak yüklenebilir . "Temiz" ne değil?
crishoj

22
Python'da bir şeyler yapmanın normal yolu budur. OP bu gerekliliklere ihtiyaç duyarsa, bunu söylerlerdi. Zihin okuyucuları değiliz, her bir sorudaki her olasılığı tahmin edemeyiz. Bu şekilde delilik yatar.
OldTinfoil

14
@ user5359531, neden import numpy as npstackoverflow tüm boyunca kabul edilebilir belirsiz ama gitpython yüklemek 'temiz' ve 'taşınabilir' ötesinde. Bence bu en iyi çözüm, çünkü tekerleği yeniden icat etmiyor, çirkin uygulamayı gizliyor ve alt süreçten git'in cevabını hacklemiyor.
Jblasco

7
@ user5359531 Genel olarak her küçük soruna parlak yeni bir kütüphane atmamanız gerektiğine katılırken, "taşınabilirlik" tanımınız, geliştiricilerin uygulamaların çalıştığı tüm ortamlar üzerinde tam kontrole sahip olduğu modern senaryoları ihmal ediyor gibi görünüyor. 2018'de Docker kapları, sanal ortamlar ve makine görüntüleri (örn. AMI'ler) ile pipveya kolayca yükleme olanağı pip. Bu modern senaryolarda, bir pipçözüm "standart kütüphane" çözümü kadar portatiftir.
Ryan

106

Bu yazı şu komutu içeriyor, Greg'in cevabı alt işlem komutunu içeriyor.

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'])

32
Çizgiyi kesmeden elde etmek için sonuca bir şerit () ekleyin :)
çekirge

Belirli bir yolda git repo için bunu nasıl çalıştırırsınız?
pkamb

2
@pkamb Çalışmak istediğiniz git deposunun yoluna gitmek için os.chdir komutunu kullanın
Zac Crites

Şu anda teslim alınan revizyon şube başı değilse bu yanlış cevap vermeyecek mi?
en fazla

7
.decode('ascii').strip()İkili dizginin kodunu çözmek için a ekleyin (ve satır sonunu kaldırın).
pfm

13

numpygüzel görünümlü bir çoklu platform rutini vardır 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

2
Bunu beğendim, oldukça temiz ve harici kütüphaneler yok
13aal

Yuji'nin yanıtı , aynı sonucu veren tek bir kod satırında benzer bir çözüm sağlar. numpy"Minimal bir ortam inşa etmenin" neden gerekli olduğunu açıklayabilir misiniz ? (iyi bir nedenleri
varsayalım

Ben sadece onların repo fark ettim ve ilgilenen insanlar için bu soruya eklemek karar verdi. Windows'ta geliştirmiyorum, bu yüzden bunu test etmedim, ancak envplatformlar arası işlevsellik için dikteyi kurmanın gerekli olduğunu varsaymıştım . Yuji'nin cevabı işe yaramaz, ancak belki de UNIX ve Windows üzerinde çalışır.
ryanjdillon

Git suçuna bakıldığında, bunu 11 yıl önce SVN için bir hata düzeltmesi olarak yaptılar: github.com/numpy/numpy/commit/… Git için artık hata düzeltmesi gerekli değildir.
gparent

@ MD004 @ryanjdillon Yerel ayarları çalışacak şekilde ayarladılar .decode('ascii')- aksi takdirde kodlama bilinmiyor.
z0r

7

Alt işlem taşınabilir değilse ve bu kadar basit bir şey yapmak için bir paket yüklemek istemiyorsanız bunu da yapabilirsiniz.

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

Bunu sadece depolarımda test ettim ama oldukça tutarlı çalışıyor gibi görünüyor.


Bazen / refs / bulunamaz, ancak geçerli taahhüt kimliği "paketlenmiş refs" içinde bulunur.
am9417

7

İşte Greg'in cevabının daha eksiksiz bir sürümü :

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

Veya komut dosyası depo dışından çağrılıyorsa:

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

1
Bunun yerine kullanılması os.chdir, cwd=arg kullanılabilir check_outputçalıştırmadan önce geçici değişikliklere çalışma dizinine.
Marc

0

Herhangi bir nedenle git kullanılamıyor ancak git repo'nuz varsa (.git klasörü bulundu), kesin karmayı .git / fetch / heads / [branch] öğesinden alabilirsiniz.

Örneğin, taahhüt kimliğini almak için depo kökünde aşağıdaki hızlı ve kirli bir Python snippet'i kullandım:

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]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.