Respostas:
O git describe
comando é uma boa maneira de criar um "número de versão" apresentável por humanos do código. Dos exemplos na documentação:
Com algo como a árvore atual do git.git, recebo:
[torvalds@g5 git]$ git describe parent v1.0.4-14-g2414721
ou seja, o cabeçalho atual do meu ramo "pai" é baseado na v1.0.4, mas como ele tem alguns commits além disso, o description adicionou o número de commits adicionais ("14") e um nome de objeto abreviado para o commit próprio ("2414721") no final.
No Python, você pode fazer algo como o seguinte:
import subprocess
label = subprocess.check_output(["git", "describe"]).strip()
fatal: No names found, cannot describe anything.
git describe --always
fará o fallback para o último commit se nenhuma tag for encontrada
git describe
normalmente requer pelo menos uma tag. Se você não possui tags, use a --always
opção Veja a documentação de descrição do git para mais informações.
Não há necessidade de obter dados do git
comando por conta própria. O GitPython é uma maneira muito boa de fazer isso e muitas outras git
coisas. Ele ainda oferece suporte ao "melhor esforço" para o Windows.
Depois que pip install gitpython
você pode fazer
import git
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
ImportError: No module named gitpython
. Você não pode contar com a instalação do usuário final gitpython
, e exigir que ele o instale antes que seu código funcione não o torna portátil. A menos que você inclua protocolos de instalação automática, nesse ponto, não será mais uma solução limpa.
pip
/ requirements.txt
) em todas as plataformas. O que não é "limpo"?
import numpy as np
pode ser assumido em todo o fluxo de pilha, mas a instalação do gitpython está além de 'clean' e 'portable'. Eu acho que essa é de longe a melhor solução, porque não reinventa a roda, oculta a implementação feia e não sai por aí cortando a resposta do git do subprocesso.
pip
ou a capacidade de instalar facilmente pip
. Nesses cenários modernos, uma pip
solução é tão portátil quanto uma solução de "biblioteca padrão".
Esta postagem contém o comando, a resposta de Greg contém o comando subprocesso.
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'])
.decode('ascii').strip()
para decodificar a sequência binária (e remova a quebra de linha).
numpy
possui uma rotina multiplataforma de boa aparência em 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
ditado era necessária para a funcionalidade de plataforma cruzada. A resposta de Yuji não, mas talvez isso funcione no UNIX e no Windows.
.decode('ascii')
funcione - caso contrário, a codificação é desconhecida.
Se o subprocesso não for portátil e você não quiser instalar um pacote para fazer algo tão simples, você também poderá fazer isso.
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()
Eu só testei isso nos meus repositórios, mas parece funcionar de maneira consistente.
Aqui está uma versão mais completa da resposta de Greg :
import subprocess
print(subprocess.check_output(["git", "describe", "--always"]).strip().decode())
Ou, se o script estiver sendo chamado de fora do repositório:
import subprocess, os
os.chdir(os.path.dirname(__file__))
print(subprocess.check_output(["git", "describe", "--always"]).strip().decode())
os.chdir
, o cwd=
arg pode ser usado check_output
para alterar temporariamente o diretório de trabalho antes de executar.
Se você não tiver o git disponível por algum motivo, mas tiver o repositório git (a pasta .git foi encontrada), poderá buscar o hash de confirmação em .git / fetch / heads / [branch]
Por exemplo, usei o seguinte snippet rápido e sujo do Python executado na raiz do repositório para obter o ID de confirmação:
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]
git rev-parse HEAD
na linha de comando. A sintaxe de saída deve ser óbvia.