Перехід від CVS до Git: $ Id $ еквівалент?


124

Я прочитав купу запитань про прості засоби управління вихідним кодом, і Git видався розумним вибором. У мене він працює і працює, і він працює добре. Один із аспектів, який мені подобається у CVS - це автоматичне збільшення номера версії.

Я розумію, що це має менший сенс у розподіленому сховищі, але як розробник я хочу / потребую чогось подібного. Поясню, чому:

Я використовую Emacs. Періодично проходжу і шукаю нові версії вихідних файлів Lisp для сторонніх пакетів. Скажіть, у мене є файл, foo.el, який за заголовком є ​​версією 1.3; якщо я шукаю останню версію і бачу, що вона 1,143 або 2,6 чи що завгодно, я знаю, що я сильно відстаю.

Якщо замість цього я побачу пару хешей з 40 символів, я не знаю, що пізніше, і не маю уявлення про те, наскільки це пізніше. Я б абсолютно ненавиджу це, якби мені довелося вручну перевірити ChangeLogs, щоб зрозуміти, наскільки я застаріла.

Як розробник, я хочу поширити цю люб’язність, як я це бачу, на людей, які використовують мої результати (і, можливо, я жартую, що хто є, але залишимо це на сторону на хвилину). Мені не хочеться кожен раз збільшувати прокляте число, або часову позначку чи щось подібне. Це справжня PITA, і я це знаю з досвіду.

То які альтернативи у мене є? Якщо я не можу отримати $ Id: $ еквівалент, як ще я можу надати те, що шукаю?

Я мушу зазначити, що моє сподівання полягає в тому, що кінцевий користувач НЕ буде встановлений Git, і навіть якщо вони будуть, він не матиме локального сховища (дійсно, я сподіваюся, що не зробить його доступним таким чином).

Відповіді:


67

SHA - це лише одне представлення версії (хоч і канонічної). git describeКоманда пропонує інші , і робить це дуже добре.

Наприклад, коли я запускаю git describeв моїй головній гілці мого клієнтського джерела пам'яті , я отримую це:

2.2-16-gc0cd61a

Це говорить про дві важливі речі:

  1. З цього часу в дереві було зареєстровано 16 річних
  2. Точне вихідне дерево може відображатися на клоні кого - небудь ще.

Скажімо, ви, наприклад, ви упакували versionфайл із джерелом (або навіть переписали весь вміст для розповсюдження), щоб показати це число. Скажімо, упакована версія була 2.2-12-g6c4ae7a(не випуск, а дійсна версія).

Тепер ви можете точно бачити, як далеко ви позаду (4 коміти), і ви можете точно бачити, які 4 коміти:

# The RHS of the .. can be origin/master or empty, or whatever you want.
% git log --pretty=format:"%h %an %s" 2.2-12-g6c4ae7a..2.2-16-gc0cd61a
c0cd61a Dustin Sallings More tries to get a timeout.
8c489ff Dustin Sallings Made the timeout test run on every protocol on every bui
fb326d5 Dustin Sallings Added a test for bug 35.
fba04e9 Valeri Felberg Support passing an expiration date into CAS operations.

1
Використовувати це не вдасться, коли ви об’єднаєте гілку розробки, тоді як у майстра були деякі виправлення. Кількість комітетів після останньої версії зміниться. Хеш не є надійним, оскільки хтось може відновити всю справу за допомогою filter-branchчогось.
LeMike

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

55

На сьогоднішній день існує підтримка $ Id: $ у Git. Щоб увімкнути його для файлу README, ви поставите "README ідентифікатор" у .gitattributes . Підтримувані підстановки на імена файлів підтримуються. Див штучні gitattributes для деталей.


14
Це дає вам sha1 блобу, але не sha1 комітету. Корисно, просто не як ідентифікатор для фіксації.
Стівен Дженнінгс

4
git не має механізму розширення ключових слів, як $Id$згаданий. Що зберігається подалі - саме те, що ви отримуєте. У будь-якому випадку, версія належить до повної колекції файлів, що складають фіксацію, а не до одного файлу зокрема (Ця ідея є залишком від днів RCS, або, можливо, тут винна SCCS ... Оскільки CVS - це просто прославлений інтерфейс до RCS, і SVN намагається бути CVS-роботоподібним, він застряг.).
фонбранд

32

Це не необгрунтований запит від ОП.

Моє використання:

  1. Я використовую Git для власного особистого коду, тому немає співпраці з іншими.
  2. Я зберігаю там системні сценарії Bash, які можуть зайти, /usr/local/binколи вони будуть готові.

Я використовую три окремі машини з тим же сховищем Git на ньому. Було б непогано знати, у якій "версії" файлу, в якому я зараз перебуваю, /usr/local/binне потрібно робити посібник "diff -u <repo version> <version in / usr / local / bin>".

Для тих, хто з вас негативний, пам’ятайте, що є й інші випадки використання. Не всі використовують Git для спільної роботи з файлами в сховищі Git, які є їх "остаточним" місцем розташування.

Як би там не було, я створив файл атрибутів у сховищі так:

cat .git/info/attributes
# see man gitattributes
*.sh ident
*.pl ident
*.cgi ident

Потім покладіть $ Id $ кудись у файл (я люблю ставити його після шебангу).

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

git commit foo.sh
rm foo.sh
git co foo.sh

І тоді ви побачите розширення, наприклад:

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

Деякі корисні відомості містяться в розділі Як увімкнути рядок ident для сховища Git? .


3
Слід зазначити, що це ідентифікує поточний файл (blob), а не поточний
комітет

3
Що git coробити? Я отримав повідомлення про помилку " git: 'co' is not a git command. See 'git --help'." Це має бутиgit checkout ?
Пітер Мортенсен

23

Не впевнений, що це коли-небудь буде в Git. Щоб процитувати Лінус :

"Вся концепція заміни ключових слів є абсолютно ідіотською. Це банально робити" поза "фактичного відстеження вмісту, якщо ви хочете мати його під час випуску дерев у вигляді кульових куль тощо).

Проте перевірити журнал досить просто - якщо ви відстежуєте стабільну гілку foo.el, ви можете побачити, які нові комісії є в журналі стійкої гілки, які відсутні у вашій локальній копії. Якщо ви хочете імітувати внутрішній номер версії CVS, ви можете порівняти часову позначку останньої комісії.

Редагувати: ви повинні написати або використовувати для цього чужі сценарії, звичайно, не робити цього вручну.


26
Так, я прочитав частину цього довгого рядка електронних листів про розширення ключових слів. Ставлення Лінуса було майже достатньо, щоб повністю відключити мене від git.
Джо Касадонте

15
Так, іноді йому не вистачає ввічливості, але він зазвичай правильний, і він, безумовно, стоїть на темі розширення ключових слів.
Бомбе

Необхідне відстеження версій. git використовується в багатьох інших інфраструктурах, крім чистої розробки, де можна прочитати код, щоб визначити, чи є це сенс. Але коли система контролю ревізії використовується для відстеження файлів з довільним вмістом, тоді ви повинні мати певні засоби знати офіційний реліз. git, не кажучи вже про журнал git не на машині, на яку були натиснуті .ini, .conf, .html та інші файли.
rjt

7
Лінус прокоментував лише один аспект розширення ключових слів - відстеження випуску. Але це не єдина мета цього. Ця цитата наочно демонструє ставлення людини, але нічого корисного з цього питання не говорить. Типовий політичний трюк "заявляй очевидний у піднесений спосіб", а натовп - твій. Проблема полягає в тому, що натовп за визначенням дурний, бо у нього всього один мозок. Які чітко пояснюють ситуацію з git та розширенням ключових слів. Один ідіот сказав "ні" і всі підбадьорились!
AnrDaemon

1
@AnrDaemon не тільки це, git тепер додав підтримку $Id$через identатрибут, як згадується в іншій відповіді тут, показуючи, що навіть сам git не є заручником думки Лінуса.
orip

21

Як я писав раніше :

Автоматично згенеровані теги Id, які показують розумний номер версії, неможливо зробити з такими інструментами DSCM, як Bazaar, оскільки всі напрямки розвитку можуть відрізнятися від усіх інших. Тож хтось може звернутися до версії "1.41" файлу, але ваша версія "1.41" цього файлу інша.

В основному, $ Id $ не має сенсу з Bazaar, Git та іншими інструментами управління розповсюдженим вихідним кодом.


6
Правильно, я прочитав це перед публікацією, і саме тому я попросив більш загальне рішення основної проблеми. Я думаю, що прагнення окремого файлу мати версію # є законним, як і неможливість git запропонувати рішення.
Джо Касадонте

Це не нездатність Git, це нездатність всіх розподілених SCM. Якщо вам дуже потрібні значущі номери версій, використовуйте Subversion або CVS або іншу централізовану систему.
Бомбе

7
що не в тому, що просто виплюнути хеш замість "номера версії"? Я хочу виписки журналу, веб-сторінки налагодження та параметри "--version" на внутрішніх скриптах, які легко підкажуть мені, яка редакція працює, де я можу перевірити цей конкретний хеш і побачити, чому він веде себе таким, яким він є. Це спрощує управління розгорнутими програмами .... і я не хочу, щоб якийсь гак фіксації, який вважає, що кожне зобов'язання є зміною кожного файлу, який містив у ньому тег $ Id $.
nairbv

1
хеш файлу, над яким ви працюєте, працював би так само, як і "версію", якщо ви можете шукати його в git за цим id
Ерік Аронесті

2
@Brian - згідно з редакцією ОП, кінцевий користувач хоче знати номер версії, але не має доступу до git чи журналів git. У цьому випадку хеш - це безглузде число, а не номер версії. DSCM не надає допомоги у вирішенні цієї потреби.
Джессі Чісгольм

10

У мене була така ж проблема. Мені потрібна була версія, яка була простішою за хеш-рядок і доступна для людей, які використовують цей інструмент, не потребуючи підключення до сховища.

Я зробив це за допомогою гака, який попередньо здійснює Git, і змінив сценарій, щоб мати можливість автоматично оновлюватись.

Я базую версію за кількістю виконаних комісій. Це невелика умова перегонів, оскільки двоє людей можуть вчинити одночасно, і обидва думають, що вони роблять один і той же номер версії, але у нас не так багато розробників для цього проекту.

Як приклад, у мене є сценарій, який я перевіряю, що знаходиться в Ruby, і я додаю до нього цей код - це досить простий код, тому його легко перенести на різні мови, якщо ви перевіряєте щось іншою мовою (хоча, очевидно, це не буде легко працювати з не запущеними чеками, такими як текстові файли). Я додав:

MYVERSION = '1.090'
## Call script to do updateVersion from .git/hooks/pre-commit
def updateVersion
  # We add 1 because the next commit is probably one more - though this is a race
  commits = %x[git log #{$0} | grep '^commit ' | wc -l].to_i + 1
  vers = "1.%0.3d" % commits

  t = File.read($0)
  t.gsub!(/^MYVERSION = '(.*)'$/, "MYVERSION = '#{vers}'")
  bak = $0+'.bak'
  File.open(bak,'w') { |f| f.puts t }
  perm = File.stat($0).mode & 0xfff
  File.rename(bak,$0)
  File.chmod(perm,$0)
  exit
end

І тоді я додаю до сценарію параметр командного рядка (-updateVersion), тому якщо я називаю його як "інструмент -updateVersion", він просто викликає updateVersion для інструменту, який змінює значення "MYVERSION" сам по собі, а потім виходить (ви могли б нехай він також оновлює інші файли, якщо вони також відкриваються, якщо ви хотіли).

Після налаштування я переходжу до голови Git і створюю виконуваний одно рядковий скрипт bash в .git/hooks/pre-commit.

Сценарій просто змінюється в голові каталогу Git і викликає мій сценарій -updateVersion.

Кожен раз, коли я перевіряю, чи виконується скрипт перед фіксацією, він запускає мій скрипт із -updateVersion, а потім змінна MYVERSION оновлюється залежно від кількості комісій. Магія!


Тож чи слід називати ваш сценарій Ruby updateVersion git updateVersion? Будь ласка, покладіть кілька зразків, як це називається.
rjt

Я роблю варіант (-updateVersion) для скрипту, який я перевіряю, і викликає функцію 'updateVersion' (у цьому випадку я намагаюся змінити номер версії в самому скрипті). Тоді я просто роблю команду оболонки oneliner, яка викликає мій скрипт за допомогою -updateVersion, а потім оновляється перед кожною реєстрацією.
David Ljung Madison Stellar

8

Якщо мати ключові слова $ важливо для вас, то, можливо, ви можете спробувати подивитися на Mercurial ? Він має розширення hgkeyword, яке реалізує те, що ви хочете. Mercurial цікавий як DVCS так чи інакше.


8

Щось робиться з репозиторіями Git - це використовувати tagоб'єкт. Це можна використовувати для тегування коміту будь-яким типом рядка та може бути використано для позначення версій. Ви можете бачити теги у сховищі з git tagкомандою, яка повертає всі теги.

Тег легко перевірити. Наприклад, якщо є тег, v1.1ви можете перевірити цей тег у такій гілці:

git checkout -b v1.1

Оскільки це об’єкт верхнього рівня, ви побачите всю історію цього комітету, а також зможете запускати розрізники, вносити зміни та злиття.

Мало того, але тег зберігається, навіть якщо гілка, на якій він був, була видалена без об'єднання назад у основний рядок.


6
Чи існує спосіб, щоб цей тег автоматично вставити у файл за допомогою git? Дякую!
Джо Касадонте

1
Якщо ви маєте на увазі розширення ключових слів? Не наскільки я знаю. якщо ви будуєте продукцію, ви можете отримати інформацію як частину сценарію збирання та вставити її десь у вбудований продукт. Спробуйте man git-опис, який дає останню тег, кількість комітетів після цього тегу та поточний хеш.
Абізерн

Так, теги та інша пов'язана інформація тепер можуть редагуватися у файли автоматично за допомогою git за допомогою export-substфункції gitattributes(5). Це, звичайно, вимагає використання git archiveдля створення випусків, і лише в отриманому файлі tar буде видно зміни заміни.
Грег А. Вудс

4

Якщо я правильно розумію, по суті, ви хочете знати, скільки комітетів відбулося в даному файлі з моменту останнього оновлення.

Спочатку отримайте зміни у віддаленому походження, але не об’єднуйте їх у свою masterгілку:

% git fetch

Потім отримайте журнал змін, які відбулися в заданому файлі між вашою masterфілією та віддаленим пристроєм origin/master.

% git log master..origin/master foo.el

Це дає вам повідомлення журналу про всі комісії, що відбулися у віддаленому сховищі з моменту останнього об'єднання origin/masterу ваше master.

Якщо ви просто хочете порахувати зміни, перегляньте їх wc. Скажіть так:

% git rev-list master..origin/master foo.el | wc -l

1
Отже, не використовуйте log: git rev-list master..origin / master | wc -l
Дастін

4

Якщо ви просто хочете, щоб люди змогли зрозуміти, наскільки вони застаріли, Git може повідомити про це кількома досить простими способами. Наприклад, вони порівнюють дати останнього вчинення на своєму багажнику та ваш багажник. Вони можуть використовувати, git cherryщоб побачити, скільки комісій відбулося у вашому багажнику, яких немає у їхньому.

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

Крім того, я б не намагався поширювати люб’язно ввічливість, якщо ви не впевнені, що цього хочуть. :)


Якщо дати порівняно з датами, введіть у файл файл DateTImeStamp. git має так багато інших випадків використання, ніж лише розробники. ІТ у цій галузі потрібно знати, чи файл .INI або .conf на робочій станції, що наразі виправляється, усувається десь поблизу від поточного.
rjt

Чи буде достатньо простого часового позначення? Неправильна гілка може мати привабливу позначку часу та все ж бути менш коректною.
користувач2066657

4

Щоб застосувати розширення до всіх файлів у всіх підкаталогах репозиторію, додайте .gitattributesфайл до каталогу верхнього рівня у сховищі (тобто там, де ви зазвичай розмістили .gitignoreфайл), що містить:

* ident

Щоб побачити це по суті, потрібно спочатку зробити ефективну перевірку файлів (файлів), наприклад, видалити або відредагувати їх будь-яким способом. Потім відновіть їх за допомогою:

git checkout .

І вам слід побачити $Id$замінені чимось на кшталт:

$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $

Від man gitattributes:

ідентич

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

Цей ідентифікатор змінюватиметься кожного разу, коли буде введено нову версію файлу.


3

Ідентифікатори RCS приємні для однофайлових проектів, але для будь-якого іншого $ Id $ нічого не говорить про проект (якщо тільки ви не примусово перевіряєте фіктивний файл на макетну версію файлу).

Все ж може бути цікаво, як отримати еквіваленти $ Author $, $ Date $, $ Revision $, $ RCSfile $ тощо на рівні файлу або на рівні фіксації (як розмістити їх там, де деякі ключові слова - це інше питання). Я не маю відповіді на це, але бачу вимогу оновити їх, особливо коли файли (зараз у Git) походять з RCS-сумісних систем (CVS).

Такі ключові слова можуть бути цікавими, якщо джерела поширюються окремо від будь-якого сховища Git (це теж я роблю). Моє рішення таке:

Кожен проект має власну каталогію, а в корені проекту у мене є текстовий файл, названий у .versionякому вміст описує поточну версію (ім'я, яке буде використано при експорті джерел).

Під час роботи над наступним випуском сценарій витягує це .versionчисло, дескриптор версії Git (як git describe) і монотонне число збірки в .build(плюс хост і дата) в автоматично створений вихідний файл, який пов'язаний з остаточною програмою, так що ви можете знайти з якого джерела і коли воно було побудоване.

Я розробляю нові функції в окремих гілках, і перше, що я роблю, - додавати n(для "наступного") до .versionрядка (кілька гілок, що походять з одного кореня, використовуватимуть те саме тимчасове .versionчисло). Перед випуском я вирішую, які гілки об’єднати (сподіваюся, всі мають однакове .version). Перш ніж здійснити злиття, я оновлююсь .versionдо наступного числа (основне або незначне оновлення, залежно від об'єднаних функцій).


3

Якщо ви хочете, щоб інформація про фіксацію git була доступна у вашому коді, тоді вам потрібно зробити попередньо побудований крок, щоб отримати її там. У bash для C / C ++ це може виглядати приблизно так:

prebuild.sh

#!/bin/bash
commit=$(git rev-parse HEAD)
tag=$(git describe --tags --always ${commit})
cat <<EOF >version.c
#include "version.h"
const char* git_tag="${tag}";
const char* git_commit="${commit}";
EOF

з version.hвиглядом:

#pragma once
const char* git_tag;
const char* git_commit;

Потім, де вам це потрібно, у вашому коді #include "version.h"та довідці git_tagабо git_commitза потребою.

І у вас Makefileможе бути щось подібне:

all: package
version:
  ./prebuild.sh
package: version
  # the normal build stuff for your project

Це має перевагу:

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

Ця реалізація prepublish.shмає недоліки:

  • примушування до перекомпіляції, навіть якщо git_tag/ git_commitне змінилося.
  • він не враховує локально модифіковані файли, які не були зроблені, але впливають на збірку.
    • використовувати, git describe --tags --always --dirtyщоб зловити цей випадок використання.
  • забруднює глобальний простір імен.

Фанер, prebuild.shякий міг би уникнути цих питань, залишається читачем як вправа.


1

Я погоджуюся з тими, хто вважає, що заміна лексеми належить до створення інструментів, а не до засобів контролю версій.

Ви повинні мати якийсь інструмент автоматизованого випуску для встановлення ідентифікаторів версії у своїх джерелах під час тегу релізу.


2
.INI .conf і .txt зазвичай не мають інструменту збирання.
rjt

Але ви можете зламати разом сценарій випуску, який приймає поточний тег Git і записує його у файл або щось подібне.
Marnen Laibow-Koser

1

Імена тегів та іншу пов’язану інформацію тепер Git може редагуватись безпосередньо у файли автоматично за допомогою export-substфункції gitattributes(5). Це, звичайно, вимагає використання git archiveдля створення випусків, і лише в отриманому файлі tar буде видно зміни заміни.

Наприклад, у .gitattributesфайл помістіть такий рядок:

* export-subst

Потім у вихідні файли ви можете додати такий рядок:

#ident  "@(#)PROJECTNAME:FILENAME:$Format:%D:%ci:%cN:%h$"

І він розшириться, щоб виглядати так у випуску, створеному, наприклад git archive v1.2.0.90,:

#ident  "@(#)PROJECTNAME:FILENAME:HEAD -> master, tag: v1.2.0.90:2020-04-03 18:40:44 -0700:Greg A. Woods:e48f949"

0

Оскільки ви використовуєте Emacs, вам може пощастить :)

Я зіткнувся з цим питанням збігом обставин, а також за збігом обставин, на який я потрапив Lively кілька днів тому, пакет Emacs, який дозволяє мати в своєму документі жваві фрагменти Emacs Lisp. Я не намагався це бути чесним, але мені прийшло в голову, читаючи це.


0

Я також прийшов із SCCS, RCS та CVS (%W% %G% %U% ).

У мене був подібний виклик. Мені хотілося знати, у якій версії був фрагмент коду в будь-якій системі, на якій він працює. Система може бути або не може бути підключена до будь-якої мережі. У системі може бути або не встановлено Git. У системі може бути або не бути встановлено сховище GitHub.

Я хотів однакове рішення для декількох типів коду (.sh, .go, .yml, .xml тощо). Я хотів, щоб будь-яка людина без знання Git чи GitHub могла відповісти на запитання "Яку версію ти працюєш?"

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

https://github.com/BradleyA/markit

git clone https://github.com/BradleyA/markit
cd markit

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