git_командная строка (1035338), страница 2
Текст из файла (страница 2)
2.1.7 git log — разнообразная информация о коммитах в целом, по отдельным файлам и различной глубины погружения в историю
Иногда требуется получить информацию об истории коммитов, коммитах, изменивших
отдельный файл; коммитах за определенный отрезок времени и так далее. Для этих
целей используется команда git log.
Простейший пример использования, в котором приводится короткая справка по всем
коммитам, коснувшимся активной в настоящий момент ветки (о ветках и ветвлении
подробно узнать можно ниже, в разделе «Ветвления и слияния»):
git log
Получить подробную информацию о каждом в виде патчей по файлам из коммитов
можно, добавив ключ -p (или -u):
git log -p
Статистика изменения файлов, вроде числа измененных файлов, внесенных в них
строк, удаленных файлов вызывается ключом --stat:
git log --stat
За информацию по созданиям, переименованиям и правам доступа файлов отвечает ключ
--summary:
git log --summary
Для исследования истории отдельного файла достаточно указать в виде параметра
его имя (кстати, в моей старой версии git этот способ не срабатывает,
обязательно добавлять " — " перед «README»):
git log README
или, если версия git не совсем свежая:
git log — README
Далее будет приводится только более современный вариант синтаксиса. Возможно
указывать время, начиная в определенного момента («weeks», «days», «hours», «s»
и так далее):
git log --since=«1 day 2 hours» README
git log --since=«2 hours» README
git log --since=«2 hours» dir/ — изменения, касающиеся отдельной папки.
Можно отталкиваться от тегов:
git log v1… — все коммиты, начиная с тега v1.
git log v1… README — все коммиты, включающие изменения файла README, начиная с
тега v1.
git log v1..v2 README — все коммиты, включающие изменения файла README, начиная с
тега v1 и заканчивая тегом v2.
Создание, выведение списка, назначение тегов будет приведено в соответствующем
разделе ниже.
Интересные возможности по формату вывода команды предоставляет ключ --pretty:
git log --pretty=oneline — выведет на каждый из коммитов по строчке, состоящей из хэша
(здесь — уникального идентификатора каждого коммита, подробней — дальше).
git log --pretty=short — лаконичная информация о коммитах, приводятся только
автор и комментарий
git log --pretty=full/fuller — более полная информация о коммитах, с именем
автора, комментарием, датой создания и внесения коммита
В принципе, формат вывода можно определить самостоятельно:
git log --pretty=format:'FORMAT'
Определение формата можно поискать в разделе по git log из Git Community Book
или справке. Красивый ASCII-граф коммитов выводится с использованием ключа
--graph.
2.1.8 git diff — отличия между деревьями проекта; коммитами; состоянием индекса и каким-либо коммитом.
Своего рода подмножеством команды git log можно считать команду git diff,
определяющую изменения между объектами в проекте: деревьями (файлов и
директорий):
git diff — покажет изменения, не внесенные в индекс.
git diff --cached — изменения, внесенные в индекс.
git diff HEAD — изменения в проекте по сравнению с последним коммитом
git diff HEAD^ — предпоследним коммитом
Можно сравнивать «головы» веток:
git diff master..experimental
Ну или активную ветку с какой-либо:
git diff experimental
2.1.9 git show — показать изменения, внесенные отдельным коммитом
Посмотреть изменения, внесенные любым коммитом в истории можно командой git
show:
git show COMMIT_TAG
2.1.10 git blame и git annotate — вспомогательные команды, помогающие отслеживать изменения файлов
При работе в команде часто требуется выяснить, кто именно написал конкретный
код. Удобно использовать команду git blame, выводящую построчную информацию о
последнем коммите, коснувшемся строки, имя автора и хэш коммита:
git blame README
Можно указать и конкретные строки для отображения:
git blame -L 2,+3 README — выведет информацию по трем строкам, начиная со второй.
Аналогично работает команда git annotate, выводящая и строки, и информацию о
коммитах, их коснувшихся:
git annotate README
2.1.11 git grep — поиск слов по проекту, состоянию проекта в прошлом
git grep, в целом, просто дублирует функционал знаменитой юниксовой
команды. Однако, он позволяет слова и их сочетания искать в прошлом проекта, что
бывает очень полезно:
git grep tst — поиск слова tst в проекте.
git grep -с tst — подсчитать число упоминаний tst в проекте.
git grep tst v1 — поиск в старой версии проекта.
Команда позволяет использовать логическое И и ИЛИ:
git grep -e 'first' --and -e 'another' — найти строки, где упоминаются и первое
слово, и второе.
git grep --all-match -e 'first' -e 'second' — найти строки, где встречается хотя
бы одно из слов.
2.2 Ветвление
Операции ветвления и слияния — сердце и душа git, именно эти возможности делают такой
удобной работу с системой.
2.2.1 git branch — создание, перечисление и удаление веток
Работа с ветками — очень легкая процедура в git, все необходимые механизмы
сконцентрированы в одной команде:
git branch — просто перечислит существующие ветки, отметив активную.
git branch new-branch — создаст новую ветку new-branch.
git branch -d new-branch — удалит ветку, если та была залита (merged) с
разрешением возможных конфликтов в текущую.
git branch -D new-branch — удалит ветку в любом случае.
git branch -m new-name-branch — переименует ветку.
git branch --contains v1.2 — покажет те ветки, среди предков которых есть
определенный коммит.
2.2.2 git checkout — переключение между ветками, извлечение отдельных файлов из истории коммитов
Команда git checkout позволяет переключаться между последними коммитами (если
упрощенно) веток:
checkout some-other-branch
checkout -b some-other-new-branch — создаст ветку, в которую и произойдет
переключение.
Если в текущей ветке были какие-то изменения по сравнению с последним коммитом в
ветке(HEAD), то команда откажется производить переключение, дабы не потерять
произведенную работу. Проигнорировать этот факт позволяет ключ -f:
checkout -f some-other-branch
В случае, когда изменения надо все же сохранить, используют ключ -m. Тогда команда
перед переключением попробует залить изменения в текущую ветку и, после
разрешения возможных конфликтов, переключиться в новую:
checkout -m some-other-branch
Вернуть файл (или просто вытащить из прошлого коммита) позволяет команда вида:
git checkout somefile — вернуть somefile к состоянию последнего коммита
git checkout HEAD~2 somefile — вернуть somefile к состоянию на два коммита назад по ветке.
2.2.3 git merge — слияние веток (разрешение возможных конфликтов).
Слияние веток, в отличие от обычной практики централизованных систем, в git
происходит практически каждый день. Естественно, что имеется удобный интерфейс к
популярной операции:
git merge new-feature — попробует объединить текующую ветку и ветку new-feature.
В случае возникновения конфликтов коммита не происходит, а по проблемным файлам
расставляются специальные метки а ля svn; сами же файлы отмечаются в индексе как
«не соединенные» (unmerged). До тех пор пока проблемы не будут решены, коммит совершить
будет нельзя.
Например, конфликт возник в файле TROUBLE, что можно увидеть в git status:
git merge experiment — произошла неудачная попытка слияния.
git status — смотрим на проблемные места.
edit TROUBLE — разрешаем проблемы.
git add. — индексируем наши изменения, тем самым снимая метки.
git commit — совершаем коммит слияния.
Вот и все, ничего сложного. Если в процессе разрешения вы передумали разрешать
конфликт, достаточно набрать:
git reset --hard HEAD — это вернет обе ветки в исходные состояния.
Если же коммит слияния был совершен, используем команду:
git reset --hard ORIG_HEAD
2.2.4 git rebase — построение ровной линии коммитов
Предположим, разработчик завел дополнительную ветку для разработки отдельной
возможности и совершил в ней несколько коммитов. Одновременно по какой-либо
причине в основной ветке также были совершены коммиты: например, в нее были
залиты изменения с удаленного сервера; либо сам разработчик совершал в ней
коммиты.
В принципе, можно обойтись обычным git merge. Но тогда усложняется сама линия
разработки, что бывает нежелательно в слишком больших проектах, где участвует
множество разработчиков.
Предположим, имеется две ветки, master и топик, в каждой из которых было совершенно несколько коммитов начиная с момента ветвления.
Команда git rebase берет коммиты из ветки topic и накладывает их на последний коммит ветки
master:
-
git-rebase master topic — вариант, в котором явно указывается, что и куда
прикладывается. -
git-rebase master — на master накладывается активная в настоящий момент
ветка.
После использования команды история становится линейной. При возникновении
конфликтов при поочередном накладывании коммитов
работа команды будет останавливаться, а в проблемные местах файлов появятся
соответствующие метки. После редактирования — разрешения конфликтов — файлы
следует внести в индекс командой git add и продолжить наложение следующих
коммитов командой git rebase --continue. Альтернативными выходами будут команды
git rebase --skip (пропустить наложение коммита и перейти к следующему) или git
rebase --abort (отмена работы команды и всех внесенных изменений).
С ключом -i (--interactive) команда будет работать в интерактивном
режиме. Пользователю будет предоставлена возможность определить порядок внесения
изменений, автоматически будет вызывать редактор для разрешения конфликтов и так
далее.
2.2.5 git cherry-pick — применение к дереву проекта изменений, внесенных отдельным коммитом
Если ведется сложная история разработки, с несколькими длинными ветками
разработками, может возникнуть необходимость в применении изменений, внесенных
отдельным коммитом одной ветки, к дереву другой (активной в настоящий момент).
git cherry-pick BUG_FIX_TAG — изменения, внесенные указанным коммитом будут
применены к дереву, автоматически проиндексированы и станут коммитом в активной
ветке.
git cherry-pick BUG_FIX_TAG -n — ключ "-n" показывает, что изменения надо
просто применить к дереву проекта без индексации и создания коммита.
2.3 Прочие команды и необходимые возможности
Для удобства работы с git было введено дополнительное понятие: тэг. Кроме того
дальше будет пояснена необходимость в хэшах, и его применение; показан способ
обращаться к коммитам при помощи относительной адресации.
2.3.1 Хэш — уникальная идентификация объектов
В git для идентификации любых объектов используется уникальный (то есть с
огромной вероятностью уникальный) хэш из 40 символов, который определяется
хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты,
файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла,
то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки
в сорок символов.
Больше всего нас интересует тот факт, что хэши идентифицируют коммиты. В этом
смысле хэш — продвинутый аналог ревизий Subversion. Несколько примеров
использования хэшей в качестве способа адресации:
git diff f292ef5d2b2f6312bc45ae49c2dc14588eef8da2 — найти разницу текущего
состояния проекта и коммита за номером… Ну сами видите, каким.
git diff f292ef5 — то же самое, но оставляем только шесть первых символов. Git
поймет, о каком коммите идет речь, если не существует другого коммита с таким
началом хэша.
git diff f292 — иногда хватает и четырех символов.
git log febc32...f292 — читаем лог с коммита по коммит.
Разумеется, человеку пользоваться хэшами не так удобно, как машине, именно поэтому были
введены другие объекты — тэги.
2.3.2 git tag — тэги как способ пометить уникальный коммит
Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит, имя
автора, собственное имя и некоторый комментарий. Кроме того, разработчик может
оставлять на таких тегах собственную цифровую подпись.
Кроме этого в git представленные так называемые «легковесные тэги» («lightweight
tags»), состоящие только из имени и ссылки на коммит. Такие тэги, как правило,
используются для упрощения навигации по дереву истории; создать их очень легко:
git tag stable-1 — создать «легковесный» тэг, связанный с последним
коммитом. Если тэг уже есть, то еще один создан не будет.
git tag stable-2 f292ef5 — пометить определенный коммит.
git tag -d stable-2 — удалить тег.
git tag -l — перечислить тэги.
git tag -f stable-1.1 — создать тэг для последнего коммита, заменить
существующий, если таковой уже был.
После создания тэга его имя можно использовать вместо хэша в любых командах
вроде git diff, git log и так далее:
git diff stable-1.1...stable-1
Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо
информации, вроде номера версии и комментария к нему. Иными словами, если в
комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по
имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию»:
git tag -a stable — создать обычный тэг для последнего коммита; будет вызван
текстовый редактор для составления комментария.
git tag -a stable -m «production version» — создать обычный тэг, сразу указав в
качестве аргумента комментарий.
Команды перечисления, удаления, перезаписи для обычных тэгов не отличаются от
команд для «легковесных» тэгов.
2.3.3 Относительная адресация
Вместо ревизий и тэгов в качестве имени коммита можно опираться на еще один
механизм — относительную адресацию. Например, можно обратиться прямо к предку
последнего коммита ветки master:
git diff master^
Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам
коммитов слияния:
git diff HEAD^2 — найти изменения по сравнению со вторым предком последнего
коммита в master. HEAD здесь — указатель на последний коммит активной ветки.
Аналогично, тильдой можно просто указывать, насколько глубоко в историю ветки
нужно погрузиться:
git diff master^^ — что привнес «дедушка» нынешнего коммита.
git diff master~2 — то же самое.
Обозначения можно объединять, чтобы добраться до нужного коммита:
git diff master~3^~2
git diff master~6