Git에서 현재 커밋 해시를 같은 커밋의 파일에 쓰는 방법


131

Git hooks로 멋진 일을하려고하지만 실제로 어떻게 해야하는지 (또는 가능한지) 모르겠습니다.

내가해야 할 일은 : 모든 커밋마다 해시를 가져 와서 커밋의 파일을이 해시로 업데이트하고 싶습니다.

어떤 아이디어?


12
기본적으로 웹 응용 프로그램이 있으며 해당 응용 프로그램의 설치된 버전을 해당 버전과 연결된 정확한 커밋과 연결하려고합니다. 내 초기 아이디어는 커밋 해시로 일종의 about.html 파일을 업데이트하는 것이 었습니다. 그러나 git의 객체 모델을 연구 한 후에는 이것이 불가능하다는 것을 깨달았습니다. = /
Felipe Kamakura

29
이것은 매우 실용적인 문제입니다. 나도 만났다!
Li Dong

7
저의 프로그램은 "myprog starting up, v.56c6bb2"와 같은 메시지를 로그에 작성하고 싶습니다. 누군가가 버그를 파일과 나에게 로그 파일을 전송하는 경우 그 방법은, 나는 알 수 정확히 내 프로그램의 버전이 실행되는 것을.
Edward Falk

5
@Jefromi, 실제 사용 사례는 실제로 매우 일반적이며 초보자에게 매우 쉽게 맞습니다. 실제 버전을 어떻게 기준선 파일에 "각인"시키는 것이 기본적인 요구이며, 그것이 왜 잘못된 생각이 될 것인지는 분명하지 않습니다. (초보자를 기억하십시오.) 많은 프로젝트에는 버전을 라이브 파일로 가져와 스탬프 할 수있는 빌드 / 설치 / 배포 단계가 전혀 없습니다. 사전 커밋 대신 사후 점검 후크가 이러한 경우에도 도움이 될 수 있습니다.
Sz.

이건 불가능 해! 이 작업을 수행 할 수 있다면 SHA-1 해시 알고리즘을 위반 한 것입니다. ericsink.com/vcbe/html/cryptographic_hashes.html
betontalpfa

답변:


82

SHA1을 추적되지 않은 파일 에 배치 하고 빌드 / 설치 / 배포 프로세스의 일부로 생성 된 것과 비슷한 작업을 수행하는 것이 좋습니다 . 분명히하기 쉽습니다 ( git rev-parse HEAD > filename또는 아마도 git describe [--tags] > filename), git의 추적과 다른 파일로 끝나는 것과 같은 미친 짓을 피합니다.

그러면 코드에서 버전 번호가 필요할 때이 파일을 참조하거나 빌드 프로세스에서 정보를 최종 제품에 통합 할 수 있습니다. 후자는 실제로 git 자체가 버전 번호를 얻는 방법입니다. 빌드 프로세스는 저장소에서 버전 번호를 가져온 다음 실행 파일에 빌드합니다.


3
누군가이 작업을 수행하는 방법에 대해 단계별로 설명 할 수 있습니까? 아니면 적어도 올바른 방향으로 조금씩 움직입니까?
Joel Worsham

1
@Joel 어떻게해야합니까? 해시를 파일에 넣는 방법을 언급했다. 나머지는 아마도 빌드 프로세스에 관한 것입니까? 당신이 그 부분에 대해 묻고 싶다면 새로운 질문 일 것입니다.
Cascabel

1
필자의 경우, 모든 빌드에서 "gitversion.h"파일을 생성하는 규칙을 Makefile에 추가했습니다. 참조 stackoverflow.com/a/38087913/338479
에드워드 포크

1
"git-checkout"후크를 사용하여이를 자동화 할 수 있습니다. 문제는 후크를 수동으로 설치해야한다는 것입니다.
Edward Falk

14

현재 커밋 해시를 작성하는 것은 불가능합니다. 향후 커밋 해시를 미리 계산하면 파일을 수정하자마자 변경됩니다.

그러나 세 가지 옵션이 있습니다.

  1. 스크립트를 사용하여 '커밋 ID'를 늘리고 어딘가에 포함하십시오. 추한
  2. 해시를 저장할 파일을 무시하십시오. 별로 편리하지 않다
  3. 에서 pre-commit, 가게 이전 해시를 커밋 : 당신은 너무,이 의지 작업, 99.99 %의 경우에 커밋 삽입 / 수정하지 마십시오. 최악의 경우 여전히 소스 개정을 식별 할 수 있습니다.

나는 후크 스크립트를 작성 중이며 여기에 '완료되면'게시하지만 Duke Nukem Forever 이전에 출시되었습니다 :))

업데이트 : 코드 .git/hooks/pre-commit:

#!/usr/bin/env bash
set -e

#=== 'prev-commit' solution by o_O Tync
#commit_hash=$(git rev-parse --verify HEAD)
commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
commit_hash=$(echo "$commit" | head -1)
commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300

branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation

# Write it
echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py

이제 필요한 것은 prev_commit,branch페어를 실제 커밋 해시 로 변환하는 도구입니다. :)

이 방법으로 커밋을 병합 할 수 있는지 여부를 모르겠습니다. 곧 확인하겠습니다


13

누군가가 ident에 대한 "man gitattributes"섹션을 지적했습니다.

신분

속성 ident가 경로로 설정되면, git은 blob 객체의 $ Id $를 $ Id :로 대체하고 그 뒤에 40 자 16 진 blob 객체 이름이오고 그 뒤에 달러 기호 $가옵니다. 작업 트리 파일에서 $ Id :로 시작하고 $로 끝나는 모든 바이트 시퀀스는 체크인시 $ Id $로 바뀝니다.

당신이 그것에 대해 생각하면, 이것은 CVS, Subversion 등이하는 일입니다. 저장소를 보면 저장소의 파일에 항상 $ Id $가 포함되어 있음을 알 수 있습니다. 그것은 그것의 확장을 포함하지 않습니다. 텍스트가 펼쳐지는 것은 체크 아웃시에만 가능합니다.


8
ident커밋의 서두가 아니라 파일 자체의 해시입니다. 에서 git-scm.com/book/en/... : "하지만, 그 결과는 제한적으로 사용 당신이 CVS에서 키워드 대체를 사용했습니다 또는 파괴, 당신은 날짜 스탬프를 포함 할 경우 - SHA는 모두 도움이되지 않습니다. 왜냐하면 그것은 상당히 임의적이며 하나의 SHA가 다른 SHA보다 오래되었거나 새로운 것인지 알 수 없기 때문입니다. " filter작동하지만 커밋 정보를 파일에 넣을 수 있습니다.
Zach Young

11

gitattributesfilter속성 을 사용하면 됩니다. 커밋 ID를 삽입 하는 명령과smudgeclean 삭제합니다, 그것은 삽입있어 파일이 단지 때문에 변경하지 않을 것이라고 등이 ID를 커밋 명령을 사용합니다.

따라서 커밋 ID는 파일의 Blob에 저장되지 않습니다. 작업 복사본에서 확장되었습니다. 실제로 커밋 ID를 Blob에 삽입하면 무한 재귀 작업이됩니다. ☺)이 트리를 복제하는 사람은 자신을 위해 속성을 설정해야합니다.


7
재귀 작업이 아닌 불가능한 작업. 커밋 해시는 파일 해시에 의존하는 트리 해시에 의존하며, 파일 내용에 의존합니다. 자기 일관성을 가져야합니다. SHA-1 해시에 대해 일종의 [일반화 된] 고정 소수점 을 찾을 수 없다면 .
Jakub Narębski

1
@Jakub, git에는 결과 해시를 수정하지 않는 추적 파일을 만들 수있는 트릭이 있습니까? 해시를 재정의하는 방법 일 수 있습니다. 그것은 해결책이 될 것입니다 :)
kolypto

@o_O Tync : 불가능합니다. 변경된 파일은 파일의 변경된 해시를 의미합니다. 이것은 의도적으로 설계된 것이며 해시 함수의 정의입니다.
Jakub Narębski

2
이것은 매우 좋은 솔루션이지만 리포지토리를 복제 할 때마다 수동으로 설치해야하는 후크와 관련이 있습니다.
Edward Falk

7

커밋 박스 밖에서 생각하십시오!

이것을 파일 후크 / 체크 아웃에 넣습니다.

#!/bin/sh
git describe --all --long > config/git-commit-version.txt

버전은 사용하는 모든 곳에서 사용할 수 있습니다.


3

커밋의 파일이 변경되면 커밋의 해시도 변경되기 때문에 실제로 그렇게하고 싶지는 않습니다.


1

git internals를 사용하여 이것이 왜 어려운 문제인지 살펴 보겠습니다. 현재 커밋의 sha1을 다음과 같이 얻을 수 있습니다.

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

기본적으로는에서 반환 한 메시지에 대해 sha1 체크섬을 실행합니다 git cat-file commit HEAD. 이 메시지를 살펴보면 즉시 두 가지 문제가 발생합니다. 하나는 트리 sha1이고 두 번째는 커밋 시간입니다.

이제 커밋 시간은 메시지를 변경하고 특정 시간에 커밋 또는 일정을 예약하는 데 걸리는 시간을 추측하여 쉽게 처리 할 수 ​​있습니다. 진정한 문제는에서 얻을 수있는 트리 sha1입니다 git ls-tree $(git write-tree) | git mktree. 기본적으로 ls-tree의 메시지에서 모든 파일과 해당 sha1 체크섬의 목록 인 sha1 체크섬을 수행하고 있습니다.

따라서 커밋 sha1 체크섬은 트리 sha1 체크섬에 의존하며,이 파일은 sha1 체크섬 파일에 직접 의존하며, 원을 완성하고 커밋 sha1에 의존합니다. 따라서 나 자신이 사용할 수있는 기술에 대한 순환 문제가 있습니다.

덜 안전한 체크섬을 사용하면 무차별 강제로 파일의 체크섬을 파일 자체에 쓸 수 있습니다. 그러나 sha1을 사용하여 해당 작업을 수행 한 작업에 대해서는 알지 못합니다. 이것은 불가능하지는 않지만 현재의 이해로는 불가능합니다 (그러나 몇 년 후에 누가 알 수 있는지는 사소한 것입니다). 그러나 (blob) 체크섬의 (트리) 체크섬에 대한 (커밋) 체크섬을 파일에 써야하기 때문에 여전히 무차별 대입하기가 더 어렵습니다.


파일을 커밋하고 체크 아웃하고 최신 커밋 해시를 각 소스 코드 파일의 시작 부분에 주석으로 넣을 수있는 방법이 있습니까? 그런 다음 빌드하고 실행합니까?
John Wooten
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.