Вход:  Пароль:  
FreeSource: RuslanHihin/gitusermanual/Chapter2 ...
Free Source | Каталог | Изменения | НовыеКомментарии | Пользователи | Регистрация |
Это старая версия RuslanHihin/gitusermanual/Chapter2 за 2008-05-12 01:17:06..

Глава 2. Изучение Git истории


Оглавление


Глава 2. Изучение Git истории 11


Как используя bisect найти регрессию 11


Именование коммитов 12


Создание тегов 13


Просмотр версий 14


Формирование сравнений (diff) 15


Просмотр старых версии файлов 15


Примеры 15


Подсчёт числа коммитов в ветке : 15


Проверка наличия истории между двумя точками ветки 16


Поиск первой помеченной версии с решением определённой проблемы 16


Просмотр уникальных коммитов в данной ветке 18


Создание журнала изменений (changelog) и тарбола релиза 18


Поиск ссылок коммитов на файл с заданным содержанием 19


Git – это один из наилучших инструментов для хранения истории множества файлов.


Это происходит потому, что он хранит сжатые снапшоты содержащие файла иерархии, вместе с «коммитами», которые отслеживают связи между ними.


Git является чрезвычайно гибким и быстрым инструментом для изучения истории проекта.


Начнём с одного специализированного инструмента, которое обычно используется для поиска программной ошибки («бага») в проекте.


Как используя bisect найти регрессию


Suppose version 2.6.18 of your project worked, but the version at “master” crashes.


Предположим, версия 2.6.18 вашего проекта была рабочей, но в версия «мастер» возникла ошибка.


Иногда лучшим способом найти причину такой регрессии, состоит в том, чтобы выполнить поиск с отдельного коммита в истории проекта который является причиной проблемы. Команда git-bisect(1) может помочь вам сделать это:


$ git bisect start


$ git bisect good v2.6.18


$ git bisect bad master


Bisecting: 3537 revisions left to test after this


[65934a9a028b88e83e2b0f8b36618fe503349f8e] BLOCK: Make USB storage depend on SCSI rather than selecting it [try #6]


Если вы запускаете сейчас “git branch” вы увидите, что git временно переместился в новую ветку с названием “bisect”. Эта ветка указывает на коммит ( с именем снапшота 65934…), который доступен из «мастер», но из v2.6.18.Откомпилируйте и протестировать его и посмотрите есть-ли в нём проблема. Допустим, что есть. Тогда:


$ git bisect bad


Bisecting: 1769 revisions left to test after this


[7eff82c8b1511017ae605f0c99ac275a7e21b867] i2c-core: Drop useless bitmaskings


Извлекаем для проверки более старую версию. Продолжая аналогично, проверяем на каждом этапе версию и говорим git`у хорошая это версия, или плохая. Можно заметить что каждый раз число подозрительных версий сокращается примерно вдвое. После примерно 13 тестов (в данном случае), получаем идентификатор «виновного» коммита. Затем можно проанализировать коммит с помощью git-show(1), найти кто записал этот коммит, и направить ему по e-mail баг-рапорт об ошибке с идентификатором этого коммита. Наконец, запустив :


$ git bisect reset


возвращаемся к ветке удаляя перед этим временную ветвь «bisect».


Заметим, что версия, которую извлекает вам для проверки git-bisect является лишь предложением, и Вы можете сразу пробовать другую версию, если считаете что это более правильно. Например, время от времени вы можете «приземлиться» в коммит который не связан c предыдущей последовательностью, запустив


$ git bisect visualize


если запустить gitk, то ярлык коммита в этом случае будет отмечен маркером “bisect”.


Выбрав безопасной просмотр ближайшего коммита, замечаем его идентификатор и проверив его уходим из него командой (Chose a safe-looking commit nearby, note its commit id, and check it out with):


$ git reset --hard fb47ddb2db...


then test, run “bisect good” or “bisect bad” as appropriate, and continue.


затем проверив его, запускаем соответственно «bisect good» или «bisect bad» и продолжаем.


Именование коммитов


Мы уже видели несколько способов именования коммитов:


* Шестнадцатеричное 40-значное имя объекта (снапшот).


* Имя ветки: относится к коммиту на вершине данной ветки


* Имя тэга: ссылка на коммит на который учитывает тэг (мы видели ветки и тэги на


которые ссылаются в специальных случаях).


* HEAD: ссылка на вершину текущей ветки


There are many more; see the “SPECIFYING REVISIONS” section of the git-rev-parse(1) man page for the complete list of ways to name revisions.


Есть много других имён, см .в странице man git-rev-parse(1) раздел “SPECIFYING REVISIONS” с полным перечнем способов задания имени версий.


Некоторые примеры:


$ git show fb47ddb2 # первые несколько символов имени объекта


# Как правило, достаточно указать его несколько которые делают его уникальным.


$ git show HEAD^ # родители коммита HEAD


$ git show HEAD^^ # «дедушки» коммита HEAD


$ git show HEAD4 # «пра-прадедушки»


Напомним, что если произошло слияние, то коммит может иметь больше чем одного родителя; по умолчанию, ^ и ~ следует за первым родителем, перечисленным в коммите, но вы также можете сделать другой выбор :


$ git show HEAD^1 # показать первого родителя HEAD


$ git show HEAD^2 # показать второго родителя HEAD


В дополнение к HEAD, существует ряд других специальных имён для коммитов:


Слияния (будет обсуждаться позже) это такие операции подобные git-reset которые изменяют текущий проверяемый коммит и как правило устанавливают имя ORIG_HEAD на значение HEAD перед выполнением операции.


Операция git-fetch всегда сохраняет вершину последней извлекаемой ветки в имени FETCH_HEAD. Например, если вы запускаете git fetch без задания локальной ветки в качестве цели операции


$ git fetch git://example.com/proj.git theirbranch


взятые коммиты всё-равно будет доступны через FETCH_HEAD.


Когда мы обсуждаем слияния мы также видим особых имя MERGE_HEAD, которое относится к другой ветви которую мы объединяем с текущей веткой.


The git-rev-parse(1) command is a low-level command that is occasionally useful for translating some name for a commit to the object name for that commit:


Команда git-rev-parse(1) — это команда низкого уровня, которая иногда полезна для перевода некоторых имён коммита в его имя объекта (имя снапшота) :


$ git rev-parse origin


e05db0fd4f31dde7005f075a84f96b360d05984b


Создание тегов


Мы можем создать тег к ссылке на особый коммит. После запуска


$ git tag stable-1 1b2e1d63ff


вы можете использовать имя stable-1 как ссылку на коммит 1b2e1d63ff.


Это создаст «легковесный» тег. Если вы хотели бы также включать комментарии в тег, и, возможно, подписать его криптографическими, то вы должны создайте вместо тэга объект, подробнее см.. man страницу git-tag(1).


Просмотр версий


Команда git-log(1) может показать лист коммитов.


On its own, it shows all commits reachable from the parent commit; but you can also make more specific requests:


Собственно она показывает все коммиты доступные из родительского коммита: но она так-же может обработать специфичные запросы :


$ git log v2.5.. # коммиты от v2.5 (только доступные)


$ git log test..master # доступные коммиты от master но не из test


$ git log master..test # ...доступные от test но не из master (две точки)


$ git log master...test # ...или от test или от master (три точки)


# но не из обоих


$ git log --since="2 weeks ago" # коммиты за последние две недели


$ git log Makefile # коммиты в которых менялся Makefile


$ git log fs/ # ... в которых изменился какой-нибудь файл в fs/


$ git log -S'foo()' # коммиты, которые добавили или удалили любые файлы


# имеющую строку 'foo()'


And of course you can combine all of these; the following finds commits since v2.5 which touch the Makefile or any file under fs:


И, конечно, вы можете комбинировать все это; следующая команда находит коммиты из v2.5 в которых изменяются Makefile и изменения в любых файлов в fs/:


$ git log v2.5.. Makefile fs/


You can also ask git log to show patches:


Также вы можете использовать git log, для просмотра патчей:


$ git log -p


См. описание опции "—pretty" в man странице git-log(1) страницу и о других опциях.


Note that git log starts with the most recent commit and works backwards through the parents; however, since git history can contain multiple independent lines of development, the particular order that commits are listed in may be somewhat arbitrary.


Заметим, что git log начинается с самых последних коммитов, и от родителей далее, однако, поскольку git история может содержать несколько независимых линий разработки, порядок в некоторой степени будет произвольным.


Формирование сравнений (diff)


You can generate diffs between any two versions using git-diff(1) :


Вы можете создавать сравнения (diff) между любыми двумя версиями используя git-diff(1):


$ git diff master..test


Эта команда создаст текст различий (diff) между двумя ветками test и master.


Если вы хотите найти различия от их общего предка до test, вы можете использовать три точки вместо двух:


$ git diff master...test


Sometimes what you want instead is a set of patches; for this you can use git-format-patch(1) : Иногда вы хотите вместо различий создать набор патчей, для этого можно использовать git format-patch(1):


$ git format-patch master..test


will generate a file with a patch for each commit reachable from test but not from master.


будет сгенерирован файл патча для совершения каждого коммита доступного из test, до master.


Просмотр старых версии файлов


Вы всегда можете просмотреть старую версию файла, перейдя к коммиту с его первой версией..


But sometimes it is more convenient to be able to view an old version of a single file without checking anything out; this command does that:


Но иногда бывает удобнее иметь возможность просмотреть старую версию одного файла, не проверив ничего другого; это делает команда:


$ git show v2.5:fs/locks.c


До двоеточия может быть любое имя коммита, а после него может быть любой путь к файлу из репозитория git.


Примеры
Подсчёт числа коммитов в ветке :


Suppose you want to know how many commits you've made on “mybranch” since it diverged from “origin”:


Предположим, вы хотите узнать, сколько коммитов вы создали на “mybranch”, после отделения от “origin”:


$ git log --pretty=oneline origin..mybranch | wc -l


Альтернативно, можно часто видеть вид всего сделанного командой низкого уровня git-rev-list(1), которая перечисляет SHA1 снапшоты всех всех имеющихся коммитов ветки:


$ git rev-list origin..mybranch | wc -l


Проверка наличия истории между двумя точками ветки


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


$ git diff origin..master


вам скажет что содержание проекта одно и то-же в обоих ветках; теоретически, однако возможно, что содержание этого проекта могло быть получено двумя различными исторических маршрутами. Вы можете сравнить имена объектов (снапшоты) :


$ git rev-list origin


e05db0fd4f31dde7005f075a84f96b360d05984b


$ git rev-list master


e05db0fd4f31dde7005f075a84f96b360d05984b


Или вы вспомните об операторе ... (три точки), который выбирает все коммиты, доступные от каждой из ссылок но не доступные от обеих:


$ git log origin...master


Команда вернёт no commits (нет коммитов), когда две ветви эквивалентны


Поиск первой помеченной версии с решением определённой проблемы


Предположим, вы знаете, что коммит e05db0fd фиксирует определённые проблемы.


Вы хотите найти ближайшее помеченный тегом релиз, который содержит это исправление.


Конечно, могут существовать более одного варианта ответа на вопрос, если история ветки после коммита 05db0fd имеет несколько «ранних» тегов релизов.


Можно визуально просмотреть коммиты после e05db0fd:


$ gitk e05db0fd..


Вы также можете использовать git-name-rev(1) которая даст коммит с именем любого тега найденного среди потомков коммита :


$ git name-rev --tags e05db0fd


e05db0fd tags/v1.5.0-rc1^023 e05db0fd tags/v1.5.0-rc1 ^ 0 ~ 23


Команда git-describe(1) делает противоположное, выдавая имя версии используя тег, на которым базируется коммит.


$ git describe e05db0fd


v1.5.0-rc0–260-ge05db0f


Иногда вам может помочь догадка, как может называться тег, которые мог возникнуть после решения проблемы.


Если вы просто хотите проверить содержит-ли помеченная тегом версия данный коммит, вы могли бы использовать git-merge-base(1):


$ git merge-base e05db0fd v1.5.0-rc1


e05db0fd4f31dde7005f075a84f96b360d05984b


Команда merge-base находит общего предка у заданных коммитов, и всегда возвращает или тот или другой коммит, когда один является потомком другого; вышеприведённые результаты свидетельствуют о том, что на самом деле e05db0fd предок v1.5.0-rc1 .


Альтернативно отметим :,


$ git log v1.5.0-rc1..e05db0fd


будет производить пустой вывод, только если в v1.5.0-rc1 включает e05db0fd, потому что он совершает только результаты, которые не доступны из v1.5.0-rc1.


As yet another alternative, the git-show-branch(1) command lists the commits reachable from its arguments with a display on the left-hand side that indicates which arguments that commit is reachable from.


Как ещё один вариант, команда git-show-branch(1) перечисляет коммиты доступные её аргументам которые показываются левой стороне дисплея, указывая на каким аргументам, что доступно.


Таким образом, вы можете запустить-то вроде


$ git show-branch e05db0fd v1.5.0-rc0 v1.5.0-rc1 v1.5.0-rc2


! [e05db0fd] Fix warnings in sha1_file.c – use C99 printf format if


available


! [v1.5.0-rc0] GIT v1.5.0 preview


! [v1.5.0-rc1] GIT v1.5.0-rc1


! [v1.5.0-rc2] GIT v1.5.0-rc2


...


Затем поиски строки, которая выглядит так


+ ++ [e05db0fd] Fix warnings in sha1_file.c – use C99 printf format if


available


Которая показывает, что e05db0fd доступен из себя, из v1.5.0-rc1, и из v1.5.0-rc2, но не из v1.5.0-rc0.


Просмотр уникальных коммитов в данной ветке


Предположим, вы хотели бы видеть все доступные коммиты от имени вершины ветки “master”, но недоступные от любой другой вершины ветки вашего репозитория.


We can list all the heads in this repository with git-show-ref(1) :


Мы можем перечислить все вершины в этом репозитории командой git-show-ref(1):


$ git show-ref --heads


bf62196b5e363d73353a9dcf094c59595f3153b7 refs/heads/core-tutorial


db768d5504c1bb46f63ee9d6e1772bd047e05bf9 refs/heads/maint


a07157ac624b2524a059a3414e99f6f44bebc1e7 refs/heads/master


24dbc180ea14dc1aebe09f14c8ecf32010690627 refs/heads/tutorial-2


1e87486ae06626c2f31eaa63d26fc0fd646c8af2 refs/heads/tutorial-fixes


Мы можем получить только имя вершины ветки, удалить “master” из вывода, с помощью стандартных утилит cut и grep:


$ git show-ref --heads | cut -d' ' -f2 | grep -v '^refs/heads/master'


refs/heads/core-tutorial


refs/heads/maint


refs/heads/tutorial-2


refs/heads/tutorial-fixes


И так-же мы можем создать запрос чтобы увидеть все доступные коммиты от вершины «master», но не от этих других вершин:


$ gitk master --not $( git show-ref --heads | cut -d' ' -f2 | grep -v '^refs/heads/master' )


Obviously, endless variations are possible; for example, to see all commits reachable from some head but not from any tag in the repository:


Очевидно, возможны бесконечные вариации на эту тему; например, чтобы увидеть все доступные коммиты некоторые от некоторой вершины но не от но без включения тэгов репозитория :


$ gitk $( git show-ref --heads ) --not $( git show-ref --tags )


(См. git-rev-parse(1) для объяснения синтаксиса выбора коммитов таких, как —not).


Создание журнала изменений (changelog) и тарбола релиза


Команда git-archive(1) может создать tar или zip архив любой версии проекта, например:


$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz


Будет использоваться вершина HEAD для создания tar архива, в котором каждому имени файла будет предшествовать путь «project/».


If you're releasing a new version of a software project, you may want to simultaneously make a changelog to include in the release announcement.


Если Вы создаёте релиз новой версии вашего в вашем проекте, вы можете одновременно создать файл изменений (changelog) который включены в анонс релиза.


Linus Torvalds, for example, makes new kernel releases by tagging them, then running:


Линуса Торвальдса, например, делает новых версиях ядра путём пометки их тегом, а затем выполняя:


$ release-script 2.6.12 2.6.13-rc6 2.6.13-rc7


где-релиз скрипта скрипт, выглядит наподобии :


#!/bin/sh


stable="$1"


last="$2"


new="$3"


echo "# git tag v$new"


echo «git archive --prefix=linux-$new/ v$new | gzip -9 > ../linux-$new.tar.gz»


echo «git diff v$stable v$new | gzip -9 > ../patch-$new.gz»


echo «git log --no-merges v$new ^v$last > ../Change Log?-$new»


echo «git shortlog --no-merges v$new ^v$last > ../Short Log?"


echo «git diff --stat --summary -M v$last v$new > ../diffstat-$new»


а потом он просто вставляет выход команд после проверки того, что отмечено OK.


Поиск ссылок коммитов на файл с заданным содержанием


Кто-то дал вам в руки копию файла, и спросил в каком коммите файл был изменён уверенный, что вы содержите содержимое файла до и после коммита Вы можете найти это командой :


$ git log --raw --abbrev=40 --pretty=oneline | grep -B 1 `git hash-object filename`


Понять как это работает, как далее требует дополнительного изучения. Страницы man git-log(1), git-diff-tree(1), и git-hash-object(1) могут помочь вам разобраться подробнее.



 
Файлов нет. [Показать файлы/форму]
Комментариев нет. [Показать комментарии/форму]