Як можна в Git записати поточний хеш-фіксацію до файлу в тій самій комісії


131

Я намагаюся тут робити гаморні речі з гачками Git, але я не знаю, як це зробити (або якщо це можливо).

Що мені потрібно зробити: це в кожному комітеті я хочу взяти його хеш, а потім оновити файл у коміті з цим хешем.

Будь-які ідеї?


12
В основному у мене є веб-додаток, і я хочу пов’язати встановлену версію цього додатка з точною фіксацією, з якою пов’язана версія. Моя початкова ідея полягала в тому, щоб оновити своєрідний файл about.html за допомогою хеш-файлу. Але вивчивши модель об’єктів git, я зрозумів, що це щось неможливо = /
Феліпе Камакура

29
Це дуже практична проблема. Я теж наткнувся на це!
Лі Донг

7
Щодо мене, я хотів би, щоб моя програма написала таке повідомлення в журнали: "myprog start up, v.56c6bb2". Таким чином, якщо хтось подасть помилку і надсилає мені файли журналу, я можу точно дізнатися, в якій версії моєї програми працювала.
Едвард Фолк

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 Як робити що? Я згадав, як укласти хеш у файл; інше, мабуть, щось стосується вашого процесу збирання? Можливо, нове питання, якщо ви намагаєтесь задати цю частину.
Каскабель

1
У своєму випадку я додав правило до свого Makefile, яке генерує файл "gitversion.h" для кожної збірки. Дивіться stackoverflow.com/a/38087913/338479
Edward Falk

1
Можливо, ви зможете автоматизувати це за допомогою гачка "git-checkout". Проблема полягає в тому, що гачки повинні бути встановлені вручну.
Едвард Фолк

14

Неможливо записати поточний хеш комісій: якщо вам вдасться заздалегідь обчислити майбутній хеш комісії - він зміниться, як тільки ви зміните будь-який файл.

Однак є три варіанти:

  1. Використовуйте скрипт, щоб збільшити "виконувати ідентифікатор" і включити його кудись. Некрасивий
  2. .gitiгноруйте файл, в який ви збираєтеся зберігати хеш. Не дуже зручно
  3. У pre-commit, зберігайте попередній хеш-комікс :) Ви не змінюєте / не вставляєте комісії у 99,99% випадків, тож, ЦЕ БУДЕ працювати. У гіршому випадку ви все одно можете визначити версію джерела.

Я працюю над сценарієм гака, розміщу його тут "коли це буде зроблено", але все ж - раніше, ніж герцог Нукем назавжди випущений :))

Оновлення : код для .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

Хтось вказав мені на розділ "людина gitattributes" на ідентифікатор, який має таке:

ідентич

Коли ідентифікатор атрибута встановлений для шляху, git замінює $ Id $ в об'єкті blob на $ Id:, а потім - шістнадцятковий ім'я об'єкта blob у 40 символів, після чого знак $ долара при оформленні каси. Будь-яка послідовність байтів, яка починається з $ Id: і закінчується на $ у файлі робочого дерева, замінюється на $ Id $ при реєстрації.

Якщо ви подумаєте над цим, це також робить CVS, Subversion тощо. Якщо ви подивитеся на сховище, то побачите, що файл у сховищі завжди містить, наприклад, $ Id $. Він ніколи не містить розширення цього. Лише під час оформлення замовлення текст розгортається.


8
ident- хеш для самого файлу, а не прискорення фіксації. Від git-scm.com/book/en/… : "Однак, цей результат має обмежене використання. Якщо ви використовували заміну ключових слів у CVS або Subversion, ви можете включити позначку дати - SHA не все так корисно, тому що це досить випадково, і ви не можете сказати, чи одна SHA старша чи новіша за іншу ". filterзаймає роботу, але вона може отримати інформацію про фіксацію у файл (і з нього).
Zach Young

11

Цього можна досягти, використовуючи filterатрибут у gitattributes . Вам потрібно буде вказати smudgeкоманду, яка вставляє ідентифікатор фіксації, і cleanкоманду, яка видаляє його, щоб файл, в який вставлено, не змінювався лише через ідентифікатор фіксації.

Таким чином, ідентифікатор фіксації ніколи не зберігається у краплі файлу; він просто розширений у вашій робочій копії. (Власне введення ідентифікатора фіксації в крапку стане нескінченно рекурсивним завданням. ☺) Кожен, хто клонує це дерево, повинен встановити атрибути для себе.


7
Неможливе завдання, а не рекурсивне завдання. Ввести хеш залежить від хеша дерева, який залежить від хеша файлу, який залежить від вмісту файлу. Ви повинні отримати самоузгодженість. Якщо ви не знайдете якусь [узагальнену] фіксовану точку для хешу SHA-1.
Jakub Narębski

1
@Jakub, чи є якась хитрість у git, яка дозволить створювати відстежені файли, які не змінюють отриманий хеш? Можливо, якийсь спосіб переоцінити його хеш. Це буде рішення :)
kolypto

@o_O Tync: Неможливо. Змінений файл означає змінений хеш (файлу) - це і за конструкцією, і за визначенням хеш-функції.
Якуб Нарубський

2
Це досить хороше рішення, але майте на увазі, що це стосується гачків, які потрібно встановити вручну, коли ви клонуєте сховище.
Едвард Фолк

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. По суті, ви робите контрольну суму sha1 для повідомлення з ls-tree, що є переліком усіх файлів та їх контрольної суми sha1.

Тому ваша контрольна сума фіксації sha1 залежить від вашої контрольної суми sha1 дерева, що безпосередньо залежить від файлів контрольної суми sha1, яка завершує коло та залежить від sha1. Таким чином, у вас є кругова проблема з прийомами, доступними мені.

З менш захищеними контрольними сумами , було показано можливим записувати контрольну суму файлу у сам файл через грубу силу; однак я не знаю жодної роботи, яка б виконала це завдання з sha1. Це не неможливо, але поруч із неможливим із нашим теперішнім розумінням (але хто знає, можливо, через пару років це буде банально). Однак, це все ще важче піддається грубій силі, оскільки вам доведеться записати контрольну суму (фіксування) контрольної суми (дерева) контрольної суми (blob) контрольної суми у файл.


Чи є спосіб, щоб можна було скопіювати файли, а потім зробити замовлення та розмістити останній хеш-комісію як коментар на початку кожного файлу вихідного коду? Тоді будувати і запускати з цього?
Джон Вутен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.