Я прочитал кучу вопросов о простых инструментах управления исходным кодом, и Git показался мне разумным выбором. Он у меня есть и работает, и пока он работает хорошо. Один из аспектов, который мне нравится в CVS, - это автоматическое увеличение номера версии.
Я понимаю, что в распределенном репозитории это не имеет смысла, но как разработчик я хочу / нуждаюсь в чем-то подобном. Позвольте мне объяснить почему:
Я использую Emacs. Периодически я просматриваю и ищу новые версии исходных файлов Lisp для сторонних пакетов. Скажем, у меня есть файл foo.el, который, согласно заголовку, имеет версию 1.3; если я посмотрю на последнюю версию и увижу, что это 1.143 или 2.6 или что-то еще, я знаю, что я очень сильно отстаю.
Если вместо этого я увижу пару 40-символьных хэшей, я не узнаю, какой из них будет позже, и не пойму, сколько он будет позже. Я бы абсолютно ненавидел, если бы мне пришлось вручную проверять журналы изменений, чтобы понять, насколько я устарел.
Как разработчик, я хочу выразить эту любезность, как я это вижу, людям, которые используют мои результаты (и, возможно, я обманываю себя, что кто-то есть, но оставим это на мгновение). Я не хочу, чтобы мне приходилось каждый раз самому увеличивать проклятое число, или временную метку, или что-то в этом роде. Это настоящая PITA, и я знаю это по опыту.
Итак, какие у меня есть альтернативы? Если я не могу получить эквивалент $ Id: $, как еще я могу предоставить то, что ищу?
Я должен упомянуть, что я ожидаю, что у конечного пользователя НЕ будет установлен Git, и даже если он установит, у него не будет локального репозитория (действительно, я не ожидаю, что он будет доступен таким образом).





Не уверен, что это когда-нибудь будет в Git. Кому цитировать Линуса:
"The whole notion of keyword substitution is just totally idiotic. It's trivial to do "outside" of the actual content tracking, if you want to have it when doing release trees as tar-balls etc."
Тем не менее, проверить журнал довольно легко - если вы отслеживаете стабильную ветку foo.el, вы можете увидеть, какие новые коммиты есть в журнале стабильной ветки, которых нет в вашей локальной копии. Если вы хотите смоделировать внутренний номер версии CVS, вы можете сравнить отметку времени последней фиксации.
Edit: для этого нужно писать или использовать чужие скрипты, конечно, не делать это вручную.
Да, иногда ему не хватает вежливости, но обычно он прав, и он определенно касается темы расширения ключевых слов.
Требуется отслеживание версий. git используется в очень многих других инфраструктурах, помимо чистой разработки, где можно прочитать код, чтобы определить, имеет ли он смысл. Но когда система контроля версий используется для отслеживания файлов с произвольным содержимым, вам нужно иметь какие-то средства узнать об официальном выпуске. git, не говоря уже о журнале git, отсутствует на машине, на которую были отправлены файлы .ini, .conf, .html и другие.
@rjt - это контролируется сценариями развертывания / пакета и т. д. Несмотря на это, вопреки моему прогнозу, git добавил поддержку много лет назад: git-scm.com/docs/gitattributes#__code_ident_code
Линус прокомментировал только один аспект расширения ключевых слов - отслеживание релизов. Но это не единственная его цель. Эта цитата ясно демонстрирует мужское отношение, но ничего полезного о предмете не говорит. Типичный политический трюк "возвышенно заявлять очевидное" - и толпа принадлежит вам. Проблема в том, что толпа по определению глупа, потому что у нее всего один мозг. Что четко объясняет ситуацию с git и расширением ключевых слов. Один идиот сказал «нет», и все обрадовались!
@AnrDaemon не только это, теперь git добавил поддержку $Id$ через атрибут ident, как упоминалось в другом ответе здесь, показывая, что даже сам git не является заложником мнения Линуса.
Я знаю, что он добавил контрольную сумму фиксации, и только ее. Мне все еще нужно перейти в командную строку git, чтобы извлечь из нее что-нибудь действительно полезное.
Если я правильно понимаю, по сути, вы хотите знать, сколько коммитов произошло с данным файлом с момента последнего обновления.
Сначала получите изменения в удаленном источнике, но не объединяйте их в свою ветку 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
Итак, не используйте log: git rev-list master..origin / master | туалет -l
Если вы просто хотите, чтобы люди понимали, насколько они устарели, Git может сообщить им об этом несколькими довольно простыми способами. Например, они сравнивают даты последней фиксации на своей стволе и на вашем стволе. Они могут использовать git cherry, чтобы увидеть, сколько коммитов произошло в вашем стволе, чего нет в их.
Если это все, что вам нужно, я бы поискал способ предоставить его без номера версии.
Кроме того, я бы не стал проявлять любезность к кому-либо, если вы не уверены, что они этого хотят. :)
Если даты подходят для сравнения, поместите DateTImeStamp в файл. У git есть много других вариантов использования, помимо разработчиков. ИТ-специалистам в полевых условиях необходимо знать, находится ли файл .INI или .conf на рабочей станции, на которой выполняется устранение неполадок, где-либо близко к текущему.
Достаточно ли будет простой метки времени? Неправильная ветка может иметь привлекательную временную метку и все же быть менее правильной.
Что-то, что делается с репозиториями Git, - это использование объекта tag. Его можно использовать для пометки фиксации строкой любого типа и для отметки версий. Вы можете увидеть эти теги в репозитории с помощью команды git tag, которая возвращает все теги.
Проверить тег легко. Например, если есть тег v1.1, вы можете выделить этот тег в ветку следующим образом:
git checkout -b v1.1
Поскольку это объект верхнего уровня, вы увидите всю историю этого коммита, а также сможете запускать сравнения, вносить изменения и объединять.
Не только это, но и тег сохраняется, даже если ветка, в которой он находился, была удалена без повторного слияния с основной строкой.
Есть ли способ автоматически вставить этот тег в файл с помощью git? Спасибо!
Если вы имеете в виду под расширением ключевых слов? Насколько я знаю, нет. если вы создаете продукты, вы можете получить эту информацию как часть сценария сборки и вставить ее где-нибудь в созданный продукт. Попробуйте man git-describe, который дает последний тег, количество коммитов с момента этого тега и текущий хэш.
Да, теги и другую связанную информацию теперь можно автоматически редактировать в файлы с помощью git с помощью функции export-subst в gitattributes(5). Это, конечно, требует использования git archive для создания релизов, и только в итоговом tar-файле будут видны подстановочные правки.
Если для вас важно наличие $ Keywords $, то, может быть, вы могли бы попробовать вместо этого взглянуть на Mercurial? У него есть расширение hgkeyword, которое реализует то, что вы хотите. В любом случае Mercurial интересен как DVCS.
Как я написал перед:
Having automatically generated Id tags that show a sensible version number is impossible to do with DSCM tools like Bazaar because everybody’s line of development can be different from all others. So somebody could refer to version “1.41” of a file but your version “1.41” of that file is different.
Basically, $Id$ does not make any sense with Bazaar, Git, and other distributed source code management tools.
Правильно, я прочитал это перед публикацией, и поэтому я попросил более общее решение основной проблемы. Я думаю, что желание, чтобы у отдельного файла была версия #, вполне законно, как и неспособность git предоставить решение.
Это не неспособность Git, это неспособность всех распределенных SCM. Если вам действительно нужны понятные номера версий, используйте Subversion, CVS или другую централизованную систему.
Вы правы, я должен был сказать «как и неспособность DSCM предоставить решение».
Полезно отметить, что с тех пор bzr включил расширение ключевого слова wiki.bazaar.canonical.com/KeywordExpansion
что плохого в том, чтобы просто выплюнуть хеш вместо "номера версии"? Мне нужны операторы журнала, отладочные веб-страницы и параметры «--version» во внутренних сценариях, которые легко скажут мне, какая ревизия и где запущена, поэтому я могу проверить этот конкретный хэш и понять, почему он ведет себя именно так. Это упрощает управление развернутыми приложениями ... и мне не нужен какой-то хук фиксации, который рассматривает каждую фиксацию как изменение каждого файла, в котором есть тег $ Id $.
хеш файла, над которым вы работаете, будет работать так же, как «версия», если вы можете найти его в git по этому идентификатору.
@Brian - согласно редактированию OP конечный пользователь хочет знать номер версии, но не имеет доступа к git или журналам git. В этом случае хеш - это бессмысленное число, а не номер версии. DSCM не помогает в решении этой проблемы.
возможно, это правильный ответ на этот конкретный вопрос, но я все же думаю, что что-то вроде $ Id $, показывающее хеш, было бы полезно многим разработчикам.
SHA - это всего лишь одно из представлений версии (хотя и каноническое). Команда git describe предлагает другие возможности и делает это достаточно хорошо.
Например, когда я запускаю git describe в своей основной ветке моего источника Клиент Java memcached, я получаю следующее:
2.2-16-gc0cd61a
Это говорит о двух важных вещах:
Скажем, например, вы упаковали файл 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.
Использование этого не удастся, поскольку вы объедините ветку разработки, в то время как у мастера были некоторые исправления. Количество коммитов с момента выхода последней версии изменится. Хэш ненадежен, так как кто-то может восстановить все это с помощью filter-branch или чего-то еще.
В описании описывается только изучение информации, а не встраивание ее в ваш исполняемый файл. Для этого вам нужно запустить команду git describe непосредственно перед сборкой, сохранить вывод в файле заголовка или иным образом встроить значение в свой код.
Поскольку вы используете Emacs, вам может повезти :)
Я натолкнулся на этот вопрос случайно, а также случайно я получил несколько дней назад Оживленный, пакет Emacs, который позволяет иметь живые части Emacs Lisp в вашем документе. Я не пробовал, если честно, но это пришло мне в голову при чтении этого.
К настоящему времени в Git есть поддержка $ Id: $. Чтобы включить его для файла ПРОЧТИ МЕНЯ, вы должны поместить «README identity» в .gitattributes. Поддерживаются подстановочные знаки в именах файлов. Подробнее см. человек gitattributes.
Это дает вам sha1 блоба, но не sha1 коммита. Полезно, но не как идентификатор фиксации.
git не имеет механизма расширения ключевых слов, подобного упомянутому $Id$. Вы получаете именно то, что хранится отдельно. В любом случае версия принадлежит полному набору файлов, составляющих коммит, а не одному файлу в частности (эта идея - пережиток времен RCS, или, возможно, SCCS здесь виноват ... Поскольку CVS - это просто прославил интерфейс для RCS, а SVN пытается быть похожим на CVS, он застрял.).
Это не необоснованный запрос OP.
Мой вариант использования:
/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?.
Следует отметить, что это идентифицирует текущий файл (blob), а не текущую фиксацию
Что должен делать git co? Я получил сообщение об ошибке "git: 'co' is not a git command. See 'git --help'." Должен ли это быть git checkout?
У меня такая же проблема. Мне нужна была версия, которая была бы проще, чем строка хэша, и была доступна для людей, использующих инструмент, без необходимости подключаться к репозиторию.
Я сделал это с помощью ловушки предварительной фиксации 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? Приложите, пожалуйста, несколько примеров того, как это называется.
Я устанавливаю параметр (-updateVersion) для проверяемого мной сценария, который вызывает функцию updateVersion (в данном случае я пытаюсь изменить номер версии в самом сценарии). Затем я просто делаю команду оболочки oneliner, которая вызывает мой скрипт с -updateVersion, а затем обновляется перед каждой проверкой.
Я согласен с теми, кто считает, что замена токена относится к инструментам сборки, а не к инструментам контроля версий.
У вас должен быть какой-то автоматический инструмент выпуска, чтобы установить идентификаторы версий в ваших источниках во время маркировки выпуска.
.INI .conf и .txt обычно не имеют инструмента сборки.
Но вы можете создать сценарий выпуска, который берет текущий тег Git и записывает его в файл или что-то в этом роде.
Идентификаторы RCS удобны для однофайловых проектов, но для любых других $ Id $ ничего не говорит о проекте (если только вы не выполняете принудительные фиктивные проверки для файла фиктивной версии).
Тем не менее, может быть интересно, как получить эквиваленты $ Author $, $ Date $, $ Revision $, $ RCSfile $ и т. д. На уровне файла или на уровне фиксации (как разместить их там, где находятся некоторые ключевые слова, это другое вопрос). У меня нет ответа на эти вопросы, но я вижу необходимость их обновления, особенно когда файлы (теперь в Git) происходят из RCS-совместимых систем (CVS).
Такие ключевые слова могут быть интересны, если исходники распространяются отдельно от любого репозитория Git (я тоже этим занимаюсь). Мое решение таково:
У каждого проекта есть собственный каталог, и в корне проекта у меня есть текстовый файл с именем .version, содержимое которого описывает текущую версию (имя, которое будет использоваться при экспорте источников).
Во время работы над следующей версией скрипт извлекает этот номер .version, некоторый дескриптор версии Git (например, git describe) и монотонный номер сборки в .build (плюс хост и дату) в автоматически сгенерированный исходный файл, связанный с окончательной программой, поэтому вы можете узнать, из какого источника и когда он был построен.
Я разрабатываю новые функции в отдельных ветках, и первое, что я делаю, это добавляю n (для «следующего») в строку .version (несколько ветвей, происходящих из одного корня, будут использовать один и тот же временный номер .version). Перед выпуском я решаю, какие ветки объединить (надеюсь, все с одним и тем же .version). Перед фиксацией слияния я обновляю .version до следующего номера (основное или незначительное обновление, в зависимости от объединенных функций).
Я также пришел из 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
Чтобы применить расширение ко всем файлам во всех подкаталогах в репозитории, добавьте файл .gitattributes в каталог верхнего уровня в репозитории (т.е. туда, куда вы обычно помещаете файл .gitignore), содержащий:
* ident
Чтобы увидеть это в действии, вам нужно сначала выполнить эффективную проверку файла (ов), например удалить или отредактировать их любым способом. Затем восстановите их с помощью:
git checkout .
И вы должны увидеть замену $Id$ на что-то вроде:
$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $
С man gitattributes:
ident
When the attribute ident is set for a path, Git replaces $Id$ in the blob object with $Id:, followed by the 40-character hexadecimal blob object name, followed by a dollar sign $ upon checkout. Any byte sequence that begins with $Id: and ends with $ in the worktree file is replaced with $Id$ upon check-in.
Этот идентификатор будет изменяться каждый раз, когда фиксируется новая версия файла.
Если вы хотите, чтобы информация о коммите 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, в котором можно было бы избежать этих проблем, оставлен в качестве упражнения для читателя.
Чтобы решить эту проблему для себя, я создал небольшой «хак» в качестве ловушки после фиксации:
echo | tee --append *
git checkout *
Более подробно задокументировано в этот пост в моем блоге.
Теперь 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"
Да, я прочитал часть этой длинной цепочки писем о расширении ключевых слов. Отношения Линуса было почти достаточно, чтобы полностью отвлечь меня от мерзости.