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


124

Я прочитал кучу вопросов о простых инструментах управления исходным кодом, и Git показался мне разумным выбором. Он у меня есть и работает, и пока он работает хорошо. Один из аспектов, который мне нравится в CVS, - это автоматическое увеличение номера версии.

Я понимаю, что в распределенном репозитории это не имеет смысла, но как разработчик я хочу / нуждаюсь в чем-то подобном. Позвольте мне объяснить почему:

Я использую Emacs. Периодически я просматриваю и ищу новые версии исходных файлов Lisp для сторонних пакетов. Допустим, у меня есть файл foo.el, который, согласно заголовку, имеет версию 1.3; если я посмотрю на последнюю версию и увижу, что это 1.143 или 2.6 или что-то еще, я знаю, что сильно отстаю.

Если вместо этого я увижу пару 40-символьных хэшей, я не узнаю, какой из них будет позже, и не пойму, сколько позже. Я бы абсолютно ненавидел, если бы мне пришлось вручную проверять журналы изменений, чтобы понять, насколько я устарел.

Как разработчик, я хочу выразить эту любезность, как я это вижу, людям, которые используют мои результаты (и, возможно, я обманываю себя, что кто-то есть, но давайте оставим это на мгновение). Я не хочу, чтобы мне приходилось каждый раз самому увеличивать проклятое число, или временную метку, или что-то в этом роде. Это настоящая PITA, и я знаю это по опыту.

Итак, какие у меня есть альтернативы? Если я не могу получить эквивалент $ Id: $, как еще я могу предоставить то, что ищу?

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

Ответы:


67

SHA - это всего лишь одно из представлений версии (хотя и каноническое). git describe предлагает другие и делает это достаточно хорошо.

Например, когда я запускаю git describeв своей основной ветке своего клиентского источника Java memcached , я получаю следующее:

2.2-16-gc0cd61a

Это говорит о двух важных вещах:

  1. В этом дереве было ровно 16 коммитов, начиная с версии 2.2.
  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команду непосредственно перед сборкой, сохранить вывод в файле заголовка или иным образом встроить значение в свой код.
Джесси

56

К настоящему времени в Git есть поддержка $ Id: $. Чтобы включить его для файла README, вы должны поместить "README identity " в .gitattributes . Поддерживаются подстановочные знаки в именах файлов. Подробнее см. Man gitattributes .


14
Это дает вам sha1 блоба, но не sha1 коммита. Полезно, но не как идентификатор фиксации.
Стивен Дженнингс,

4
git не имеет механизма расширения ключевых слов, подобного $Id$упомянутому. Вы получаете именно то, что хранится отдельно. В любом случае версия принадлежит полному набору файлов, составляющих коммит, а не одному файлу в частности (эта идея - пережиток времен RCS, или, возможно, SCCS здесь виноват ... Поскольку CVS - это просто прославил интерфейс для RCS, а SVN пытается быть похожим на CVS, он застрял.).
vonbrand

32

Это не необоснованный запрос OP.

Мой вариант использования:

  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 $ (я люблю ставить его после shebang).

Коммит. Обратите внимание, что это не делает расширение автоматически, как я ожидал. Вам нужно пересобрать файл, например,

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

И тогда вы увидите расширение, например:

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

Полезная информация содержится в разделе Как включить строку идентификатора для репозитория Git? ,


3
Следует отметить, что это действительно определяет текущий файл (blob), а не текущую фиксацию
CharlesB

3
Что git coделать? Я получил сообщение об ошибке " git: 'co' is not a git command. See 'git --help'." Должно бытьgit checkout ?
Питер Мортенсен

23

Не уверен, что это когда-нибудь будет в Git. Чтобы процитировать Линус :

«Сама идея подстановки ключевых слов является совершенно идиотской. Это тривиально делать« вне »фактического отслеживания контента, если вы хотите, чтобы это происходило при создании деревьев релизов в виде тар-шаров и т. Д.»

Тем не менее, довольно легко проверить журнал - если вы отслеживаете стабильную ветку foo.el, вы можете увидеть, какие новые коммиты есть в журнале стабильной ветки, которых нет в вашей локальной копии. Если вы хотите имитировать внутренний номер версии CVS, вы можете сравнить отметку времени последней фиксации.

Edit: для этого нужно писать или использовать чужие скрипты, конечно, не делать это вручную.


26
Да, я прочитал часть этой длинной цепочки писем о расширении ключевых слов. Отношения Линуса было почти достаточно, чтобы полностью отвлечь меня от мерзости.
Джо Касадонте

15
Да, иногда ему не хватает вежливости, но обычно он прав, и он определенно касается темы расширения ключевых слов.
Bombe

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

7
Линус прокомментировал только один аспект расширения ключевых слов - отслеживание релизов. Но это не единственная его цель. Эта цитата ясно демонстрирует мужскую позицию, но ничего полезного о предмете не говорит. Типичный политический трюк «возвышенно заявлять о очевидном», и толпа принадлежит вам. Проблема в том, что толпа по определению глупа, потому что у нее всего один мозг. Что четко объясняет ситуацию с git и расширением ключевых слов. Один идиот сказал «нет», и все обрадовались!
AnrDaemon

1
@AnrDaemon не только это, теперь git добавил поддержку атрибута $Id$via ident, как упоминалось в другом ответе здесь, показывая, что даже сам git не является заложником мнения Линуса.
orip 01

21

Как я уже писал ранее :

Автоматически сгенерированные теги Id, показывающие разумный номер версии, невозможно сделать с помощью таких инструментов DSCM, как Bazaar, потому что линия разработки каждого человека может отличаться от всех остальных. Так что кто-то может сослаться на версию «1.41» файла, но ваша версия «1.41» этого файла отличается.

По сути, $ Id $ не имеет смысла с Bazaar, Git и другими инструментами управления распределенным исходным кодом.


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

Это не неспособность Git, это неспособность всех распределенных SCM. Если вам действительно нужны понятные номера версий, используйте Subversion, CVS или какую-нибудь другую централизованную систему.
Bombe

7
что плохого в том, чтобы просто выплюнуть хеш вместо "номера версии"? Мне нужны операторы журнала, отладочные веб-страницы и параметры «--version» во внутренних сценариях, которые легко скажут мне, какая ревизия и где запущена, поэтому я могу проверить этот конкретный хэш и понять, почему он ведет себя именно так. Это упрощает управление развернутыми приложениями ... и мне не нужен какой-то хук фиксации, который рассматривает каждую фиксацию как изменение каждого файла, в котором есть тег $ Id $.
nairbv 01

1
хэш файла, над которым вы работаете, будет работать так же, как «версия», если вы можете найти его в git по этому идентификатору
Эрик Аронести

2
@Brian - согласно редактированию OP конечный пользователь хочет знать номер версии, но не имеет доступа к 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), поэтому, если я назову его как «tool -updateVersion», он просто вызовет updateVersion для инструмента, который изменяет значение «MYVERSION» в себе, а затем завершает работу (вы могли пусть он также обновит другие файлы, если они открыты, если хотите).

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

Скрипт просто переходит в заголовок каталога Git и вызывает мой скрипт с -updateVersion.

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


Так должен ли ваш сценарий Ruby называться updateVersion, чтобы иметь git updateVersion? Приложите, пожалуйста, несколько примеров того, как это называется.
rjt

Я добавляю параметр (-updateVersion) в проверяемый мной сценарий, который вызывает функцию updateVersion (в данном случае я пытаюсь изменить номер версии в самом сценарии). Затем я просто делаю команду оболочки oneliner, которая вызывает мой скрипт с -updateVersion, а затем обновляется перед каждой проверкой.
Дэвид Люнг Мэдисон

8

Если для вас важно наличие $ Keywords $, то, может быть, вы могли бы попробовать вместо этого взглянуть на Mercurial ? У него есть расширение hgkeyword, которое реализует то, что вы хотите. В любом случае Mercurial интересен как DVCS.


8

Что-то, что делается с репозиториями Git, - это использовать tagобъект. Его можно использовать для пометки фиксации строкой любого типа и для отметки версий. Вы можете увидеть эти теги в репозитории с помощью git tagкоманды, которая возвращает все теги.

Проверить тег легко. Например, если есть тег, v1.1вы можете проверить этот тег в ветке следующим образом:

git checkout -b v1.1

Поскольку это объект верхнего уровня, вы увидите всю историю этого коммита, а также сможете запускать сравнения, вносить изменения и объединять.

Не только это, но и тег сохраняется, даже если ветка, в которой он находился, была удалена без повторного объединения с основной строкой.


6
Есть ли способ автоматически вставить этот тег в файл с помощью git? Спасибо!
Джо Касадонте

1
Если вы имеете в виду под расширением ключевых слов? Насколько я знаю, нет. если вы создаете продукты, вы можете получить эту информацию как часть сценария сборки и вставить ее где-нибудь в созданный продукт. Попробуйте man git-describe, который дает последний тег, количество коммитов с момента этого тега и текущий хэш.
Abizern

Да, теги и другую связанную информацию теперь можно автоматически редактировать в файлы с помощью 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

Будет ли достаточно простой отметки времени? Неправильная ветка может иметь привлекательную временную метку и при этом быть менее правильной.
user2066657

4

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

* ident

Чтобы увидеть это в действии, вам нужно сначала выполнить эффективную проверку файла (ов), например удалить или отредактировать их любым способом. Затем восстановите их с помощью:

git checkout .

И вы должны увидеть $Id$замену на что-то вроде:

$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $

Из man gitattributes :

идент

Если для пути установлен атрибут identity, Git заменяет $ Id $ в объекте большого двоичного объекта на $ Id :, за которым следует 40-символьное шестнадцатеричное имя объекта большого двоичного объекта, за которым следует знак доллара $ при оформлении заказа. Любая последовательность байтов, которая начинается с $ 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.