Переход от CVS к Git: $ Id: $ эквивалент?
Я прочитал кучу вопросов о простых инструментах контроля исходного кода, и Git показался мне разумным выбором. У меня есть и работает, и это работает хорошо до сих пор. Один аспект, который мне нравится в CVS, - это автоматическое увеличение номера версии.
Я понимаю, что это имеет меньше смысла в распределенном репозитории, но как разработчик мне нужно/нужно что-то вроде этого. Позвольте мне объяснить, почему:
Я использую Emacs. Периодически я просматриваю новые версии исходных файлов Lisp для сторонних пакетов. Скажем, у меня есть файл foo.el, который, согласно заголовку, версии 1.3; если я посмотрю последнюю версию и увижу ее 1.143 или 2.6 или что-то еще, я знаю, что я довольно далеко позади.
Если вместо этого я увижу пару 40-символьных хэшей, я не буду знать, что будет позже, или не пойму, насколько это позже. Я бы совершенно ненавидел бы это, если бы мне пришлось вручную проверять ChangeLogs, просто чтобы понять, насколько я устарел.
Как разработчик, я хочу выразить эту любезность, как мне кажется, людям, которые используют мой вывод (и, возможно, я шучу над собой, что кто-то есть, но давайте на минуту оставим это в стороне). Я не хочу помнить, чтобы каждый раз увеличивать число чертово, или временную метку, или что-то в этом роде. Это настоящая PITA, и я знаю это по опыту.
Итак, какие у меня есть альтернативы? Если я не могу получить эквивалент $ Id: $, как еще я могу предоставить то, что я ищу?
Я должен отметить, что я ожидаю, что конечный пользователь НЕ будет иметь установленный Git, и даже если он сделает это, у него не будет локального репозитория (на самом деле, я не собираюсь делать его доступным таким образом).
Ответы
Ответ 1
SHA - это только одно представление версии (пусть и канонической). Команда git describe
предлагает другим и делает это довольно хорошо.
Например, когда я запускаю git describe
в моей основной ветке моего клиента Java memcached, я получаю это:
2.2-16-gc0cd61a
Это говорит о двух важных вещах:
- В этом дереве было ровно 16 коммитов с 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.
Ответ 2
В настоящее время существует поддержка $Id: $в Git. Чтобы включить его для файла README, вы должны поставить "README ident" в .gitattributes. Поддерживаются подстановочные знаки в именах файлов. Подробнее см. man gitattributes.
Ответ 3
Это не необоснованный запрос от ОП.
Мой вариант использования:
- Я использую Git для своего личного кода, поэтому не сотрудничаю с другими.
- Я храню там системные скрипты Bash, которые могут быть помещены в
/usr/local/bin
когда они будут готовы.
Я использую три отдельные машины с одним и тем же Git-репозиторием. Было бы неплохо узнать, какая "версия" файла у меня в настоящее время находится в /usr/local/bin
без необходимости выполнять руководство "diff -u <версия репозитория> <версия в /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 $
Некоторая полезная информация находится в разделе Как включить строку идентификатора для репозитория Git? ,
Ответ 4
Не уверен, что это когда-нибудь будет в Git. К quote Linus:
"Все понятие замены ключевых слов просто полностью идиотски. тривиально делать" вне "фактического отслеживания контента, если вы хотите иметь это, когда делаете деревья релиза как тар-шары и т.д."
Это довольно легко проверить журнал, хотя - если вы отслеживаете стабильную ветку foo.el, вы можете увидеть, какие новые коммиты находятся в журнале стабильной ветки, которые не находятся в вашей локальной копии. Если вы хотите имитировать внутренний номер версии CVS, вы можете сравнить временную метку последнего фиксации.
Изменить: вы должны писать или использовать для этого другие скрипты, конечно, не делать это вручную.
Ответ 5
Как я писал до:
Наличие автоматически генерируемых тегов идентификаторов, которые показывают разумный номер версии, невозможно сделать с инструментами DSCM, такими как Bazaar, потому что каждая линия развития может отличаться от всех остальных. Поэтому кто-то может ссылаться на версию "1.41" файла, но ваша версия "1.41" этого файла отличается.
В принципе, $Id $не имеет никакого смысла с Bazaar, Git и другими инструментами управления распределенными исходными кодами.
Ответ 6
У меня такая же проблема. Мне нужно было иметь версию, которая была бы проще хеш-строки и была бы доступна людям, использующим инструмент, без необходимости подключения к хранилищу.
Я сделал это с помощью хита Git pre-commit и изменил свой скрипт, чтобы иметь возможность автоматически обновляться.
Я основываю версию на количестве совершенных коммитов. Это небольшое условие гонки, потому что два человека могут выполнять коммит одновременно, и оба думают, что фиксируют один и тот же номер версии, но у нас мало разработчиков в этом проекте.
Мой в Ruby, но это не очень сложный код. Скрипт 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 для инструмента.
Наконец, я перехожу к главе Git и создаю исполняемый скрипт в .git/hooks/pre-commit
.
Скрипт просто переходит в начало каталога Git и вызывает мой скрипт с -updateVersion
.
Каждый раз, когда я регистрируюсь, переменная MYVERSION обновляется в зависимости от количества коммитов.
Ответ 7
Что-то, что делается с репозиториями Git, - это использование объекта tag
. Это может быть использовано для маркировки коммита любой строкой и может использоваться для маркировки версий. Вы можете увидеть эти теги в репозитории с помощью команды git tag
, которая возвращает все теги.
Это легко проверить тег. Например, если есть тег v1.1
вы можете проверить этот тег на ветке следующим образом:
git checkout -b v1.1
Поскольку это объект верхнего уровня, вы увидите всю историю этого коммита, а также сможете запускать сравнения, вносить изменения и слияния.
Не только это, но и тег сохраняется, даже если ветвь, в которой он находился, была удалена без слияния обратно в основную строку.
Ответ 8
Если для вас важны $Ключевые слова $, возможно, вы могли бы вместо этого взглянуть на Mercurial? Он имеет расширение hgkeyword, которое реализует то, что вы хотите. Mercurial интересен как DVCS в любом случае.
Ответ 9
Если вы просто хотите, чтобы люди могли понять, насколько они устарели, Git может проинформировать их об этом несколькими довольно простыми способами. Например, они сравнивают даты последнего коммита на своем сундуке и вашем сундуке. Они могут использовать git cherry
чтобы увидеть, сколько коммитов произошло в вашем сундуке, а их нет.
Если это все, чего вы хотите, я бы искал способ предоставить его без номера версии.
Кроме того, я бы не стал распространять любезность на кого-либо, если вы не уверены, что он этого хочет. :)
Ответ 10
Если я правильно понимаю, по сути, вы хотите знать, сколько коммитов произошло в данном файле с момента последнего обновления.
Сначала получите изменения в удаленном источнике, но не объедините их в ветвь 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
Ответ 11
Идентификаторы RCS хороши для однофайловых проектов, но для любого другого $ Id $ ничего не говорит о проекте (если вы не выполняете принудительную регистрацию в файле фиктивной версии).
Еще может быть интересно, как получить эквиваленты $ Author $, $ Date $, $ Revision $, $ RCSfile $ и т.д. На уровне файла или на уровне фиксации (как разместить их там, где одни ключевые слова - это другое вопрос). У меня нет ответа на эти вопросы, но я вижу необходимость их обновления, особенно когда файлы (теперь в Git) происходят из RCS-совместимых систем (CVS).
Такие ключевые слова могут быть интересны, если исходники распространяются отдельно от любого Git-репозитория (что я и делаю). Мое решение таково:
У каждого проекта есть свой собственный каталог, и в корне проекта у меня есть текстовый файл с именем .version
содержимое которого описывает текущую версию (имя, которое будет использоваться при экспорте исходных текстов).
При работе для следующего выпуска скрипт извлекает этот номер .version
, некоторый дескриптор версии Git (например, git describe
description) и монотонный номер сборки в .build
(плюс хост и дату) в автоматически сгенерированный исходный файл, который связан с финальным Программа, так что вы можете узнать, из какого источника и когда он был построен.
Я разрабатываю новые функции в отдельных ветвях, и первое, что я делаю, это добавляю n
(для "следующего") в строку .version
(несколько ветвей, происходящих из одного корня, будут использовать один и тот же временный номер .version
). Перед выпуском я решаю, какие ветки объединить (надеюсь, у всех .version
та же .version
). Перед совершением слияния я обновляю .version
до следующего номера (основное или незначительное обновление, в зависимости от объединенных функций).
Ответ 12
Я согласен с теми, кто считает, что замена токенов принадлежит инструментам сборки, а не инструментам управления версиями.
У вас должен быть какой-то инструмент автоматического выпуска для установки идентификаторов версий в ваших источниках во время тега релиза.
Ответ 13
Чтобы применить расширение ко всем файлам во всех подкаталогах в хранилище, добавьте файл .gitattributes
каталог верхнего уровня в хранилище (т. .gitignore
куда вы обычно помещаете файл .gitignore
), содержащий:
* ident
Чтобы убедиться в этом, вам нужно сначала выполнить эффективную проверку файлов, например, удалить или отредактировать их любым способом. Затем восстановите их с помощью:
git checkout .
И вы должны увидеть, что $Id$
заменяется чем-то вроде:
$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $
От man gitattributes
:
идент
Когда для пути задан идентификатор атрибута, Git заменяет $ Id $ в объекте blob на $ Id:, за которым следует 40-символьное имя объекта шестнадцатеричного двоичного объекта, за которым следует знак доллара $ при оформлении заказа. Любая последовательность байтов, которая начинается с $ Id: и заканчивается $ в файле рабочего дерева, заменяется на $ Id $ при регистрации.
Этот идентификатор будет меняться каждый раз при подтверждении новой версии файла.
Ответ 14
Поскольку вы используете Emacs, вам может повезти :)
Я столкнулся с этим вопросом по стечению обстоятельств, а также по стечению обстоятельств, что я натолкнулся на Lively несколько дней назад, пакет Emacs, который позволяет включать в ваш документ живые кусочки Emacs Lisp. Я не пробовал, если честно, но пришло мне в голову, читая это.
Ответ 15
Я также пришел из 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
Ответ 16
Если вы хотите, чтобы информация о 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
который мог бы избежать этих проблем, оставлен в качестве упражнения для читателя.